📄 avi.c
字号:
es_format_Init( &fmt, VIDEO_ES, tk->i_codec ); if( p_vids->p_bih->biBitCount == 24 ) { /* This is in BGR format */ fmt.video.i_bmask = 0x00ff0000; fmt.video.i_gmask = 0x0000ff00; fmt.video.i_rmask = 0x000000ff; } } else { es_format_Init( &fmt, VIDEO_ES, p_vids->p_bih->biCompression ); if( tk->i_codec == FOURCC_mp4v && !strncasecmp( (char*)&p_strh->i_handler, "XVID", 4 ) ) { fmt.i_codec = VLC_FOURCC( 'X', 'V', 'I', 'D' ); } } tk->i_samplesize = 0; fmt.video.i_width = p_vids->p_bih->biWidth; fmt.video.i_height = p_vids->p_bih->biHeight; fmt.video.i_bits_per_pixel = p_vids->p_bih->biBitCount; fmt.video.i_frame_rate = tk->i_rate; fmt.video.i_frame_rate_base = tk->i_scale; fmt.i_extra = __MIN( p_vids->p_bih->biSize - sizeof( BITMAPINFOHEADER ), p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER) ); fmt.p_extra = &p_vids->p_bih[1]; msg_Dbg( p_demux, "stream[%d] video(%4.4s) %dx%d %dbpp %ffps", i, (char*)&p_vids->p_bih->biCompression, p_vids->p_bih->biWidth, p_vids->p_bih->biHeight, p_vids->p_bih->biBitCount, (float)tk->i_rate/(float)tk->i_scale ); if( p_vids->p_bih->biCompression == 0x00 ) { /* RGB DIB are coded from bottom to top */ fmt.video.i_height = (unsigned int)(-(int)p_vids->p_bih->biHeight); } /* Extract palette from extradata if bpp <= 8 * (assumes that extradata contains only palette but appears * to be true for all palettized codecs we support) */ if( fmt.i_extra && fmt.video.i_bits_per_pixel <= 8 && fmt.video.i_bits_per_pixel > 0 ) { int i; fmt.video.p_palette = calloc( sizeof(video_palette_t), 1 ); fmt.video.p_palette->i_entries = 1; /* Apparently this is necessary. But why ? */ fmt.i_extra = p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER); for( i = 0; i < __MIN(fmt.i_extra/4, 256); i++ ) { ((uint32_t *)&fmt.video.p_palette->palette[0][0])[i] = GetDWLE((uint32_t*)fmt.p_extra + i); } } break; case( AVIFOURCC_txts): tk->i_cat = SPU_ES; tk->i_codec = VLC_FOURCC( 's', 'u', 'b', 't' ); msg_Dbg( p_demux, "stream[%d] subtitles", i ); es_format_Init( &fmt, SPU_ES, tk->i_codec ); break; case( AVIFOURCC_mids): msg_Dbg( p_demux, "stream[%d] midi is UNSUPPORTED", i ); default: msg_Warn( p_demux, "stream[%d] unknown type", i ); free( tk ); continue; } if( p_strn ) { fmt.psz_description = strdup( p_strn->p_str ); } tk->p_es = es_out_Add( p_demux->out, &fmt ); TAB_APPEND( p_sys->i_track, p_sys->track, tk ); } if( p_sys->i_track <= 0 ) { msg_Err( p_demux, "no valid track" ); goto error; } if( config_GetInt( p_demux, "avi-index" ) ) { if( p_sys->b_seekable ) { AVI_IndexCreate( p_demux ); } else { msg_Warn( p_demux, "cannot create index (unseekable stream)" ); AVI_IndexLoad( p_demux ); } } else { AVI_IndexLoad( p_demux ); } /* *** movie length in sec *** */ p_sys->i_length = AVI_MovieGetLength( p_demux ); if( p_sys->i_length < (mtime_t)p_avih->i_totalframes * (mtime_t)p_avih->i_microsecperframe / (mtime_t)1000000 ) { msg_Warn( p_demux, "broken or missing index, 'seek' will be axproximative or will have strange behavour" ); } /* fix some BeOS MediaKit generated file */ for( i = 0 ; i < p_sys->i_track; i++ ) { avi_track_t *tk = p_sys->track[i]; avi_chunk_list_t *p_strl; avi_chunk_strh_t *p_strh; avi_chunk_strf_auds_t *p_auds; if( tk->i_cat != AUDIO_ES ) { continue; } if( tk->i_idxnb < 1 || tk->i_scale != 1 || tk->i_samplesize != 0 ) { continue; } p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i ); p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 ); p_auds = AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 ); if( p_auds->p_wf->wFormatTag != WAVE_FORMAT_PCM && (unsigned int)tk->i_rate == p_auds->p_wf->nSamplesPerSec ) { int64_t i_track_length = tk->p_index[tk->i_idxnb-1].i_length + tk->p_index[tk->i_idxnb-1].i_lengthtotal; mtime_t i_length = (mtime_t)p_avih->i_totalframes * (mtime_t)p_avih->i_microsecperframe; if( i_length == 0 ) { msg_Warn( p_demux, "track[%d] cannot be fixed (BeOS MediaKit generated)", i ); continue; } tk->i_samplesize = 1; tk->i_rate = i_track_length * (int64_t)1000000/ i_length; msg_Warn( p_demux, "track[%d] fixed with rate=%d scale=%d (BeOS MediaKit generated)", i, tk->i_rate, tk->i_scale ); } } if( p_sys->b_seekable ) { /* we have read all chunk so go back to movi */ stream_Seek( p_demux->s, p_movi->i_chunk_pos ); } /* Skip movi header */ stream_Read( p_demux->s, NULL, 12 ); p_sys->i_movi_begin = p_movi->i_chunk_pos; return VLC_SUCCESS;error: if( p_sys->meta ) { vlc_meta_Delete( p_sys->meta ); } AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root ); free( p_sys ); return VLC_EGENERIC;}/***************************************************************************** * Close: frees unused data *****************************************************************************/static void Close ( vlc_object_t * p_this ){ demux_t * p_demux = (demux_t *)p_this; unsigned int i; demux_sys_t *p_sys = p_demux->p_sys ; for( i = 0; i < p_sys->i_track; i++ ) { if( p_sys->track[i] ) { FREE( p_sys->track[i]->p_index ); free( p_sys->track[i] ); } } FREE( p_sys->track ); AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root ); vlc_meta_Delete( p_sys->meta ); free( p_sys );}/***************************************************************************** * Demux_Seekable: reads and demuxes data packets for stream seekable ***************************************************************************** * AVIDemux: reads and demuxes data packets ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/typedef struct{ vlc_bool_t b_ok; int i_toread; off_t i_posf; /* where we will read : if i_idxposb == 0 : begining of chunk (+8 to acces data) else : point on data directly */} avi_track_toread_t;static int Demux_Seekable( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; unsigned int i_track_count = 0; unsigned int i_track; vlc_bool_t b_stream; /* cannot be more than 100 stream (dcXX or wbXX) */ avi_track_toread_t toread[100]; /* detect new selected/unselected streams */ for( i_track = 0; i_track < p_sys->i_track; i_track++ ) { avi_track_t *tk = p_sys->track[i_track]; vlc_bool_t b; es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b ); if( b && !tk->b_activated ) { if( p_sys->b_seekable) { AVI_TrackSeek( p_demux, i_track, p_sys->i_time ); } tk->b_activated = VLC_TRUE; } else if( !b && tk->b_activated ) { tk->b_activated = VLC_FALSE; } if( b ) { i_track_count++; } } if( i_track_count <= 0 ) { int64_t i_length = p_sys->i_length * (mtime_t)1000000; p_sys->i_time += 25*1000; /* read 25ms */ if( i_length > 0 ) { if( p_sys->i_time >= i_length ) return 0; return 1; } msg_Warn( p_demux, "no track selected, exiting..." ); return 0; } /* wait for the good time */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time + 1 ); p_sys->i_time += 25*1000; /* read 25ms */ /* init toread */ for( i_track = 0; i_track < p_sys->i_track; i_track++ ) { avi_track_t *tk = p_sys->track[i_track]; mtime_t i_dpts; toread[i_track].b_ok = tk->b_activated; if( tk->i_idxposc < tk->i_idxnb ) { toread[i_track].i_posf = tk->p_index[tk->i_idxposc].i_pos; if( tk->i_idxposb > 0 ) { toread[i_track].i_posf += 8 + tk->i_idxposb; } } else { toread[i_track].i_posf = -1; } i_dpts = p_sys->i_time - AVI_GetPTS( tk ); if( tk->i_samplesize ) { toread[i_track].i_toread = AVI_PTSToByte( tk, __ABS( i_dpts ) ); } else { toread[i_track].i_toread = AVI_PTSToChunk( tk, __ABS( i_dpts ) ); } if( i_dpts < 0 ) { toread[i_track].i_toread *= -1; } } b_stream = VLC_FALSE; for( ;; ) { avi_track_t *tk; vlc_bool_t b_done; block_t *p_frame; off_t i_pos; unsigned int i; size_t i_size; /* search for first chunk to be read */ for( i = 0, b_done = VLC_TRUE, i_pos = -1; i < p_sys->i_track; i++ ) { if( !toread[i].b_ok || AVI_GetDPTS( p_sys->track[i], toread[i].i_toread ) <= -25 * 1000 ) { continue; } if( toread[i].i_toread > 0 ) { b_done = VLC_FALSE; /* not yet finished */ } if( toread[i].i_posf > 0 ) { if( i_pos == -1 || i_pos > toread[i_track].i_posf ) { i_track = i; i_pos = toread[i].i_posf; } } } if( b_done ) { return( 1 ); } if( i_pos == -1 ) { int i_loop_count = 0; /* no valid index, we will parse directly the stream * in case we fail we will disable all finished stream */ if( p_sys->i_movi_lastchunk_pos >= p_sys->i_movi_begin + 12 ) { stream_Seek( p_demux->s, p_sys->i_movi_lastchunk_pos ); if( AVI_PacketNext( p_demux ) ) { return( AVI_TrackStopFinishedStreams( p_demux ) ? 0 : 1 ); } } else { stream_Seek( p_demux->s, p_sys->i_movi_begin + 12 ); } for( ;; ) { avi_packet_t avi_pk; if( AVI_PacketGetHeader( p_demux, &avi_pk ) ) { msg_Warn( p_demux, "cannot get packet header, track disabled" ); return( AVI_TrackStopFinishedStreams( p_demux ) ? 0 : 1 ); } if( avi_pk.i_stream >= p_sys->i_track || ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) ) { if( AVI_PacketNext( p_demux ) ) { msg_Warn( p_demux, "cannot skip packet, track disabled" ); return( AVI_TrackStopFinishedStreams( p_demux ) ? 0 : 1 ); } /* Prevents from eating all the CPU with broken files. * This value should be low enough so that it doesn't * affect the reading speed too much. */ if( !(++i_loop_count % 1024) ) { if( p_demux->b_die ) return -1; msleep( 10000 ); if( !(i_loop_count % (1024 * 10)) ) msg_Warn( p_demux, "don't seem to find any data..." ); } continue; } else { /* add this chunk to the index */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -