X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Favi%2Favi.c;h=723aa0efdab38de562cf8f01d41d77a0f426cea4;hb=37a2578ce4265f4ed495290923e3fa674c662656;hp=8a61fe2993ac745aec9d93d37569e54ea37e0c3b;hpb=a9288be1e747a49faba96c644fed1abd5d3f50a9;p=vlc diff --git a/modules/demux/avi/avi.c b/modules/demux/avi/avi.c index 8a61fe2993..723aa0efda 100644 --- a/modules/demux/avi/avi.c +++ b/modules/demux/avi/avi.c @@ -1,7 +1,7 @@ /***************************************************************************** * avi.c : AVI file Stream input module for vlc ***************************************************************************** - * Copyright (C) 2001-2004 VideoLAN + * Copyright (C) 2001-2004 the VideoLAN team * $Id$ * Authors: Laurent Aimar * @@ -17,19 +17,26 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ -#include /* malloc(), free() */ -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include -#include "vlc_meta.h" -#include "codecs.h" +#include +#include +#include #include "libavi.h" @@ -38,23 +45,33 @@ *****************************************************************************/ #define INTERLEAVE_TEXT N_("Force interleaved method" ) -#define INTERLEAVE_LONGTEXT N_( "Force interleaved method" ) +#define INTERLEAVE_LONGTEXT N_( "Force interleaved method." ) #define INDEX_TEXT N_("Force index creation") #define INDEX_LONGTEXT N_( \ - "Recreate a index for the AVI file so we can seek trough it more reliably." ) + "Recreate a index for the AVI file. Use this if your AVI file is damaged "\ + "or incomplete (not seekable)." ) static int Open ( vlc_object_t * ); static void Close( vlc_object_t * ); +static const int pi_index[] = {0,1,2}; + +static const char *const ppsz_indexes[] = { N_("Ask"), N_("Always fix"), + N_("Never fix") }; + vlc_module_begin(); - set_description( _("AVI demuxer") ); - set_capability( "demux2", 212 ); + set_shortname( "AVI" ); + set_description( N_("AVI demuxer") ); + set_capability( "demux", 212 ); + set_category( CAT_INPUT ); + set_subcategory( SUBCAT_INPUT_DEMUX ); add_bool( "avi-interleaved", 0, NULL, - INTERLEAVE_TEXT, INTERLEAVE_LONGTEXT, VLC_TRUE ); - add_bool( "avi-index", 0, NULL, - INDEX_TEXT, INDEX_LONGTEXT, VLC_TRUE ); + INTERLEAVE_TEXT, INTERLEAVE_LONGTEXT, true ); + add_integer( "avi-index", 0, NULL, + INDEX_TEXT, INDEX_LONGTEXT, false ); + change_integer_list( pi_index, ppsz_indexes, 0 ); set_callbacks( Open, Close ); vlc_module_end(); @@ -67,7 +84,6 @@ static int Seek ( demux_t *, mtime_t, int ); static int Demux_Seekable ( demux_t * ); static int Demux_UnSeekable( demux_t * ); -#define FREE( p ) if( p ) { free( p ); (p) = NULL; } #define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) ) typedef struct @@ -96,7 +112,7 @@ typedef struct typedef struct { - vlc_bool_t b_activated; + bool b_activated; unsigned int i_cat; /* AUDIO_ES, VIDEO_ES */ vlc_fourcc_t i_codec; @@ -107,16 +123,23 @@ typedef struct es_out_id_t *p_es; + /* Avi Index */ avi_entry_t *p_index; - unsigned int i_idxnb; - unsigned int i_idxmax; + unsigned int i_idxnb; + unsigned int i_idxmax; - unsigned int i_idxposc; /* numero of chunk */ - unsigned int i_idxposb; /* byte in the current chunk */ + unsigned int i_idxposc; /* numero of chunk */ + unsigned int i_idxposb; /* byte in the current chunk */ + + /* extra information given to the decoder */ + void *p_extra; /* For VBR audio only */ - unsigned int i_blockno; - unsigned int i_blocksize; + unsigned int i_blockno; + unsigned int i_blocksize; + + /* For muxed streams */ + stream_t *p_out_muxed; } avi_track_t; struct demux_sys_t @@ -124,10 +147,11 @@ struct demux_sys_t mtime_t i_time; mtime_t i_length; - vlc_bool_t b_seekable; + bool b_seekable; + bool b_muxed; avi_chunk_t ck_root; - vlc_bool_t b_odml; + bool b_odml; off_t i_movi_begin; off_t i_movi_lastchunk_pos; /* XXX position of last valid chunk */ @@ -138,6 +162,10 @@ struct demux_sys_t /* meta */ vlc_meta_t *meta; + + /* Progress box */ + mtime_t last_update; + int i_dialog_id; }; static inline off_t __EVEN( off_t i ) @@ -194,26 +222,32 @@ static int Open( vlc_object_t * p_this ) demux_t *p_demux = (demux_t *)p_this; demux_sys_t *p_sys; + bool b_index = false; + int i_do_index; + avi_chunk_t ck_riff; avi_chunk_list_t *p_riff = (avi_chunk_list_t*)&ck_riff; avi_chunk_list_t *p_hdrl, *p_movi; avi_chunk_avih_t *p_avih; unsigned int i_track; - unsigned int i; - - uint8_t *p_peek; + unsigned int i, i_peeker; + const uint8_t *p_peek; /* Is it an avi file ? */ - if( stream_Peek( p_demux->s, &p_peek, 12 ) < 12 ) + if( stream_Peek( p_demux->s, &p_peek, 200 ) < 200 ) return VLC_EGENERIC; + + for( i_peeker = 0; i_peeker < 188; i_peeker++ ) { - msg_Err( p_demux, "cannot peek()" ); - return VLC_EGENERIC; + if( !strncmp( (char *)&p_peek[0], "RIFF", 4 ) && !strncmp( (char *)&p_peek[8], "AVI ", 4 ) ) + break; + if( !strncmp( (char *)&p_peek[0], "ON2 ", 4 ) && !strncmp( (char *)&p_peek[8], "ON2f", 4 ) ) + break; + p_peek++; } - if( strncmp( &p_peek[0], "RIFF", 4 ) || strncmp( &p_peek[8], "AVI ", 4 ) ) + if( i_peeker == 188 ) { - msg_Warn( p_demux, "avi module discarded (invalid header)" ); return VLC_EGENERIC; } @@ -223,7 +257,8 @@ static int Open( vlc_object_t * p_this ) p_sys->i_time = 0; p_sys->i_length = 0; p_sys->i_movi_lastchunk_pos = 0; - p_sys->b_odml = VLC_FALSE; + p_sys->b_odml = false; + p_sys->b_muxed = false; p_sys->i_track = 0; p_sys->track = NULL; p_sys->meta = NULL; @@ -232,12 +267,18 @@ static int Open( vlc_object_t * p_this ) p_demux->pf_control = Control; p_demux->pf_demux = Demux_Seekable; + /* For unseekable stream, automaticaly use Demux_UnSeekable */ if( !p_sys->b_seekable || config_GetInt( p_demux, "avi-interleaved" ) ) { p_demux->pf_demux = Demux_UnSeekable; } + if( i_peeker > 0 ) + { + stream_Read( p_demux->s, NULL, i_peeker ); + } + if( AVI_ChunkReadRoot( p_demux->s, &p_sys->ck_root ) ) { msg_Err( p_demux, "avi module discarded (invalid file)" ); @@ -258,7 +299,7 @@ static int Open( vlc_object_t * p_this ) if( p_sysx->i_type == AVIFOURCC_AVIX ) { msg_Warn( p_demux, "detected OpenDML file" ); - p_sys->b_odml = VLC_TRUE; + p_sys->b_odml = true; break; } } @@ -292,7 +333,7 @@ static int Open( vlc_object_t * p_this ) goto error; } - /* print informations on streams */ + /* print information on streams */ msg_Dbg( p_demux, "AVIH: %d stream, flags %s%s%s%s ", i_track, p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"", @@ -307,28 +348,24 @@ static int Open( vlc_object_t * p_this ) p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"", p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"", p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" ); - vlc_meta_Add( p_sys->meta, VLC_META_SETTING, buffer ); + vlc_meta_SetSetting( p_sys->meta, buffer ); } /* now read info on each stream and create ES */ for( i = 0 ; i < i_track; i++ ) { - avi_track_t *tk = malloc( sizeof( avi_track_t ) ); - avi_chunk_list_t *p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i ); - avi_chunk_strh_t *p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 ); - avi_chunk_strf_auds_t *p_auds; - avi_chunk_strf_vids_t *p_vids; - es_format_t fmt; + avi_track_t *tk = malloc( sizeof( avi_track_t ) ); + if( !tk ) + goto error; - tk->b_activated = VLC_FALSE; - tk->p_index = 0; - tk->i_idxnb = 0; - tk->i_idxmax = 0; - tk->i_idxposc = 0; - tk->i_idxposb = 0; + avi_chunk_list_t *p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i ); + avi_chunk_strh_t *p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 ); + avi_chunk_STRING_t *p_strn = AVI_ChunkFind( p_strl, AVIFOURCC_strn, 0 ); + avi_chunk_strf_auds_t *p_auds = NULL; + avi_chunk_strf_vids_t *p_vids = NULL; + es_format_t fmt; - tk->i_blockno = 0; - tk->i_blocksize = 0; + memset( tk, 0, sizeof( avi_track_t ) ); p_vids = (avi_chunk_strf_vids_t*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 ); p_auds = (avi_chunk_strf_auds_t*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 ); @@ -351,7 +388,9 @@ static int Open( vlc_object_t * p_this ) tk->i_cat = AUDIO_ES; tk->i_codec = AVI_FourccGetCodec( AUDIO_ES, p_auds->p_wf->wFormatTag ); - if( ( tk->i_blocksize = p_auds->p_wf->nBlockAlign ) == 0 ) + if( tk->i_codec == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ) + tk->i_blocksize = 0; /* fix vorbis VBR decoding */ + else if( ( tk->i_blocksize = p_auds->p_wf->nBlockAlign ) == 0 ) { if( p_auds->p_wf->wFormatTag == 1 ) { @@ -369,12 +408,86 @@ static int Open( vlc_object_t * p_this ) fmt.i_bitrate = p_auds->p_wf->nAvgBytesPerSec*8; fmt.audio.i_blockalign = p_auds->p_wf->nBlockAlign; fmt.audio.i_bitspersample = p_auds->p_wf->wBitsPerSample; + fmt.b_packetized = !tk->i_blocksize; + + msg_Dbg( p_demux, + "stream[%d] audio(0x%x) %d channels %dHz %dbits", + i, p_auds->p_wf->wFormatTag, p_auds->p_wf->nChannels, + p_auds->p_wf->nSamplesPerSec, + p_auds->p_wf->wBitsPerSample ); + fmt.i_extra = __MIN( p_auds->p_wf->cbSize, p_auds->i_chunk_size - sizeof(WAVEFORMATEX) ); - fmt.p_extra = &p_auds->p_wf[1]; - msg_Dbg( p_demux, "stream[%d] audio(0x%x) %d channels %dHz %dbits", - i, p_auds->p_wf->wFormatTag, p_auds->p_wf->nChannels, - p_auds->p_wf->nSamplesPerSec, p_auds->p_wf->wBitsPerSample); + fmt.p_extra = tk->p_extra = malloc( fmt.i_extra ); + if( !fmt.p_extra ) goto error; + memcpy( fmt.p_extra, &p_auds->p_wf[1], fmt.i_extra ); + + /* Rewrite the vorbis headers from Xiph-like format + * to VLC internal format + * + * Xiph format: + * - 1st byte == N, is the number of packets - 1 + * - Following bytes are the size of the N first packets: + * while( *p == 0xFF ) { size += 0xFF; p++ } size += *p; + * (the size of the last packet is the size of remaining + * data in the buffer) + * - Finally, all the packets concatenated + * + * VLC format: + * - Size of the packet on 16 bits (big endian) FIXME: should be 32 bits to be safe + * - The packet itself + * - Size of the next packet, and so on ... + */ + + if( tk->i_codec == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ) + { + uint8_t *p_extra = fmt.p_extra; + size_t i_extra = fmt.i_extra; + + if( i_extra <= 1 ) break; + if( *p_extra++ != 2 ) break; /* 3 packets - 1 = 2 */ + i_extra--; + + size_t i_identifier_len = 0; + while( *p_extra == 0xFF ) + { + i_identifier_len += 0xFF; + p_extra++; + if( --i_extra <= 1 ) break; + } + i_identifier_len += *p_extra++; + if( i_identifier_len > --i_extra ) break; + + size_t i_comment_len = 0; + while( *p_extra == 0xFF ) + { + i_comment_len += 0xFF; + p_extra++; + if( --i_extra <= 1 ) break; + } + i_comment_len += *p_extra++; + if( i_comment_len > --i_extra ) break; + size_t i_cookbook_len = i_extra; + + size_t i_headers_size = 3 * 2 + i_identifier_len + + i_comment_len + i_cookbook_len; + uint8_t *p_out = malloc( i_headers_size ); + if( !p_out ) goto error; + free( fmt.p_extra ); + fmt.p_extra = tk->p_extra = p_out; + fmt.i_extra = i_headers_size; + #define copy_packet( len ) \ + *p_out++ = len >> 8; \ + *p_out++ = len & 0xFF; \ + memcpy( p_out, p_extra, len ); \ + p_out += len; \ + p_extra += len; + copy_packet( i_identifier_len ); + copy_packet( i_comment_len ); + copy_packet( i_cookbook_len ); + #undef copy_packet + break; + } break; case( AVIFOURCC_vids ): @@ -400,35 +513,116 @@ static int Open( vlc_object_t * p_this ) case 9: tk->i_codec = VLC_FOURCC( 'Y', 'V', 'U', '9' ); /* <- TODO check that */ break; + case 8: + tk->i_codec = VLC_FOURCC('Y','8','0','0'); + break; } 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, + msg_Dbg( p_demux, "stream[%d] video(%4.4s) %"PRIu32"x%"PRIu32" %dbpp %ffps", + i, (char*)&p_vids->p_bih->biCompression, + (uint32_t)p_vids->p_bih->biWidth, + (uint32_t)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_iavs): + case( AVIFOURCC_ivas): + p_sys->b_muxed = true; + msg_Dbg( p_demux, "stream[%d] iavs with handler %4.4s", i, (char *)&p_strh->i_handler ); + if( p_strh->i_handler == FOURCC_dvsd || + p_strh->i_handler == FOURCC_dvhd || + p_strh->i_handler == FOURCC_dvsl || + p_strh->i_handler == FOURCC_dv25 || + p_strh->i_handler == FOURCC_dv50 ) + { + tk->p_out_muxed = stream_DemuxNew( p_demux, (char *)"rawdv", p_demux->out ); + if( !tk->p_out_muxed ) + msg_Err( p_demux, "could not load the DV parser" ); + else break; + } + free( tk ); + continue; + + case( AVIFOURCC_mids): + msg_Dbg( p_demux, "stream[%d] midi is UNSUPPORTED", i ); + default: - msg_Warn( p_demux, "stream[%d] unknown type", i ); + msg_Warn( p_demux, "stream[%d] unknown type %4.4s", i, (char *)&p_strh->i_type ); free( tk ); continue; } - tk->p_es = es_out_Add( p_demux->out, &fmt ); + if( p_strn ) + { + /* The charset of p_strn is undefined */ + EnsureUTF8( p_strn->p_str ); + fmt.psz_description = strdup( p_strn->p_str ); + } + if( tk->p_out_muxed == NULL ) + tk->p_es = es_out_Add( p_demux->out, &fmt ); TAB_APPEND( p_sys->i_track, p_sys->track, tk ); } @@ -438,8 +632,10 @@ static int Open( vlc_object_t * p_this ) goto error; } - if( config_GetInt( p_demux, "avi-index" ) ) + i_do_index = config_GetInt( p_demux, "avi-index" ); + if( i_do_index == 1 ) /* Always fix */ { +aviindex: if( p_sys->b_seekable ) { AVI_IndexCreate( p_demux ); @@ -461,8 +657,35 @@ static int Open( vlc_object_t * p_this ) (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" ); + msg_Warn( p_demux, "broken or missing index, 'seek' will be " + "approximative or will exhibit strange behavior" ); + if( i_do_index == 0 && !b_index ) + { + if( !p_sys->b_seekable ) { + b_index = true; + goto aviindex; + } + int i_create; + i_create = intf_UserYesNo( p_demux, _("AVI Index") , + _( "This AVI file is broken. Seeking will not " + "work correctly.\nDo you want to " + "try to repair it?\n\nThis might take a long time." ), + _( "Repair" ), _( "Don't repair" ), _( "Cancel") ); + if( i_create == DIALOG_OK_YES ) + { + b_index = true; + msg_Dbg( p_demux, "Fixing AVI index" ); + goto aviindex; + } + else if( i_create == DIALOG_CANCELLED ) + { + /* Kill input */ + vlc_object_kill( p_demux->p_parent ); + goto error; + } + } } + /* fix some BeOS MediaKit generated file */ for( i = 0 ; i < p_sys->i_track; i++ ) { @@ -539,11 +762,14 @@ static void Close ( vlc_object_t * p_this ) { if( p_sys->track[i] ) { - FREE( p_sys->track[i]->p_index ); + if( p_sys->track[i]->p_out_muxed ) + stream_DemuxDelete( p_sys->track[i]->p_out_muxed ); + free( p_sys->track[i]->p_index ); + free( p_sys->track[i]->p_extra ); free( p_sys->track[i] ); } } - FREE( p_sys->track ); + free( p_sys->track ); AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root ); vlc_meta_Delete( p_sys->meta ); @@ -559,7 +785,7 @@ static void Close ( vlc_object_t * p_this ) *****************************************************************************/ typedef struct { - vlc_bool_t b_ok; + bool b_ok; int i_toread; @@ -574,7 +800,7 @@ static int Demux_Seekable( demux_t *p_demux ) unsigned int i_track_count = 0; unsigned int i_track; - vlc_bool_t b_stream; + bool b_stream; /* cannot be more than 100 stream (dcXX or wbXX) */ avi_track_toread_t toread[100]; @@ -583,7 +809,14 @@ static int Demux_Seekable( demux_t *p_demux ) 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; + bool b; + + if( p_sys->b_muxed && tk->p_out_muxed ) + { + i_track_count++; + tk->b_activated = true; + continue; + } es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b ); if( b && !tk->b_activated ) @@ -592,11 +825,11 @@ static int Demux_Seekable( demux_t *p_demux ) { AVI_TrackSeek( p_demux, i_track, p_sys->i_time ); } - tk->b_activated = VLC_TRUE; + tk->b_activated = true; } else if( !b && tk->b_activated ) { - tk->b_activated = VLC_FALSE; + tk->b_activated = false; } if( b ) { @@ -606,12 +839,21 @@ static int Demux_Seekable( demux_t *p_demux ) 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 ); + return 0; } /* wait for the good time */ - es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_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 */ @@ -651,19 +893,19 @@ static int Demux_Seekable( demux_t *p_demux ) } } - b_stream = VLC_FALSE; + b_stream = false; for( ;; ) { avi_track_t *tk; - vlc_bool_t b_done; + bool 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++ ) + for( i = 0, b_done = true, i_pos = -1; i < p_sys->i_track; i++ ) { if( !toread[i].b_ok || AVI_GetDPTS( p_sys->track[i], @@ -674,11 +916,11 @@ static int Demux_Seekable( demux_t *p_demux ) if( toread[i].i_toread > 0 ) { - b_done = VLC_FALSE; /* not yet finished */ + b_done = false; /* not yet finished */ } if( toread[i].i_posf > 0 ) { - if( i_pos == -1 || i_pos > toread[i_track].i_posf ) + if( i_pos == -1 || i_pos > toread[i].i_posf ) { i_track = i; i_pos = toread[i].i_posf; @@ -798,7 +1040,8 @@ static int Demux_Seekable( demux_t *p_demux ) } else { - i_toread = __MAX( AVI_PTSToByte( tk, 20 * 1000 ), 100 ); + i_toread = AVI_PTSToByte( tk, 20 * 1000 ); + i_toread = __MAX( i_toread, 100 ); } } i_size = __MIN( tk->p_index[tk->i_idxposc].i_length - @@ -817,9 +1060,9 @@ static int Demux_Seekable( demux_t *p_demux ) if( ( p_frame = stream_Block( p_demux->s, __EVEN( i_size ) ) )==NULL ) { - msg_Warn( p_demux, "failled reading data" ); - tk->b_activated = VLC_FALSE; - toread[i_track].b_ok = VLC_FALSE; + msg_Warn( p_demux, "failed reading data" ); + tk->b_activated = false; + toread[i_track].b_ok = false; continue; } if( i_size % 2 ) /* read was padded on word boundary */ @@ -832,7 +1075,7 @@ static int Demux_Seekable( demux_t *p_demux ) p_frame->p_buffer += 8; p_frame->i_buffer -= 8; } - p_frame->i_pts = AVI_GetPTS( tk ); + p_frame->i_pts = AVI_GetPTS( tk ) + 1; if( tk->p_index[tk->i_idxposc].i_flags&AVIIF_KEYFRAME ) { p_frame->i_flags = BLOCK_FLAG_TYPE_I; @@ -885,7 +1128,7 @@ static int Demux_Seekable( demux_t *p_demux ) toread[i_track].i_posf = -1; } - b_stream = VLC_TRUE; /* at least one read succeed */ + b_stream = true; /* at least one read succeed */ if( tk->i_cat != VIDEO_ES ) p_frame->i_dts = p_frame->i_pts; @@ -896,7 +1139,10 @@ static int Demux_Seekable( demux_t *p_demux ) } //p_pes->i_rate = p_demux->stream.control.i_rate; - es_out_Send( p_demux->out, tk->p_es, p_frame ); + if( tk->p_out_muxed ) + stream_DemuxSend( tk->p_out_muxed, p_frame ); + else + es_out_Send( p_demux->out, tk->p_es, p_frame ); } } @@ -913,14 +1159,20 @@ static int Demux_UnSeekable( demux_t *p_demux ) unsigned int i_stream; unsigned int i_packet; - es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time ); + if( p_sys->b_muxed ) + { + msg_Err( p_demux, "Can not yet process muxed avi substreams without seeking" ); + return VLC_EGENERIC; + } + + es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time + 1 ); /* *** find master stream for data packet skipping algo *** */ /* *** -> first video, if any, or first audio ES *** */ for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ ) { avi_track_t *tk = p_sys->track[i_stream]; - vlc_bool_t b; + bool b; es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b ); @@ -994,7 +1246,7 @@ static int Demux_UnSeekable( demux_t *p_demux ) { return( -1 ); } - p_frame->i_pts = AVI_GetPTS( p_stream ); + p_frame->i_pts = AVI_GetPTS( p_stream ) + 1; if( avi_pk.i_cat != VIDEO_ES ) p_frame->i_dts = p_frame->i_pts; @@ -1038,15 +1290,13 @@ static int Demux_UnSeekable( demux_t *p_demux ) /***************************************************************************** * Seek: goto to i_date or i_percent - ***************************************************************************** - * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/ static int Seek( demux_t *p_demux, mtime_t i_date, int i_percent ) { demux_sys_t *p_sys = p_demux->p_sys; unsigned int i_stream; - msg_Dbg( p_demux, "seek requested: "I64Fd" secondes %d%%", + msg_Dbg( p_demux, "seek requested: %"PRId64" seconds %d%%", i_date / 1000000, i_percent ); if( p_sys->b_seekable ) @@ -1057,12 +1307,12 @@ static int Seek( demux_t *p_demux, mtime_t i_date, int i_percent ) int64_t i_pos; /* use i_percent to create a true i_date */ - msg_Warn( p_demux, "mmh, seeking without index at %d%%" - " work only for interleaved file", i_percent ); + msg_Warn( p_demux, "seeking without index at %d%%" + " only works for interleaved files", i_percent ); if( i_percent >= 100 ) { msg_Warn( p_demux, "cannot seek so far !" ); - return( -1 ); + return VLC_EGENERIC; } i_percent = __MAX( i_percent, 0 ); @@ -1082,14 +1332,14 @@ static int Seek( demux_t *p_demux, mtime_t i_date, int i_percent ) if( !p_stream || !p_stream->b_activated ) { msg_Warn( p_demux, "cannot find any selected stream" ); - return( -1 ); + return VLC_EGENERIC; } /* be sure that the index exist */ if( AVI_StreamChunkSet( p_demux, i_stream, 0 ) ) { msg_Warn( p_demux, "cannot seek" ); - return( -1 ); + return VLC_EGENERIC; } while( i_pos >= p_stream->p_index[p_stream->i_idxposc].i_pos + @@ -1100,63 +1350,38 @@ static int Seek( demux_t *p_demux, mtime_t i_date, int i_percent ) i_stream, p_stream->i_idxposc + 1 ) ) { msg_Warn( p_demux, "cannot seek" ); - return( -1 ); + return VLC_EGENERIC; } } i_date = AVI_GetPTS( p_stream ); /* TODO better support for i_samplesize != 0 */ - msg_Dbg( p_demux, "estimate date "I64Fd, i_date ); + msg_Dbg( p_demux, "estimate date %"PRId64, i_date ); } -#define p_stream p_sys->track[i_stream] - p_sys->i_time = 0; - /* seek for chunk based streams */ + /* */ for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ ) { - if( p_stream->b_activated && !p_stream->i_samplesize ) -/* if( p_stream->b_activated ) */ - { - AVI_TrackSeek( p_demux, i_stream, i_date ); - p_sys->i_time = __MAX( AVI_GetPTS( p_stream ), - p_sys->i_time ); - } - } -#if 1 - if( p_sys->i_time ) - { - i_date = p_sys->i_time; - } - /* seek for bytes based streams */ - for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ ) - { - if( p_stream->b_activated && p_stream->i_samplesize ) - { - AVI_TrackSeek( p_demux, i_stream, i_date ); -/* p_sys->i_time = __MAX( AVI_GetPTS( p_stream ), p_sys->i_time );*/ - } - } - msg_Dbg( p_demux, "seek: "I64Fd" seconds", p_sys->i_time /1000000 ); - /* set true movie time */ -#endif - if( !p_sys->i_time ) - { - p_sys->i_time = i_date; + avi_track_t *p_stream = p_sys->track[i_stream]; + + if( !p_stream->b_activated ) + continue; + + AVI_TrackSeek( p_demux, i_stream, i_date ); } -#undef p_stream - return( 1 ); + p_sys->i_time = i_date; + msg_Dbg( p_demux, "seek: %"PRId64" seconds", p_sys->i_time /1000000 ); + return VLC_SUCCESS; } else { msg_Err( p_demux, "shouldn't yet be executed" ); - return( -1 ); + return VLC_EGENERIC; } } /***************************************************************************** * Control: - ***************************************************************************** - * *****************************************************************************/ static double ControlGetPosition( demux_t *p_demux ) { @@ -1186,18 +1411,18 @@ static double ControlGetPosition( demux_t *p_demux ) } } } - return (double)i64 / (double)stream_Size( p_demux->s ); + return (double)i64 / stream_Size( p_demux->s ); } return 0.0; } -static int Control( demux_t *p_demux, int i_query, va_list args ) +static int Control( demux_t *p_demux, int i_query, va_list args ) { demux_sys_t *p_sys = p_demux->p_sys; int i; double f, *pf; int64_t i64, *pi64; - vlc_meta_t **pp_meta; + vlc_meta_t *p_meta; switch( i_query ) { @@ -1210,7 +1435,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) if( p_sys->b_seekable ) { i64 = (mtime_t)(1000000.0 * p_sys->i_length * f ); - return Seek( p_demux, i64, (int)(f * 100) ) < 0 ? VLC_EGENERIC : VLC_SUCCESS; + return Seek( p_demux, i64, (int)(f * 100) ); } else { @@ -1258,8 +1483,8 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) } return VLC_SUCCESS; case DEMUX_GET_META: - pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** ); - *pp_meta = vlc_meta_Duplicate( p_sys->meta ); + p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* ); + vlc_meta_Merge( p_meta, p_sys->meta ); return VLC_SUCCESS; default: @@ -1273,6 +1498,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) static mtime_t AVI_PTSToChunk( avi_track_t *tk, mtime_t i_pts ) { + if( !tk->i_scale ) + return (mtime_t)0; + return (mtime_t)((int64_t)i_pts * (int64_t)tk->i_rate / (int64_t)tk->i_scale / @@ -1280,6 +1508,9 @@ static mtime_t AVI_PTSToChunk( avi_track_t *tk, mtime_t i_pts ) } static mtime_t AVI_PTSToByte( avi_track_t *tk, mtime_t i_pts ) { + if( !tk->i_scale || !tk->i_samplesize ) + return (mtime_t)0; + return (mtime_t)((int64_t)i_pts * (int64_t)tk->i_rate / (int64_t)tk->i_scale / @@ -1289,7 +1520,10 @@ static mtime_t AVI_PTSToByte( avi_track_t *tk, mtime_t i_pts ) static mtime_t AVI_GetDPTS( avi_track_t *tk, int64_t i_count ) { - mtime_t i_dpts; + mtime_t i_dpts = 0; + + if( !tk->i_rate ) + return i_dpts; i_dpts = (mtime_t)( (int64_t)1000000 * (int64_t)i_count * @@ -1414,7 +1648,6 @@ static int AVI_StreamChunkFind( demux_t *p_demux, unsigned int i_stream ) } } - /* be sure that i_ck will be a valid index entry */ static int AVI_StreamChunkSet( demux_t *p_demux, unsigned int i_stream, unsigned int i_ck ) @@ -1442,7 +1675,6 @@ static int AVI_StreamChunkSet( demux_t *p_demux, unsigned int i_stream, return VLC_SUCCESS; } - /* XXX FIXME up to now, we assume that all chunk are one after one */ static int AVI_StreamBytesSet( demux_t *p_demux, unsigned int i_stream, @@ -1546,7 +1778,7 @@ static int AVI_TrackSeek( demux_t *p_demux, } msg_Dbg( p_demux, - "old:"I64Fd" %s new "I64Fd, + "old:%"PRId64" %s new %"PRId64, i_oldpts, i_oldpts > i_date ? ">" : "<", i_date ); @@ -1554,7 +1786,7 @@ static int AVI_TrackSeek( demux_t *p_demux, if( p_stream->i_cat == VIDEO_ES ) { /* search key frame */ - if( i_date < i_oldpts ) + //if( i_date < i_oldpts || 1 ) { while( p_stream->i_idxposc > 0 && !( p_stream->p_index[p_stream->i_idxposc].i_flags & @@ -1567,7 +1799,10 @@ static int AVI_TrackSeek( demux_t *p_demux, return VLC_EGENERIC; } } + if( p_stream->p_es ) + es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, p_stream->p_es, i_date ); } +#if 0 else { while( p_stream->i_idxposc < p_stream->i_idxnb && @@ -1582,6 +1817,7 @@ static int AVI_TrackSeek( demux_t *p_demux, } } } +#endif } } else @@ -1598,7 +1834,7 @@ static int AVI_TrackSeek( demux_t *p_demux, } /**************************************************************************** - * Return VLC_TRUE if it's a key frame + * Return true if it's a key frame ****************************************************************************/ static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, uint8_t *p_byte ) { @@ -1624,7 +1860,7 @@ static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, uint8_t *p_byte ) */ return p_byte[0] & 0xC0 ? 0 : AVIIF_KEYFRAME; case FOURCC_mp4v: - /* we should find first occurence of 0x000001b6 (32bits) + /* we should find first occurrence of 0x000001b6 (32bits) * startcode: 0x000001b6 32bits * piture type 0(I),1(P) 2bits */ @@ -1711,7 +1947,7 @@ vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t i_codec ) * ****************************************************************************/ static void AVI_ParseStreamHeader( vlc_fourcc_t i_id, - int *pi_number, int *pi_type ) + unsigned int *pi_number, unsigned int *pi_type ) { #define SET_PTR( p, v ) if( p ) *(p) = (v); int c1, c2; @@ -1749,7 +1985,7 @@ static void AVI_ParseStreamHeader( vlc_fourcc_t i_id, ****************************************************************************/ static int AVI_PacketGetHeader( demux_t *p_demux, avi_packet_t *p_pk ) { - uint8_t *p_peek; + const uint8_t *p_peek; if( stream_Peek( p_demux->s, &p_peek, 16 ) < 16 ) { @@ -1805,6 +2041,7 @@ static int AVI_PacketNext( demux_t *p_demux ) } return VLC_SUCCESS; } + static int AVI_PacketRead( demux_t *p_demux, avi_packet_t *p_pk, block_t **pp_frame ) @@ -1924,6 +2161,8 @@ static int AVI_IndexLoad_idx1( demux_t *p_demux ) off_t i_offset; unsigned int i; + bool b_keyset[100]; + p_riff = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0); p_idx1 = AVI_ChunkFind( p_riff, AVIFOURCC_idx1, 0); p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0); @@ -1947,6 +2186,10 @@ static int AVI_IndexLoad_idx1( demux_t *p_demux ) } } + /* Reset b_keyset */ + for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ ) + b_keyset[i_stream] = false; + for( i_index = 0; i_index < p_idx1->i_entry_count; i_index++ ) { unsigned int i_cat; @@ -1964,6 +2207,21 @@ static int AVI_IndexLoad_idx1( demux_t *p_demux ) index.i_pos = p_idx1->entry[i_index].i_pos + i_offset; index.i_length = p_idx1->entry[i_index].i_length; AVI_IndexAddEntry( p_sys, i_stream, &index ); + + if( index.i_flags&AVIIF_KEYFRAME ) + b_keyset[i_stream] = true; + } + } + + for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ ) + { + if( !b_keyset[i_stream] ) + { + avi_track_t *tk = p_sys->track[i_stream]; + + msg_Dbg( p_demux, "no key frame set for track %d", i_stream ); + for( i_index = 0; i_index < tk->i_idxnb; i_index++ ) + tk->p_index[i_index].i_flags |= AVIIF_KEYFRAME; } } return VLC_SUCCESS; @@ -2004,7 +2262,7 @@ static void __Parse_indx( demux_t *p_demux, } else { - msg_Warn( p_demux, "unknow subtype index(0x%x)", p_indx->i_indexsubtype ); + msg_Warn( p_demux, "unknown subtype index(0x%x)", p_indx->i_indexsubtype ); } } @@ -2031,7 +2289,8 @@ static void AVI_IndexLoad_indx( demux_t *p_demux ) if( !p_indx ) { - msg_Warn( p_demux, "cannot find indx (misdetect/broken OpenDML file?)" ); + msg_Warn( p_demux, "cannot find indx (misdetect/broken OpenDML " + "file?)" ); continue; } @@ -2041,7 +2300,7 @@ static void AVI_IndexLoad_indx( demux_t *p_demux ) } else if( p_indx->i_indextype == AVI_INDEX_OF_INDEXES ) { - avi_chunk_indx_t ck_sub; + avi_chunk_t ck_sub; for( i = 0; i < p_indx->i_entriesinuse; i++ ) { if( stream_Seek( p_demux->s, p_indx->idx.super[i].i_offset )|| @@ -2049,12 +2308,12 @@ static void AVI_IndexLoad_indx( demux_t *p_demux ) { break; } - __Parse_indx( p_demux, i_stream, &ck_sub ); + __Parse_indx( p_demux, i_stream, &ck_sub.indx ); } } else { - msg_Warn( p_demux, "unknow type index(0x%x)", p_indx->i_indextype ); + msg_Warn( p_demux, "unknown type index(0x%x)", p_indx->i_indextype ); } #undef p_stream } @@ -2119,6 +2378,18 @@ static void AVI_IndexCreate( demux_t *p_demux ) stream_Seek( p_demux->s, p_movi->i_chunk_pos + 12 ); msg_Warn( p_demux, "creating index from LIST-movi, will take time !" ); + + + /* Only show dialog if AVI is > 10MB */ + p_demux->p_sys->i_dialog_id = -1; + if( stream_Size( p_demux->s ) > 10000000 ) + { + p_demux->p_sys->i_dialog_id = intf_IntfProgress( p_demux, + _( "Fixing AVI Index..." ), + 0.0 ); + p_demux->p_sys->last_update = mdate(); + } + for( ;; ) { avi_packet_t pk; @@ -2128,6 +2399,18 @@ static void AVI_IndexCreate( demux_t *p_demux ) return; } + /* Don't update dialog too often */ + if( p_demux->p_sys->i_dialog_id > 0 && + mdate() - p_demux->p_sys->last_update > 100000 ) + { + int64_t i_pos = stream_Tell( p_demux->s )* 100 / + stream_Size( p_demux->s ); + float f_pos = (float)i_pos; + p_demux->p_sys->last_update = mdate(); + intf_ProgressUpdate( p_demux, p_demux->p_sys->i_dialog_id, + _( "Fixing AVI Index..." ), f_pos, -1 ); + } + if( AVI_PacketGetHeader( p_demux, &pk ) ) { break; @@ -2185,6 +2468,11 @@ static void AVI_IndexCreate( demux_t *p_demux ) } print_stat: + if( p_demux->p_sys->i_dialog_id > 0 ) + { + intf_UserHide( p_demux, p_demux->p_sys->i_dialog_id ); + } + for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ ) { msg_Dbg( p_demux, @@ -2201,19 +2489,19 @@ static int AVI_TrackStopFinishedStreams( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; unsigned int i; - int b_end = VLC_TRUE; + int b_end = true; for( i = 0; i < p_sys->i_track; i++ ) { avi_track_t *tk = p_sys->track[i]; if( tk->i_idxposc >= tk->i_idxnb ) { - tk->b_activated = VLC_FALSE; - es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, tk->p_es, VLC_FALSE ); + tk->b_activated = false; + if( tk->p_es ) es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, tk->p_es, false ); } else { - b_end = VLC_FALSE; + b_end = false; } } return( b_end ); @@ -2252,7 +2540,7 @@ static mtime_t AVI_MovieGetLength( demux_t *p_demux ) i_length /= (mtime_t)1000000; /* in seconds */ msg_Dbg( p_demux, - "stream[%d] length:"I64Fd" (based on index)", + "stream[%d] length:%"PRId64" (based on index)", i, i_length ); i_maxlength = __MAX( i_maxlength, i_length ); @@ -2260,5 +2548,3 @@ static mtime_t AVI_MovieGetLength( demux_t *p_demux ) return i_maxlength; } - -