From 233ac074b794146188fe1167d7d142a11a6a6b1f Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Fri, 22 Aug 2003 20:31:47 +0000 Subject: [PATCH] * avi: use stream_*, some clean and reordering. --- modules/demux/avi/avi.c | 3408 +++++++++++++++++------------------- modules/demux/avi/avi.h | 4 +- modules/demux/avi/libavi.c | 432 ++--- modules/demux/avi/libavi.h | 308 ++-- 4 files changed, 1903 insertions(+), 2249 deletions(-) diff --git a/modules/demux/avi/avi.c b/modules/demux/avi/avi.c index 6bb52d68d8..2cfa68e7a7 100644 --- a/modules/demux/avi/avi.c +++ b/modules/demux/avi/avi.c @@ -2,7 +2,7 @@ * avi.c : AVI file Stream input module for vlc ***************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: avi.c,v 1.56 2003/08/20 01:10:54 fenrir Exp $ + * $Id: avi.c,v 1.57 2003/08/22 20:31:47 fenrir Exp $ * Authors: Laurent Aimar * * This program is free software; you can redistribute it and/or modify @@ -24,14 +24,11 @@ * Preamble *****************************************************************************/ #include /* malloc(), free() */ -#include /* strdup() */ -#include -#include #include #include - -#include "vlc_video.h" +#include "ninput.h" +#include "codecs.h" #include "libavi.h" @@ -42,20 +39,12 @@ #endif #include "avi.h" -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static int AVIInit ( vlc_object_t * ); -static void __AVIEnd ( vlc_object_t * ); -static int AVISeek ( input_thread_t *, mtime_t, int ); -static int AVIDemux_Seekable ( input_thread_t * ); -static int AVIDemux_UnSeekable( input_thread_t *p_input ); - -#define AVIEnd(a) __AVIEnd(VLC_OBJECT(a)) -#define FREE( p ) if( p ) { free( p ); (p) = NULL; } /***************************************************************************** * Module descriptor *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + vlc_module_begin(); add_category_hint( N_("avi-demuxer"), NULL, VLC_TRUE ); add_bool( "avi-interleaved", 0, NULL, @@ -67,1364 +56,1232 @@ vlc_module_begin(); set_description( N_("AVI demuxer") ); set_capability( "demux", 212 ); - set_callbacks( AVIInit, __AVIEnd ); + set_callbacks( Open, Close ); vlc_module_end(); -static vlc_fourcc_t GetFOURCC( byte_t *p_buff ) -{ - return VLC_FOURCC( p_buff[0], p_buff[1], p_buff[2], p_buff[3] ); -} +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Seek ( input_thread_t *, mtime_t, int ); +static int Demux_Seekable ( input_thread_t * ); +static int Demux_UnSeekable( input_thread_t *p_input ); + +#define FREE( p ) if( p ) { free( p ); (p) = NULL; } +#define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) ) static inline off_t __EVEN( off_t i ) { return (i & 1) ? i + 1 : i; } -#define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) ) - -/* read data in a pes */ -static int input_ReadInPES( input_thread_t *p_input, - pes_packet_t **pp_pes, - size_t i_size ) -{ - pes_packet_t *p_pes; - data_packet_t *p_data; +static mtime_t AVI_PTSToChunk( avi_stream_t *, mtime_t i_pts ); +static mtime_t AVI_PTSToByte ( avi_stream_t *, mtime_t i_pts ); +static mtime_t AVI_GetDPTS ( avi_stream_t *, int i_count ); +static mtime_t AVI_GetPTS ( avi_stream_t *p_info ); - if( !(p_pes = input_NewPES( p_input->p_method_data ) ) ) - { - pp_pes = NULL; - return -1; - } +static int AVI_StreamChunkFind( input_thread_t *, unsigned int i_stream ); +static int AVI_StreamChunkSet( input_thread_t *, + unsigned int i_stream, unsigned int i_ck ); +static int AVI_StreamBytesSet( input_thread_t *, + unsigned int i_stream, off_t i_byte ); - *pp_pes = p_pes; +vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t ); +static int AVI_GetKeyFlag( vlc_fourcc_t , uint8_t * ); - if( !i_size ) - { - p_pes->p_first = - p_pes->p_last = - input_NewPacket( p_input->p_method_data, 0 ); - p_pes->i_nb_data = 1; - p_pes->i_pes_size = 0; - return 0; - } +static vlc_bool_t AVI_Interleaved( input_thread_t *p_input ); - p_pes->i_nb_data = 0; - p_pes->i_pes_size = 0; +static int AVI_PacketGetHeader( input_thread_t *p_input, avi_packet_t *p_pk ); +static int AVI_PacketNext( input_thread_t *p_input ); +static int AVI_PacketRead( input_thread_t *p_input, + avi_packet_t *p_pk, + pes_packet_t **pp_pes ); +static int AVI_PacketSearch( input_thread_t *p_input ); - while( p_pes->i_pes_size < i_size ) - { - int i_read; +static void AVI_IndexLoad( input_thread_t *p_input ); +static void AVI_IndexCreate( input_thread_t *p_input ); +static void AVI_IndexAddEntry( demux_sys_t *, int, AVIIndexEntry_t * ); - i_read = input_SplitBuffer(p_input, - &p_data, - __MIN( i_size - - p_pes->i_pes_size, 2048 ) ); - if( i_read <= 0 ) - { - /* should occur only with EOF and max allocation reached - * it safer to return an error */ - /* free pes */ - input_DeletePES( p_input->p_method_data, p_pes ); - return -1; - } +static mtime_t AVI_MovieGetLength( input_thread_t * ); - if( !p_pes->p_first ) - { - p_pes->p_first = p_data; - } - else - { - p_pes->p_last->p_next = p_data; - } - p_pes->p_last = p_data; - p_pes->i_nb_data++; - p_pes->i_pes_size += i_read; - } +/***************************************************************************** + * Stream management + *****************************************************************************/ +static vlc_bool_t AVI_StreamStart ( input_thread_t *, int ); +static void AVI_StreamStop ( input_thread_t *, int ); +static int AVI_StreamSeek ( input_thread_t *, int, mtime_t ); +static int AVI_StreamStopFinishedStreams( input_thread_t *); +/***************************************************************************** + * Open: check file and initializes AVI structures + *****************************************************************************/ +static int Open( vlc_object_t * p_this ) +{ + input_thread_t * p_input = (input_thread_t *)p_this; + 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; +#if 0 + avi_chunk_list_t *p_INFO; + avi_chunk_strz_t *p_name; +#endif + avi_chunk_avih_t *p_avih; + demux_sys_t *p_avi; + es_descriptor_t *p_es = NULL; /* avoid warning */ + unsigned int i; +#ifdef __AVI_SUBTITLE__ + mtime_t i_microsecperframe = 0; // for some subtitle format +#endif - return p_pes->i_pes_size; -} + vlc_bool_t b_stream_audio, b_stream_video; + uint8_t *p_peek; -/* check if the file is interleaved */ -static vlc_bool_t AVI_Interleaved( input_thread_t *p_input ); -/* Test if it seems that it's a key frame */ -static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, uint8_t *p_byte ) -{ - switch( i_fourcc ) + /* Is it an avi file ? */ + if( input_Peek( p_input, &p_peek, 12 ) < 12 ) { - case FOURCC_DIV1: - /* we have: - * startcode: 0x00000100 32bits - * framenumber ? 5bits - * piture type 0(I),1(P) 2bits - */ - if( GetDWBE( p_byte ) != 0x00000100 ) - { - /* it's not an msmpegv1 stream, strange...*/ - return AVIIF_KEYFRAME; - } - else - { - return p_byte[4] & 0x06 ? 0 : AVIIF_KEYFRAME; - } - case FOURCC_DIV2: - case FOURCC_DIV3: // wmv1 also - /* we have - * picture type 0(I),1(P) 2bits - */ - return p_byte[0] & 0xC0 ? 0 : AVIIF_KEYFRAME; - case FOURCC_mp4v: - /* we should find first occurence of 0x000001b6 (32bits) - * startcode: 0x000001b6 32bits - * piture type 0(I),1(P) 2bits - */ - if( GetDWBE( p_byte ) != 0x000001b6 ) - { - /* not true , need to find the first VOP header */ - return AVIIF_KEYFRAME; - } - else - { - return p_byte[4] & 0xC0 ? 0 : AVIIF_KEYFRAME; - } - default: - /* I can't do it, so say yes */ - return AVIIF_KEYFRAME; + msg_Err( p_input, "cannot peek()" ); + return VLC_EGENERIC; } -} - -vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t i_codec ) -{ - switch( i_cat ) + if( strncmp( &p_peek[0], "RIFF", 4 ) || strncmp( &p_peek[8], "AVI ", 4 ) ) { - case AUDIO_ES: - wf_tag_to_fourcc( i_codec, &i_codec, NULL ); - return i_codec; - - case VIDEO_ES: - // XXX DIV1 <- msmpeg4v1, DIV2 <- msmpeg4v2, DIV3 <- msmpeg4v3, mp4v for mpeg4 - switch( i_codec ) - { - case FOURCC_DIV1: - case FOURCC_div1: - case FOURCC_MPG4: - case FOURCC_mpg4: - return FOURCC_DIV1; - case FOURCC_DIV2: - case FOURCC_div2: - case FOURCC_MP42: - case FOURCC_mp42: - case FOURCC_MPG3: - case FOURCC_mpg3: - return FOURCC_DIV2; - case FOURCC_div3: - case FOURCC_MP43: - case FOURCC_mp43: - case FOURCC_DIV3: - case FOURCC_DIV4: - case FOURCC_div4: - case FOURCC_DIV5: - case FOURCC_div5: - case FOURCC_DIV6: - case FOURCC_div6: - case FOURCC_AP41: - case FOURCC_3IV1: - case FOURCC_3iv1: - case FOURCC_3IVD: - case FOURCC_3ivd: - case FOURCC_3VID: - case FOURCC_3vid: - return FOURCC_DIV3; - case FOURCC_DIVX: - case FOURCC_divx: - case FOURCC_MP4S: - case FOURCC_mp4s: - case FOURCC_M4S2: - case FOURCC_m4s2: - case FOURCC_xvid: - case FOURCC_XVID: - case FOURCC_XviD: - case FOURCC_DX50: - case FOURCC_mp4v: - case FOURCC_4: - case FOURCC_3IV2: - case FOURCC_3iv2: - return FOURCC_mp4v; - } - default: - return VLC_FOURCC( 'u', 'n', 'd', 'f' ); + msg_Warn( p_input, "avi module discarded (invalid header)" ); + return VLC_EGENERIC; } -} - -static void AVI_ParseStreamHeader( vlc_fourcc_t i_id, - int *pi_number, int *pi_type ) -{ -#define SET_PTR( p, v ) if( p ) *(p) = (v); - int c1, c2; - c1 = ((uint8_t *)&i_id)[0]; - c2 = ((uint8_t *)&i_id)[1]; + /* Initialize input structures. */ + p_avi = p_input->p_demux_data = malloc( sizeof(demux_sys_t) ); + memset( p_avi, 0, sizeof( demux_sys_t ) ); + p_avi->i_time = 0; + p_avi->i_pcr = 0; + p_avi->i_movi_lastchunk_pos = 0; + p_avi->b_odml = VLC_FALSE; + p_avi->b_interleaved = VLC_FALSE; - if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' ) + /* Create stream facilities */ + if( ( p_avi->s = stream_OpenInput( p_input ) ) == NULL ) { - SET_PTR( pi_number, 100 ); /* > max stream number */ - SET_PTR( pi_type, UNKNOWN_ES ); + msg_Err( p_input, "cannot create stream_t" ); + free( p_avi ); + return VLC_EGENERIC; } - else + stream_Control( p_avi->s, STREAM_CAN_FASTSEEK, &p_avi->b_seekable ); + + p_input->pf_demux = Demux_Seekable; + /* For unseekable stream, automaticaly use Demux_UnSeekable */ + if( !p_avi->b_seekable || config_GetInt( p_input, "avi-interleaved" ) ) { - SET_PTR( pi_number, (c1 - '0') * 10 + (c2 - '0' ) ); - switch( VLC_TWOCC( ((uint8_t *)&i_id)[2], ((uint8_t *)&i_id)[3] ) ) - { - case AVITWOCC_wb: - SET_PTR( pi_type, AUDIO_ES ); - break; - case AVITWOCC_dc: - case AVITWOCC_db: - SET_PTR( pi_type, VIDEO_ES ); - break; - default: - SET_PTR( pi_type, UNKNOWN_ES ); - break; - } + p_input->pf_demux = Demux_UnSeekable; } -#undef SET_PTR -} - -static int AVI_PacketGetHeader( input_thread_t *p_input, avi_packet_t *p_pk ) -{ - uint8_t *p_peek; - if( input_Peek( p_input, &p_peek, 16 ) < 16 ) + if( AVI_ChunkReadRoot( p_avi->s, &p_avi->ck_root ) ) { + msg_Err( p_input, "avi module discarded (invalid file)" ); return VLC_EGENERIC; } - p_pk->i_fourcc = GetFOURCC( p_peek ); - p_pk->i_size = GetDWLE( p_peek + 4 ); - p_pk->i_pos = AVI_TellAbsolute( p_input ); - if( p_pk->i_fourcc == AVIFOURCC_LIST || p_pk->i_fourcc == AVIFOURCC_RIFF ) - { - p_pk->i_type = GetFOURCC( p_peek + 8 ); - } - else + + if( AVI_ChunkCount( &p_avi->ck_root, AVIFOURCC_RIFF ) > 1 ) { - p_pk->i_type = 0; - } + unsigned int i_count = + AVI_ChunkCount( &p_avi->ck_root, AVIFOURCC_RIFF ); - memcpy( p_pk->i_peek, p_peek + 8, 8 ); + msg_Warn( p_input, "multiple riff -> OpenDML ?" ); + for( i = 1; i < i_count; i++ ) + { + avi_chunk_list_t *p_avix; - AVI_ParseStreamHeader( p_pk->i_fourcc, &p_pk->i_stream, &p_pk->i_cat ); - return VLC_SUCCESS; -} + p_avix = AVI_ChunkFind( &p_avi->ck_root, AVIFOURCC_RIFF, i ); + if( p_avix->i_type == AVIFOURCC_AVIX ) + { + msg_Warn( p_input, "detected OpenDML file" ); + p_avi->b_odml = VLC_TRUE; + break; + } + } + } -static int AVI_PacketNext( input_thread_t *p_input ) -{ - avi_packet_t avi_ck; + p_riff = AVI_ChunkFind( &p_avi->ck_root, AVIFOURCC_RIFF, 0 ); + p_hdrl = AVI_ChunkFind( p_riff, AVIFOURCC_hdrl, 0 ); + p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0 ); +#if 0 + p_INFO = AVI_ChunkFind( p_riff, AVIFOURCC_INFO, 0 ); + p_name = AVI_ChunkFind( p_INFO, AVIFOURCC_INAM, 0 ); +#endif - if( AVI_PacketGetHeader( p_input, &avi_ck ) ) + if( !p_hdrl || !p_movi ) { - return VLC_EGENERIC; + msg_Err( p_input, "avi module discarded (invalid file)" ); + goto error; } - //msg_Dbg( p_input, "skip %4.4s:%4.4s", (char*)&avi_ck.i_fourcc, (char*)&avi_ck.i_type ); - if( avi_ck.i_fourcc == AVIFOURCC_LIST && ( avi_ck.i_type == AVIFOURCC_rec || avi_ck.i_type == AVIFOURCC_movi ) ) + if( !( p_avih = AVI_ChunkFind( p_hdrl, AVIFOURCC_avih, 0 ) ) ) { - return AVI_SkipBytes( p_input, 12 ); + msg_Err( p_input, "cannot find avih chunk" ); + goto error; } - else if( avi_ck.i_fourcc == AVIFOURCC_RIFF && avi_ck.i_type == AVIFOURCC_AVIX ) + p_avi->i_streams = AVI_ChunkCount( p_hdrl, AVIFOURCC_strl ); + if( p_avih->i_streams != p_avi->i_streams ) { - return AVI_SkipBytes( p_input, 24 ); + msg_Warn( p_input, + "found %d stream but %d are declared", + p_avi->i_streams, + p_avih->i_streams ); } - else + if( p_avi->i_streams == 0 ) { - return AVI_SkipBytes( p_input, __EVEN( avi_ck.i_size ) + 8 ); + msg_Err( p_input, "no stream defined!" ); + goto error; } -} -static int AVI_PacketRead( input_thread_t *p_input, - avi_packet_t *p_pk, - pes_packet_t **pp_pes ) -{ - size_t i_size; - vlc_bool_t b_pad; - i_size = __EVEN( p_pk->i_size + 8 ); - b_pad = ( i_size != p_pk->i_size + 8 ); - - if( input_ReadInPES( p_input, pp_pes, i_size ) != (ssize_t)i_size ) + /* create one program */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + if( input_InitStream( p_input, 0 ) == -1) { - return VLC_EGENERIC; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + msg_Err( p_input, "cannot init stream" ); + goto error; } - (*pp_pes)->p_first->p_payload_start += 8; - (*pp_pes)->i_pes_size -= 8; - - if( b_pad ) + if( input_AddProgram( p_input, 0, 0) == NULL ) { - (*pp_pes)->p_last->p_payload_end--; - (*pp_pes)->i_pes_size--; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + msg_Err( p_input, "cannot add program" ); + goto error; } + p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; + p_input->stream.i_mux_rate = 0; /* Fixed later */ + vlc_mutex_unlock( &p_input->stream.stream_lock ); - return VLC_SUCCESS; -} + /* print informations on streams */ + msg_Dbg( p_input, "AVIH: %d stream, flags %s%s%s%s ", + p_avi->i_streams, + p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"", + 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":"" ); + { + input_info_category_t *p_cat = input_InfoCategory( p_input, _("Avi") ); + input_AddInfo( p_cat, _("Number of Streams"), "%d", p_avi->i_streams ); + input_AddInfo( p_cat, _("Flags"), "%s%s%s%s", + p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"", + 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":"" ); + } -static int AVI_PacketSearch( input_thread_t *p_input ) -{ - demux_sys_t *p_avi = p_input->p_demux_data; + /* now read info on each stream and create ES */ + p_avi->pp_info = calloc( p_avi->i_streams, + sizeof( avi_stream_t* ) ); + memset( p_avi->pp_info, + 0, + sizeof( avi_stream_t* ) * p_avi->i_streams ); - avi_packet_t avi_pk; - for( ;; ) + for( i = 0 ; i < p_avi->i_streams; i++ ) { - if( AVI_SkipBytes( p_input, 1 ) ) + avi_chunk_list_t *p_avi_strl; + avi_chunk_strh_t *p_avi_strh; + avi_chunk_strf_auds_t *p_avi_strf_auds; + avi_chunk_strf_vids_t *p_avi_strf_vids; + int i_init_size; + void *p_init_data; +#define p_info p_avi->pp_info[i] + p_info = malloc( sizeof(avi_stream_t ) ); + memset( p_info, 0, sizeof( avi_stream_t ) ); + + p_avi_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i ); + p_avi_strh = AVI_ChunkFind( p_avi_strl, AVIFOURCC_strh, 0 ); + p_avi_strf_auds = (void*) + p_avi_strf_vids = (void*) + AVI_ChunkFind( p_avi_strl, AVIFOURCC_strf, 0 ); + + if( !p_avi_strl || !p_avi_strh || + ( !p_avi_strf_auds && !p_avi_strf_vids ) ) { - return VLC_EGENERIC; + msg_Warn( p_input, "stream[%d] incomplete", i ); + continue; } - AVI_PacketGetHeader( p_input, &avi_pk ); - if( avi_pk.i_stream < p_avi->i_streams && - ( avi_pk.i_cat == AUDIO_ES || avi_pk.i_cat == VIDEO_ES ) ) + + /* *** Init p_info *** */ + p_info->i_rate = p_avi_strh->i_rate; + p_info->i_scale = p_avi_strh->i_scale; + p_info->i_samplesize = p_avi_strh->i_samplesize; + msg_Dbg( p_input, "stream[%d] rate:%d scale:%d samplesize:%d", + i, + p_info->i_rate, p_info->i_scale, p_info->i_samplesize ); + switch( p_avi_strh->i_type ) { - return VLC_SUCCESS; + case( AVIFOURCC_auds ): + p_info->i_cat = AUDIO_ES; + p_info->i_fourcc = + AVI_FourccGetCodec( AUDIO_ES, + p_avi_strf_auds->p_wf->wFormatTag ); + p_info->i_codec = p_info->i_fourcc; + i_init_size = p_avi_strf_auds->i_chunk_size; + p_init_data = p_avi_strf_auds->p_wf; + msg_Dbg( p_input, "stream[%d] audio(0x%x) %d channels %dHz %dbits", + i, + p_avi_strf_auds->p_wf->wFormatTag, + p_avi_strf_auds->p_wf->nChannels, + p_avi_strf_auds->p_wf->nSamplesPerSec, + p_avi_strf_auds->p_wf->wBitsPerSample ); + { + char psz_cat[ sizeof("Stream") + 10 ]; + input_info_category_t *p_cat; + sprintf( psz_cat, _("Stream %d"), i ); + p_cat = input_InfoCategory( p_input, psz_cat ); + input_AddInfo( p_cat, _("Type"), "Audio(0x%x)", + p_avi_strf_auds->p_wf->wFormatTag ); + input_AddInfo( p_cat, _("Codec"), "%4.4s", + (const char*)&(p_info->i_codec) ); + input_AddInfo( p_cat, _("FOURCC"), "0x%x", + p_info->i_codec ); + input_AddInfo( p_cat, _("Channels"), "%d", + p_avi_strf_auds->p_wf->nChannels ); + input_AddInfo( p_cat, _("Sample Rate"), "%d", + p_avi_strf_auds->p_wf->nSamplesPerSec ); + if( p_avi_strf_auds->p_wf->wBitsPerSample > 0 + && p_info->i_scale != 0 ) + { + input_AddInfo( p_cat, _("Bits Per Sample"), "%d", + p_avi_strf_auds->p_wf->wBitsPerSample ); + input_AddInfo( p_cat, _("Audio Bitrate"), "%d", + p_info->i_samplesize * p_info->i_rate + / p_info->i_scale ); + } + } + break; + + case( AVIFOURCC_vids ): + p_info->i_cat = VIDEO_ES; + /* XXX quick hack for playing ffmpeg video, I don't know + who is doing something wrong */ + p_info->i_samplesize = 0; + p_info->i_fourcc = p_avi_strf_vids->p_bih->biCompression; + p_info->i_codec = + AVI_FourccGetCodec( VIDEO_ES, p_info->i_fourcc ); + i_init_size = p_avi_strf_vids->i_chunk_size; + p_init_data = p_avi_strf_vids->p_bih; + msg_Dbg( p_input, "stream[%d] video(%4.4s) %dx%d %dbpp %ffps", + i, + (char*)&p_avi_strf_vids->p_bih->biCompression, + p_avi_strf_vids->p_bih->biWidth, + p_avi_strf_vids->p_bih->biHeight, + p_avi_strf_vids->p_bih->biBitCount, + (float)p_info->i_rate / + (float)p_info->i_scale ); + { + char psz_cat[ sizeof("Stream") + 10 ]; + input_info_category_t *p_cat; + sprintf( psz_cat, "Stream %d", i ); + p_cat = input_InfoCategory( p_input, psz_cat ); + input_AddInfo( p_cat, _("Type"), _("Video") ); + input_AddInfo( p_cat, _("Codec"), "%4.4s", + (const char*)&(p_info->i_codec) ); + input_AddInfo( p_cat, _("FOURCC"), "0x%x", + p_info->i_codec ); + input_AddInfo( p_cat, _("Resolution"), "%dx%d", + p_avi_strf_vids->p_bih->biWidth, + p_avi_strf_vids->p_bih->biHeight ); + input_AddInfo( p_cat, _("Frame Rate"), "%f", + (float)p_info->i_rate / + (float)p_info->i_scale ); + input_AddInfo( p_cat, _("Bits Per Pixel"), "%d", + p_avi_strf_vids->p_bih->biBitCount ); + } +#ifdef __AVI_SUBTITLE__ + if( i_microsecperframe == 0 ) + { + i_microsecperframe = (mtime_t)1000000 * + (mtime_t)p_info->i_scale / + (mtime_t)p_info->i_rate; + } +#endif + break; + default: + msg_Warn( p_input, "stream[%d] unknown type", i ); + p_info->i_cat = UNKNOWN_ES; + i_init_size = 0; + p_init_data = NULL; + { + char psz_cat[32]; /* We'll clip i just in case */ + input_info_category_t *p_cat; + sprintf( psz_cat, "Stream %d", __MIN( i, 100000 ) ); + p_cat = input_InfoCategory( p_input, psz_cat ); + input_AddInfo( p_cat, _("Type"), _("Unknown") ); + } + break; } - switch( avi_pk.i_fourcc ) + p_info->b_activated = VLC_FALSE; + /* add one ES */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_info->p_es = + p_es = input_AddES( p_input, p_input->stream.p_selected_program, + 1+i, p_info->i_cat, NULL, 0 ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + p_es->i_stream_id =i; /* XXX: i don't use it */ + p_es->i_fourcc = p_info->i_fourcc; + if( p_es->i_cat == AUDIO_ES ) { - case AVIFOURCC_JUNK: - case AVIFOURCC_LIST: - case AVIFOURCC_RIFF: - case AVIFOURCC_idx1: - return VLC_SUCCESS; + if( i_init_size < (int)sizeof( WAVEFORMATEX ) ) + { + i_init_size = sizeof( WAVEFORMATEX ); + } + p_es->p_waveformatex = malloc( i_init_size ); + memcpy( p_es->p_waveformatex, p_init_data, i_init_size ); + } + else if( p_es->i_cat == VIDEO_ES ) + { + p_es->p_bitmapinfoheader = malloc( i_init_size ); + memcpy( p_es->p_bitmapinfoheader, p_init_data, i_init_size ); } +#undef p_info } -} +#ifdef __AVI_SUBTITLE__ + if( ( p_avi->p_sub = subtitle_New( p_input, NULL, i_microsecperframe ) ) ) + { + subtitle_Select( p_avi->p_sub ); + } +#endif -static void __AVI_AddEntryIndex( avi_stream_t *p_info, - AVIIndexEntry_t *p_index) -{ - if( p_info->p_index == NULL ) + if( config_GetInt( p_input, "avi-index" ) ) { - p_info->i_idxmax = 16384; - p_info->i_idxnb = 0; - if( !( p_info->p_index = calloc( p_info->i_idxmax, - sizeof( AVIIndexEntry_t ) ) ) ) + if( p_avi->b_seekable ) { - return; + AVI_IndexCreate( p_input ); } - } - if( p_info->i_idxnb >= p_info->i_idxmax ) - { - p_info->i_idxmax += 16384; - if( !( p_info->p_index = realloc( (void*)p_info->p_index, - p_info->i_idxmax * - sizeof( AVIIndexEntry_t ) ) ) ) + else { - return; + msg_Warn( p_input, "cannot create index (unseekable stream)" ); + AVI_IndexLoad( p_input ); } } - /* calculate cumulate length */ - if( p_info->i_idxnb > 0 ) + else { - p_index->i_lengthtotal = - p_info->p_index[p_info->i_idxnb - 1].i_length + - p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal; + AVI_IndexLoad( p_input ); } - else + + /* *** movie length in sec *** */ + p_avi->i_length = AVI_MovieGetLength( p_input ); + if( p_avi->i_length < (mtime_t)p_avih->i_totalframes * + (mtime_t)p_avih->i_microsecperframe / + (mtime_t)1000000 ) { - p_index->i_lengthtotal = 0; + msg_Warn( p_input, "broken or missing index, 'seek' will be axproximative or will have strange behavour" ); } - p_info->p_index[p_info->i_idxnb] = *p_index; - p_info->i_idxnb++; - -} - -static void AVI_IndexAddEntry( demux_sys_t *p_avi, - int i_stream, - AVIIndexEntry_t *p_index) -{ - __AVI_AddEntryIndex( p_avi->pp_info[i_stream], - p_index ); - if( p_avi->i_movi_lastchunk_pos < p_index->i_pos ) + /* fix some BeOS MediaKit generated file */ + for( i = 0 ; i < p_avi->i_streams; i++ ) { - p_avi->i_movi_lastchunk_pos = p_index->i_pos; - } -} - -static int AVI_IndexLoad_idx1( input_thread_t *p_input ) -{ - demux_sys_t *p_avi = p_input->p_demux_data; - - avi_chunk_list_t *p_riff; - avi_chunk_list_t *p_movi; - avi_chunk_idx1_t *p_idx1; + avi_chunk_list_t *p_avi_strl; + avi_chunk_strh_t *p_avi_strh; + avi_chunk_strf_auds_t *p_avi_strf_auds; +#define p_stream p_avi->pp_info[i] - unsigned int i_stream; - unsigned int i_index; - off_t i_offset; - unsigned int i; + if( p_stream->i_cat != AUDIO_ES ) + { + continue; + } + if( p_stream->i_idxnb < 1 || + p_stream->i_scale != 1 || + p_stream->i_samplesize != 0 ) + { + continue; + } + p_avi_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i ); + p_avi_strh = AVI_ChunkFind( p_avi_strl, AVIFOURCC_strh, 0 ); + p_avi_strf_auds = AVI_ChunkFind( p_avi_strl, AVIFOURCC_strf, 0 ); - p_riff = (avi_chunk_list_t*)AVI_ChunkFind( &p_avi->ck_root, - AVIFOURCC_RIFF, 0); + if( p_avi_strf_auds->p_wf->wFormatTag != WAVE_FORMAT_PCM && + (unsigned int)p_stream->i_rate == p_avi_strf_auds->p_wf->nSamplesPerSec ) + { + int64_t i_track_length = + p_stream->p_index[p_stream->i_idxnb-1].i_length + + p_stream->p_index[p_stream->i_idxnb-1].i_lengthtotal; + mtime_t i_length = (mtime_t)p_avih->i_totalframes * + (mtime_t)p_avih->i_microsecperframe; - p_idx1 = (avi_chunk_idx1_t*)AVI_ChunkFind( p_riff, AVIFOURCC_idx1, 0); - p_movi = (avi_chunk_list_t*)AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0); + if( i_length == 0 ) + { + msg_Warn( p_input, "track[%d] cannot be fixed (BeOS MediaKit generated)", i ); + continue; + } + p_stream->i_samplesize = 1; + p_stream->i_rate = i_track_length * (int64_t)1000000/ i_length; + msg_Warn( p_input, "track[%d] fixed with rate=%d scale=%d (BeOS MediaKit generated)", i, p_stream->i_rate, p_stream->i_scale ); + } +#undef p_stream + } - if( !p_idx1 ) + vlc_mutex_lock( &p_input->stream.stream_lock ); + if( p_avi->i_length ) { - msg_Warn( p_input, "cannot find idx1 chunk, no index defined" ); - return VLC_EGENERIC; + p_input->stream.i_mux_rate = + p_input->stream.p_selected_area->i_size / 50 / p_avi->i_length; + + p_avi->b_interleaved = AVI_Interleaved( p_input ); + msg_Dbg( p_input, "interleaved=%s", + p_avi->b_interleaved ? "yes" : "no" ); } + vlc_mutex_unlock( &p_input->stream.stream_lock ); - /* *** calculate offset *** */ - /* Well, avi is __SHIT__ so test more than one entry - * (needed for some avi files) */ - i_offset = 0; - for( i = 0; i < __MIN( p_idx1->i_entry_count, 10 ); i++ ) + b_stream_audio = VLC_FALSE; + b_stream_video = VLC_FALSE; + + for( i = 0; i < p_avi->i_streams; i++ ) { - if( p_idx1->entry[i].i_pos < p_movi->i_chunk_pos ) +#define tk p_avi->pp_info[i] + if( tk->p_es->i_cat == VIDEO_ES && !b_stream_video ) { - i_offset = p_movi->i_chunk_pos + 8; - break; + b_stream_video = AVI_StreamStart( p_input, i ); } + else if(tk->p_es->i_cat == AUDIO_ES && !b_stream_audio ) + { + b_stream_audio = AVI_StreamStart( p_input, i ); + } +#undef tk } - for( i_index = 0; i_index < p_idx1->i_entry_count; i_index++ ) + if( !b_stream_video ) { - unsigned int i_cat; + msg_Warn( p_input, "no video stream found" ); + } + if( !b_stream_audio ) + { + msg_Warn( p_input, "no audio stream found!" ); + } - AVI_ParseStreamHeader( p_idx1->entry[i_index].i_fourcc, - &i_stream, - &i_cat ); - if( i_stream < p_avi->i_streams && - i_cat == p_avi->pp_info[i_stream]->i_cat ) - { - AVIIndexEntry_t index; - index.i_id = p_idx1->entry[i_index].i_fourcc; - index.i_flags = - p_idx1->entry[i_index].i_flags&(~AVIIF_FIXKEYFRAME); - 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_avi, i_stream, &index ); - } + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_input->stream.p_selected_program->b_is_ok = 1; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + if( p_avi->b_seekable ) + { + /* we have read all chunk so go back to movi */ + stream_Seek( p_avi->s, p_movi->i_chunk_pos ); } + /* Skip movi header */ + stream_Read( p_avi->s, NULL, 12 ); + + p_avi->i_movi_begin = p_movi->i_chunk_pos; return VLC_SUCCESS; + +error: + AVI_ChunkFreeRoot( p_avi->s, &p_avi->ck_root ); + stream_Release( p_avi->s ); + free( p_avi ); + return VLC_EGENERIC; } -static void __Parse_indx( input_thread_t *p_input, - int i_stream, - avi_chunk_indx_t *p_indx ) +/***************************************************************************** + * Close: frees unused data + *****************************************************************************/ +static void Close ( vlc_object_t * p_this ) { - demux_sys_t *p_avi = p_input->p_demux_data; - AVIIndexEntry_t index; - int32_t i; - - msg_Dbg( p_input, "loading subindex(0x%x) %d entries", p_indx->i_indextype, p_indx->i_entriesinuse ); - if( p_indx->i_indexsubtype == 0 ) - { - for( i = 0; i < p_indx->i_entriesinuse; i++ ) - { - index.i_id = p_indx->i_id; - index.i_flags = p_indx->idx.std[i].i_size & 0x80000000 ? 0 : AVIIF_KEYFRAME; - index.i_pos = p_indx->i_baseoffset + p_indx->idx.std[i].i_offset - 8; - index.i_length = p_indx->idx.std[i].i_size&0x7fffffff; + input_thread_t * p_input = (input_thread_t *)p_this; + unsigned int i; + demux_sys_t *p_avi = p_input->p_demux_data ; - AVI_IndexAddEntry( p_avi, i_stream, &index ); - } - } - else if( p_indx->i_indexsubtype == AVI_INDEX_2FIELD ) + for( i = 0; i < p_avi->i_streams; i++ ) { - for( i = 0; i < p_indx->i_entriesinuse; i++ ) + if( p_avi->pp_info[i] ) { - index.i_id = p_indx->i_id; - index.i_flags = p_indx->idx.field[i].i_size & 0x80000000 ? 0 : AVIIF_KEYFRAME; - index.i_pos = p_indx->i_baseoffset + p_indx->idx.field[i].i_offset - 8; - index.i_length = p_indx->idx.field[i].i_size; - - AVI_IndexAddEntry( p_avi, i_stream, &index ); + FREE( p_avi->pp_info[i]->p_index ); + free( p_avi->pp_info[i] ); } } - else + FREE( p_avi->pp_info ); +#ifdef __AVI_SUBTITLE__ + if( p_avi->p_sub ) { - msg_Warn( p_input, "unknow subtype index(0x%x)", p_indx->i_indexsubtype ); + subtitle_Close( p_avi->p_sub ); } +#endif + AVI_ChunkFreeRoot( p_avi->s, &p_avi->ck_root ); + + stream_Release( p_avi->s ); + free( p_avi ); } -static void AVI_IndexLoad_indx( input_thread_t *p_input ) +/***************************************************************************** + * 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 avi_stream_toread_s { - demux_sys_t *p_avi = p_input->p_demux_data; - unsigned int i_stream; - int32_t i; + vlc_bool_t b_ok; - avi_chunk_list_t *p_riff; - avi_chunk_list_t *p_hdrl; + int i_toread; - p_riff = (void*)AVI_ChunkFind( &p_avi->ck_root, - AVIFOURCC_RIFF, 0); - p_hdrl = (void*)AVI_ChunkFind( p_riff, AVIFOURCC_hdrl, 0 ); + 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_stream_toread_t; - for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) - { - avi_chunk_list_t *p_strl; - avi_chunk_indx_t *p_indx; +static int Demux_Seekable( input_thread_t *p_input ) +{ + unsigned int i_stream_count; + unsigned int i_stream; + vlc_bool_t b_stream; + vlc_bool_t b_play_audio; + vlc_bool_t b_video; /* is there some video track selected */ + // cannot be more than 100 stream (dcXX or wbXX) + avi_stream_toread_t toread[100]; -#define p_stream p_avi->pp_info[i_stream] - p_strl = (void*)AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i_stream ); - p_indx = (void*)AVI_ChunkFind( p_strl, AVIFOURCC_indx, 0 ); + demux_sys_t *p_avi = p_input->p_demux_data; - if( !p_indx ) - { - msg_Warn( p_input, "cannot find indx (misdetect/broken OpenDML file?)" ); - continue; - } - if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS ) - { - __Parse_indx( p_input, i_stream, p_indx ); - } - else if( p_indx->i_indextype == AVI_INDEX_OF_INDEXES ) + /* detect new selected/unselected streams */ + for( i_stream = 0,i_stream_count= 0, b_video = VLC_FALSE; + i_stream < p_avi->i_streams; i_stream++ ) + { +#define p_stream p_avi->pp_info[i_stream] + if( p_stream->p_es ) { - avi_chunk_indx_t ck_sub; - for( i = 0; i < p_indx->i_entriesinuse; i++ ) + if( p_stream->p_es->p_decoder_fifo && + !p_stream->b_activated ) { - if( AVI_SeekAbsolute( p_input, p_indx->idx.super[i].i_offset ) ) - { - break; - } - - if( AVI_ChunkRead( p_input, &ck_sub, NULL, p_avi->b_seekable ) ) - { - break; - } - __Parse_indx( p_input, i_stream, &ck_sub ); + AVI_StreamStart( p_input, i_stream ); + } + else + if( !p_stream->p_es->p_decoder_fifo && + p_stream->b_activated ) + { + AVI_StreamStop( p_input, i_stream ); } } - else + if( p_stream->b_activated ) { - msg_Warn( p_input, "unknow type index(0x%x)", p_indx->i_indextype ); + i_stream_count++; + if( p_stream->i_cat == VIDEO_ES ) + { + b_video = VLC_TRUE; + } } -#undef p_stream +#undef p_stream } -} - -static void AVI_IndexLoad( input_thread_t *p_input ) -{ - demux_sys_t *p_avi = p_input->p_demux_data; - unsigned int i_stream; - for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) + if( i_stream_count <= 0 ) { - p_avi->pp_info[i_stream]->i_idxnb = 0; - p_avi->pp_info[i_stream]->i_idxmax = 0; - p_avi->pp_info[i_stream]->p_index = NULL; + msg_Warn( p_input, "no track selected, exiting..." ); + return( 0 ); } - if( p_avi->b_odml ) - { - AVI_IndexLoad_indx( p_input ); - } - else + if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT ) { - if( AVI_IndexLoad_idx1( p_input ) ) - { - /* try indx if idx1 failed as some "normal" file have indx too */ - AVI_IndexLoad_indx( p_input ); - } - } + mtime_t i_date; + int i_percent; + /* first wait for empty buffer, arbitrary time FIXME */ + //msleep( DEFAULT_PTS_DELAY ); - for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) - { - msg_Dbg( p_input, - "stream[%d] created %d index entries", - i_stream, - p_avi->pp_info[i_stream]->i_idxnb ); -#if 0 - for( i = 0; i < p_avi->pp_info[i_stream]->i_idxnb; i++ ) + i_date = (mtime_t)1000000 * + (mtime_t)p_avi->i_length * + (mtime_t)stream_Tell( p_avi->s ) / + (mtime_t)p_input->stream.p_selected_area->i_size; + i_percent = 100 * stream_Tell( p_avi->s ) / + p_input->stream.p_selected_area->i_size; + + Seek( p_input, i_date, i_percent); + +#ifdef __AVI_SUBTITLE__ + if( p_avi->p_sub ) { - msg_Dbg( p_input, "stream[%d] idx[%d] pos=%lld size=%d", - i_stream, - i, - p_avi->pp_info[i_stream]->p_index[i].i_pos, - p_avi->pp_info[i_stream]->p_index[i].i_length ); + subtitle_Seek( p_avi->p_sub, p_avi->i_time ); } #endif } -} -static void AVI_IndexCreate( input_thread_t *p_input ) -{ - demux_sys_t *p_avi = p_input->p_demux_data; - avi_chunk_list_t *p_riff; - avi_chunk_list_t *p_movi; + /* wait for the good time */ - unsigned int i_stream; - off_t i_movi_end; + p_avi->i_pcr = p_avi->i_time * 9 / 100; - p_riff = (avi_chunk_list_t*)AVI_ChunkFind( &p_avi->ck_root, - AVIFOURCC_RIFF, 0); - p_movi = (avi_chunk_list_t*)AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0); + input_ClockManageRef( p_input, + p_input->stream.p_selected_program, + p_avi->i_pcr ); - if( !p_movi ) - { - msg_Err( p_input, "cannot find p_movi" ); - return; - } - for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) + p_avi->i_time += 25*1000; /* read 25ms */ + +#ifdef __AVI_SUBTITLE__ + if( p_avi->p_sub ) { - p_avi->pp_info[i_stream]->i_idxnb = 0; - p_avi->pp_info[i_stream]->i_idxmax = 0; - p_avi->pp_info[i_stream]->p_index = NULL; + subtitle_Demux( p_avi->p_sub, p_avi->i_time ); } - i_movi_end = __MIN( (off_t)(p_movi->i_chunk_pos + p_movi->i_chunk_size), - p_input->stream.p_selected_area->i_size ); +#endif - AVI_SeekAbsolute( p_input, p_movi->i_chunk_pos + 12); - msg_Warn( p_input, "creating index from LIST-movi, will take time !" ); - for( ;; ) + /* Check if we need to send the audio data to decoder */ + b_play_audio = !p_input->stream.control.b_mute; + + /* init toread */ + for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) { - avi_packet_t pk; +#define p_stream p_avi->pp_info[i_stream] + mtime_t i_dpts; - if( AVI_PacketGetHeader( p_input, &pk ) ) + toread[i_stream].b_ok = p_stream->b_activated; + if( p_stream->i_idxposc < p_stream->i_idxnb ) { - break; + toread[i_stream].i_posf = + p_stream->p_index[p_stream->i_idxposc].i_pos; + if( p_stream->i_idxposb > 0 ) + { + toread[i_stream].i_posf += 8 + p_stream->i_idxposb; + } } - if( pk.i_stream < p_avi->i_streams && - pk.i_cat == p_avi->pp_info[pk.i_stream]->i_cat ) + else { - AVIIndexEntry_t index; - index.i_id = pk.i_fourcc; - index.i_flags = - AVI_GetKeyFlag(p_avi->pp_info[pk.i_stream]->i_codec, pk.i_peek); - index.i_pos = pk.i_pos; - index.i_length = pk.i_size; - AVI_IndexAddEntry( p_avi, pk.i_stream, &index ); + toread[i_stream].i_posf = -1; + } + + i_dpts = p_avi->i_time - AVI_GetPTS( p_stream ); + + if( p_stream->i_samplesize ) + { + toread[i_stream].i_toread = AVI_PTSToByte( p_stream, + __ABS( i_dpts ) ); } else { - switch( pk.i_fourcc ) - { - case AVIFOURCC_idx1: - if( p_avi->b_odml ) - { - avi_chunk_list_t *p_avix; - p_avix = (void*)AVI_ChunkFind( &p_avi->ck_root, - AVIFOURCC_RIFF, 1 ); - - msg_Dbg( p_input, "looking for new RIFF chunk" ); - if( AVI_SeekAbsolute( p_input, p_avix->i_chunk_pos + 24) ) - { - goto print_stat; - } - break; - } - goto print_stat; - case AVIFOURCC_RIFF: - msg_Dbg( p_input, "new RIFF chunk found" ); - case AVIFOURCC_rec: - case AVIFOURCC_JUNK: - break; - default: - msg_Warn( p_input, "need resync, probably broken avi" ); - if( AVI_PacketSearch( p_input ) ) - { - msg_Warn( p_input, "lost sync, abord index creation" ); - goto print_stat; - } - } + toread[i_stream].i_toread = AVI_PTSToChunk( p_stream, + __ABS( i_dpts ) ); } - if( ( !p_avi->b_odml && pk.i_pos + pk.i_size >= i_movi_end ) || - AVI_PacketNext( p_input ) ) + if( i_dpts < 0 ) { - break; + toread[i_stream].i_toread *= -1; } +#undef p_stream } -print_stat: - for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) - { - msg_Dbg( p_input, - "stream[%d] creating %d index entries", - i_stream, - p_avi->pp_info[i_stream]->i_idxnb ); - } -} - - -/***************************************************************************** - * Stream management - *****************************************************************************/ -static vlc_bool_t AVI_StreamStart ( input_thread_t *, demux_sys_t *, int ); -static int AVI_StreamSeek ( input_thread_t *, demux_sys_t *, int, mtime_t ); -static void AVI_StreamStop ( input_thread_t *, demux_sys_t *, int ); -static int AVI_StreamStopFinishedStreams( input_thread_t *, demux_sys_t * ); - -static vlc_bool_t AVI_StreamStart( input_thread_t *p_input, - demux_sys_t *p_avi, int i_stream ) -{ -#define p_stream p_avi->pp_info[i_stream] - if( !p_stream->p_es ) - { - msg_Warn( p_input, "stream[%d] unselectable", i_stream ); - return VLC_FALSE; - } - if( p_stream->b_activated ) - { - msg_Warn( p_input, "stream[%d] already selected", i_stream ); - return VLC_TRUE; - } + b_stream = VLC_FALSE; - if( !p_stream->p_es->p_decoder_fifo ) - { - vlc_mutex_lock( &p_input->stream.stream_lock ); - input_SelectES( p_input, p_stream->p_es ); - vlc_mutex_unlock( &p_input->stream.stream_lock ); - } - p_stream->b_activated = p_stream->p_es->p_decoder_fifo ? VLC_TRUE - : VLC_FALSE; - if( p_stream->b_activated && p_avi->b_seekable) + for( ;; ) { - AVI_StreamSeek( p_input, p_avi, i_stream, p_avi->i_time ); - } - - return p_stream->b_activated; -#undef p_stream -} - -static void AVI_StreamStop( input_thread_t *p_input, - demux_sys_t *p_avi, int i_stream ) -{ #define p_stream p_avi->pp_info[i_stream] + vlc_bool_t b_done; + pes_packet_t *p_pes; + off_t i_pos; + unsigned int i; + size_t i_size; - if( !p_stream->b_activated ) - { - msg_Warn( p_input, "stream[%d] already unselected", i_stream ); - return; - } - - if( p_stream->p_es->p_decoder_fifo ) - { - vlc_mutex_lock( &p_input->stream.stream_lock ); - input_UnselectES( p_input, p_stream->p_es ); - vlc_mutex_unlock( &p_input->stream.stream_lock ); - } - - - p_stream->b_activated = VLC_FALSE; - -#undef p_stream -} + /* search for first chunk to be read */ + for( i = 0, b_done = VLC_TRUE, i_pos = -1; i < p_avi->i_streams; i++ ) + { + if( !toread[i].b_ok || + AVI_GetDPTS( p_avi->pp_info[i], + toread[i].i_toread ) <= -25 * 1000 ) + { + continue; + } -static int AVI_StreamStopFinishedStreams( input_thread_t *p_input, - demux_sys_t *p_avi ) -{ - unsigned int i_stream; - int b_end; + if( toread[i].i_toread > 0 ) + { + b_done = VLC_FALSE; // not yet finished + } - for( i_stream = 0,b_end = VLC_TRUE; - i_stream < p_avi->i_streams; i_stream++ ) - { -#define p_stream p_avi->pp_info[i_stream] - if( p_stream->i_idxposc >= p_stream->i_idxnb ) - { - AVI_StreamStop( p_input, p_avi, i_stream ); - } - else - { - b_end = VLC_FALSE; + if( toread[i].i_posf > 0 ) + { + if( i_pos == -1 || i_pos > toread[i_stream].i_posf ) + { + i_stream = i; + i_pos = toread[i].i_posf; + } + } } -#undef p_stream - } - return( b_end ); -} -/**************************************************************************** - * AVI_MovieGetLength give max streams length in second - ****************************************************************************/ -static mtime_t AVI_MovieGetLength( input_thread_t *p_input, demux_sys_t *p_avi ) -{ - unsigned int i_stream; - mtime_t i_maxlength; - i_maxlength = 0; - for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) - { -#define p_stream p_avi->pp_info[i_stream] - mtime_t i_length; - /* fix length for each stream */ - if( p_stream->i_idxnb < 1 || !p_stream->p_index ) + if( b_done ) { - continue; +// return( b_stream ? 1 : 0 ); + return( 1 ); } - if( p_stream->i_samplesize ) + if( i_pos == -1 ) { - i_length = - (mtime_t)( p_stream->p_index[p_stream->i_idxnb-1].i_lengthtotal + - p_stream->p_index[p_stream->i_idxnb-1].i_length ) * - (mtime_t)p_stream->i_scale / - (mtime_t)p_stream->i_rate / - (mtime_t)p_stream->i_samplesize; + /* no valid index, we will parse directly the stream + * in case we fail we will disable all finished stream */ + if( p_avi->i_movi_lastchunk_pos >= p_avi->i_movi_begin + 12 ) + { + stream_Seek( p_avi->s, p_avi->i_movi_lastchunk_pos ); + if( AVI_PacketNext( p_input ) ) + { + return( AVI_StreamStopFinishedStreams( p_input ) ? 0 : 1 ); + } + } + else + { + stream_Seek( p_avi->s, p_avi->i_movi_begin + 12 ); + } + + for( ;; ) + { + avi_packet_t avi_pk; + + if( AVI_PacketGetHeader( p_input, &avi_pk ) ) + { + msg_Warn( p_input, + "cannot get packet header, track disabled" ); + return( AVI_StreamStopFinishedStreams( p_input ) ? 0 : 1 ); + } + if( avi_pk.i_stream >= p_avi->i_streams || + ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) ) + { + if( AVI_PacketNext( p_input ) ) + { + msg_Warn( p_input, + "cannot skip packet, track disabled" ); + return( AVI_StreamStopFinishedStreams( p_input ) ? 0 : 1 ); + } + continue; + } + else + { + /* add this chunk to the index */ + AVIIndexEntry_t index; + + index.i_id = avi_pk.i_fourcc; + index.i_flags = + AVI_GetKeyFlag(p_avi->pp_info[avi_pk.i_stream]->i_codec, + avi_pk.i_peek); + index.i_pos = avi_pk.i_pos; + index.i_length = avi_pk.i_size; + AVI_IndexAddEntry( p_avi, avi_pk.i_stream, &index ); + + i_stream = avi_pk.i_stream; + /* do we will read this data ? */ + if( AVI_GetDPTS( p_stream, + toread[i_stream].i_toread ) > -25 * 1000 ) + { + break; + } + else + { + if( AVI_PacketNext( p_input ) ) + { + msg_Warn( p_input, + "cannot skip packet, track disabled" ); + return( AVI_StreamStopFinishedStreams( p_input ) ? 0 : 1 ); + } + } + } + } + } else { - i_length = (mtime_t)p_stream->i_idxnb * - (mtime_t)p_stream->i_scale / - (mtime_t)p_stream->i_rate; + stream_Seek( p_avi->s, i_pos ); } - msg_Dbg( p_input, - "stream[%d] length:"I64Fd" (based on index)", - i_stream, - i_length ); - i_maxlength = __MAX( i_maxlength, i_length ); -#undef p_stream - } - - return i_maxlength; -} - -/***************************************************************************** - * AVIEnd: frees unused data - *****************************************************************************/ -static void __AVIEnd ( vlc_object_t * p_this ) -{ - input_thread_t * p_input = (input_thread_t *)p_this; - unsigned int i; - demux_sys_t *p_avi = p_input->p_demux_data ; - - if( p_avi->pp_info ) - { - for( i = 0; i < p_avi->i_streams; i++ ) + /* read thoses data */ + if( p_stream->i_samplesize ) { - if( p_avi->pp_info[i] ) + unsigned int i_toread; + + if( ( i_toread = toread[i_stream].i_toread ) <= 0 ) { - if( p_avi->pp_info[i]->p_index ) + if( p_stream->i_samplesize > 1 ) + { + i_toread = p_stream->i_samplesize; + } + else { - free( p_avi->pp_info[i]->p_index ); + i_toread = __MAX( AVI_PTSToByte( p_stream, 20 * 1000 ), 100 ); } - free( p_avi->pp_info[i] ); } + i_size = __MIN( p_stream->p_index[p_stream->i_idxposc].i_length - + p_stream->i_idxposb, + i_toread ); + } + else + { + i_size = p_stream->p_index[p_stream->i_idxposc].i_length; } - free( p_avi->pp_info ); - } -#ifdef __AVI_SUBTITLE__ - if( p_avi->p_sub ) - { - subtitle_Close( p_avi->p_sub ); - p_avi->p_sub = NULL; - } -#endif - AVI_ChunkFreeRoot( p_input, &p_avi->ck_root ); - - FREE( p_input->p_demux_data ); -} -/***************************************************************************** - * AVIInit: check file and initializes AVI structures - *****************************************************************************/ -static int AVIInit( vlc_object_t * p_this ) -{ - input_thread_t * p_input = (input_thread_t *)p_this; - 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; -#if 0 - avi_chunk_list_t *p_INFO; - avi_chunk_strz_t *p_name; -#endif - avi_chunk_avih_t *p_avih; - demux_sys_t *p_avi; - es_descriptor_t *p_es = NULL; /* avoid warning */ - unsigned int i; -#ifdef __AVI_SUBTITLE__ - mtime_t i_microsecperframe = 0; // for some subtitle format -#endif + if( p_stream->i_idxposb == 0 ) + { + i_size += 8; // need to read and skip header + } - vlc_bool_t b_stream_audio, b_stream_video; + if( ( p_pes = stream_PesPacket( p_avi->s, __EVEN( i_size ) ) ) == NULL ) + { + msg_Warn( p_input, "failled reading data" ); + AVI_StreamStop( p_input, i_stream ); + toread[i_stream].b_ok = VLC_FALSE; + continue; + } + if( i_size % 2 ) // read was padded on word boundary + { + p_pes->p_last->p_payload_end--; + p_pes->i_pes_size--; + } + // skip header + if( p_stream->i_idxposb == 0 ) + { + p_pes->p_first->p_payload_start += 8; + p_pes->i_pes_size -= 8; + } - p_input->pf_demux = AVIDemux_Seekable; - if( AVI_TestFile( p_input ) ) - { - msg_Warn( p_input, "avi module discarded (invalid header)" ); - return VLC_EGENERIC; - } + p_pes->i_pts = AVI_GetPTS( p_stream ); - /* Initialize access plug-in structures. */ - if( p_input->i_mtu == 0 ) - { - /* Improve speed. */ - p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE; - } +#if 0 + /* fix pts for audio: ie pts sould be for the first byte of the first frame */ + if( p_stream->i_samplesize == 1 ) + { + AVI_FixPTS( p_stream, p_pes ); + } +#endif - if( !( p_input->p_demux_data = - p_avi = malloc( sizeof(demux_sys_t) ) ) ) - { - msg_Err( p_input, "out of memory" ); - return VLC_ENOMEM; - } - memset( p_avi, 0, sizeof( demux_sys_t ) ); - p_avi->i_time = 0; - p_avi->i_pcr = 0; - p_avi->b_seekable = ( ( p_input->stream.b_seekable ) - &&( p_input->stream.i_method == INPUT_METHOD_FILE ) ); - p_avi->i_movi_lastchunk_pos = 0; - p_avi->b_odml = VLC_FALSE; - p_avi->b_interleaved = VLC_FALSE; + /* read data */ + if( p_stream->i_samplesize ) + { + if( p_stream->i_idxposb == 0 ) + { + i_size -= 8; + } + toread[i_stream].i_toread -= i_size; + p_stream->i_idxposb += i_size; + if( p_stream->i_idxposb >= + p_stream->p_index[p_stream->i_idxposc].i_length ) + { + p_stream->i_idxposb = 0; + p_stream->i_idxposc++; + } + } + else + { + toread[i_stream].i_toread--; + p_stream->i_idxposc++; + } - /* *** for unseekable stream, automaticaly use AVIDemux_interleaved *** */ - if( !p_avi->b_seekable || config_GetInt( p_input, "avi-interleaved" ) ) - { - p_input->pf_demux = AVIDemux_UnSeekable; - } + if( p_stream->i_idxposc < p_stream->i_idxnb) + { + toread[i_stream].i_posf = + p_stream->p_index[p_stream->i_idxposc].i_pos; + if( p_stream->i_idxposb > 0 ) + { + toread[i_stream].i_posf += 8 + p_stream->i_idxposb; + } - if( AVI_ChunkReadRoot( p_input, &p_avi->ck_root, p_avi->b_seekable ) ) - { - msg_Err( p_input, "avi module discarded (invalid file)" ); - return VLC_EGENERIC; - } - AVI_ChunkDumpDebug( p_input, &p_avi->ck_root ); + } + else + { + toread[i_stream].i_posf = -1; + } - if( AVI_ChunkCount( &p_avi->ck_root, AVIFOURCC_RIFF ) > 1 ) - { - int i_count = AVI_ChunkCount( &p_avi->ck_root, AVIFOURCC_RIFF ); - int i; + b_stream = VLC_TRUE; // at least one read succeed - msg_Warn( p_input, "multiple riff -> OpenDML ?" ); - for( i = 1; i < i_count; i++ ) + if( p_stream->p_es && p_stream->p_es->p_decoder_fifo && + ( b_play_audio || p_stream->i_cat != AUDIO_ES ) ) { - avi_chunk_list_t *p_avix; + p_pes->i_dts = + p_pes->i_pts = + input_ClockGetTS( p_input, + p_input->stream.p_selected_program, + p_pes->i_pts * 9/100); - p_avix = (avi_chunk_list_t*)AVI_ChunkFind( &p_avi->ck_root, - AVIFOURCC_RIFF, i ); - if( p_avix->i_type == AVIFOURCC_AVIX ) - { - msg_Warn( p_input, "detected OpenDML file" ); + p_pes->i_rate = p_input->stream.control.i_rate; - p_avi->b_odml = VLC_TRUE; - break; - } + input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes ); + } + else + { + input_DeletePES( p_input->p_method_data, p_pes ); } - p_avi->b_odml = VLC_TRUE; } +} - p_riff = (avi_chunk_list_t*)AVI_ChunkFind( &p_avi->ck_root, - AVIFOURCC_RIFF, 0 ); - p_hdrl = (avi_chunk_list_t*)AVI_ChunkFind( p_riff, - AVIFOURCC_hdrl, 0 ); - p_movi = (avi_chunk_list_t*)AVI_ChunkFind( p_riff, - AVIFOURCC_movi, 0 ); -#if 0 - p_INFO = (avi_chunk_list_t*)AVI_ChunkFind( p_riff, - AVIFOURCC_INFO, 0 ); - p_name = (avi_chunk_strz_t*)AVI_ChunkFind( p_INFO, - AVIFOURCC_INAM, 0 ); - if( p_name ) - { - - } -#endif - - if( !p_hdrl || !p_movi ) - { - msg_Err( p_input, "avi module discarded (invalid file)" ); - return VLC_EGENERIC; - } +/***************************************************************************** + * Demux_UnSeekable: reads and demuxes data packets for unseekable file + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise + *****************************************************************************/ +static int Demux_UnSeekable( input_thread_t *p_input ) +{ + demux_sys_t *p_avi = p_input->p_demux_data; + avi_stream_t *p_stream_master; + vlc_bool_t b_audio; + unsigned int i_stream; + unsigned int i_packet; - if( !( p_avih = (avi_chunk_avih_t*)AVI_ChunkFind( p_hdrl, - AVIFOURCC_avih, 0 ) ) ) - { - msg_Err( p_input, "cannot find avih chunk" ); - return VLC_EGENERIC; - } - p_avi->i_streams = AVI_ChunkCount( p_hdrl, AVIFOURCC_strl ); - if( p_avih->i_streams != p_avi->i_streams ) - { - msg_Warn( p_input, - "found %d stream but %d are declared", - p_avi->i_streams, - p_avih->i_streams ); - } - if( p_avi->i_streams == 0 ) - { - AVIEnd( p_input ); - msg_Err( p_input, "no stream defined!" ); - return VLC_EGENERIC; - } + /* Check if we need to send the audio data to decoder */ + b_audio = !p_input->stream.control.b_mute; - /* create one program */ - vlc_mutex_lock( &p_input->stream.stream_lock ); - if( input_InitStream( p_input, 0 ) == -1) - { - vlc_mutex_unlock( &p_input->stream.stream_lock ); - AVIEnd( p_input ); - msg_Err( p_input, "cannot init stream" ); - return VLC_EGENERIC; - } - if( input_AddProgram( p_input, 0, 0) == NULL ) + input_ClockManageRef( p_input, + p_input->stream.p_selected_program, + p_avi->i_pcr ); + /* *** find master stream for data packet skipping algo *** */ + /* *** -> first video, if any, or first audio ES *** */ + for( i_stream = 0, p_stream_master = NULL; + i_stream < p_avi->i_streams; i_stream++ ) { - vlc_mutex_unlock( &p_input->stream.stream_lock ); - AVIEnd( p_input ); - msg_Err( p_input, "cannot add program" ); - return VLC_EGENERIC; +#define p_stream p_avi->pp_info[i_stream] + if( p_stream->p_es && + p_stream->p_es->p_decoder_fifo ) + { + if( p_stream->i_cat == VIDEO_ES ) + { + p_stream_master = p_stream; + break; + } + if( p_stream->i_cat == AUDIO_ES && !p_stream_master ) + { + p_stream_master = p_stream; + } + } +#undef p_stream } - p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - /* print informations on streams */ - msg_Dbg( p_input, "AVIH: %d stream, flags %s%s%s%s ", - p_avi->i_streams, - p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"", - 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":"" ); + if( !p_stream_master ) { - input_info_category_t *p_cat = input_InfoCategory( p_input, _("Avi") ); - input_AddInfo( p_cat, _("Number of Streams"), "%d", p_avi->i_streams ); - input_AddInfo( p_cat, _("Flags"), "%s%s%s%s", - p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"", - 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":"" ); + msg_Warn( p_input, "no more stream selected" ); + return( 0 ); } - /* now read info on each stream and create ES */ - p_avi->pp_info = calloc( p_avi->i_streams, - sizeof( avi_stream_t* ) ); - memset( p_avi->pp_info, - 0, - sizeof( avi_stream_t* ) * p_avi->i_streams ); + p_avi->i_pcr = AVI_GetPTS( p_stream_master ) * 9 / 100; - for( i = 0 ; i < p_avi->i_streams; i++ ) + for( i_packet = 0; i_packet < 10; i_packet++) { - avi_chunk_list_t *p_avi_strl; - avi_chunk_strh_t *p_avi_strh; - avi_chunk_strf_auds_t *p_avi_strf_auds; - avi_chunk_strf_vids_t *p_avi_strf_vids; - int i_init_size; - void *p_init_data; -#define p_info p_avi->pp_info[i] - p_info = malloc( sizeof(avi_stream_t ) ); - memset( p_info, 0, sizeof( avi_stream_t ) ); +#define p_stream p_avi->pp_info[avi_pk.i_stream] - p_avi_strl = (avi_chunk_list_t*)AVI_ChunkFind( p_hdrl, - AVIFOURCC_strl, i ); - p_avi_strh = (avi_chunk_strh_t*)AVI_ChunkFind( p_avi_strl, - AVIFOURCC_strh, 0 ); - p_avi_strf_auds = (avi_chunk_strf_auds_t*) - p_avi_strf_vids = (avi_chunk_strf_vids_t*) - AVI_ChunkFind( p_avi_strl, AVIFOURCC_strf, 0 ); + avi_packet_t avi_pk; - if( !p_avi_strl || !p_avi_strh || - ( !p_avi_strf_auds && !p_avi_strf_vids ) ) + if( AVI_PacketGetHeader( p_input, &avi_pk ) ) { - msg_Warn( p_input, "stream[%d] incomlete", i ); - continue; + return( 0 ); } - /* *** Init p_info *** */ - p_info->i_rate = p_avi_strh->i_rate; - p_info->i_scale = p_avi_strh->i_scale; - p_info->i_samplesize = p_avi_strh->i_samplesize; - msg_Dbg( p_input, "stream[%d] rate:%d scale:%d samplesize:%d", - i, - p_info->i_rate, p_info->i_scale, p_info->i_samplesize ); - switch( p_avi_strh->i_type ) + if( avi_pk.i_stream >= p_avi->i_streams || + ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) ) { - case( AVIFOURCC_auds ): - p_info->i_cat = AUDIO_ES; - p_info->i_fourcc = - AVI_FourccGetCodec( AUDIO_ES, - p_avi_strf_auds->p_wf->wFormatTag ); - p_info->i_codec = p_info->i_fourcc; - i_init_size = p_avi_strf_auds->i_chunk_size; - p_init_data = p_avi_strf_auds->p_wf; - msg_Dbg( p_input, "stream[%d] audio(0x%x) %d channels %dHz %dbits", - i, - p_avi_strf_auds->p_wf->wFormatTag, - p_avi_strf_auds->p_wf->nChannels, - p_avi_strf_auds->p_wf->nSamplesPerSec, - p_avi_strf_auds->p_wf->wBitsPerSample ); - { - char psz_cat[ sizeof("Stream") + 10 ]; - input_info_category_t *p_cat; - sprintf( psz_cat, _("Stream %d"), i ); - p_cat = input_InfoCategory( p_input, psz_cat ); - input_AddInfo( p_cat, _("Type"), "Audio(0x%x)", - p_avi_strf_auds->p_wf->wFormatTag ); - input_AddInfo( p_cat, _("Codec"), "%4.4s", - (const char*)&(p_info->i_codec) ); - input_AddInfo( p_cat, _("FOURCC"), "0x%x", - p_info->i_codec ); - input_AddInfo( p_cat, _("Channels"), "%d", - p_avi_strf_auds->p_wf->nChannels ); - input_AddInfo( p_cat, _("Sample Rate"), "%d", - p_avi_strf_auds->p_wf->nSamplesPerSec ); - if( p_avi_strf_auds->p_wf->wBitsPerSample > 0 - && p_info->i_scale != 0 ) + /* we haven't found an audio or video packet: + * - we have seek, found first next packet + * - others packets could be found, skip them + */ + switch( avi_pk.i_fourcc ) + { + case AVIFOURCC_JUNK: + case AVIFOURCC_LIST: + case AVIFOURCC_RIFF: + return( !AVI_PacketNext( p_input ) ? 1 : 0 ); + case AVIFOURCC_idx1: + if( p_avi->b_odml ) { - input_AddInfo( p_cat, _("Bits Per Sample"), "%d", - p_avi_strf_auds->p_wf->wBitsPerSample ); - input_AddInfo( p_cat, _("Audio Bitrate"), "%d", - p_info->i_samplesize * p_info->i_rate - / p_info->i_scale ); + return( !AVI_PacketNext( p_input ) ? 1 : 0 ); } - } - break; - - case( AVIFOURCC_vids ): - p_info->i_cat = VIDEO_ES; - /* XXX quick hack for playing ffmpeg video, I don't know - who is doing something wrong */ - p_info->i_samplesize = 0; - p_info->i_fourcc = p_avi_strf_vids->p_bih->biCompression; - p_info->i_codec = - AVI_FourccGetCodec( VIDEO_ES, p_info->i_fourcc ); - i_init_size = p_avi_strf_vids->i_chunk_size; - p_init_data = p_avi_strf_vids->p_bih; - msg_Dbg( p_input, "stream[%d] video(%4.4s) %dx%d %dbpp %ffps", - i, - (char*)&p_avi_strf_vids->p_bih->biCompression, - p_avi_strf_vids->p_bih->biWidth, - p_avi_strf_vids->p_bih->biHeight, - p_avi_strf_vids->p_bih->biBitCount, - (float)p_info->i_rate / - (float)p_info->i_scale ); + return( 0 ); // eof + default: + msg_Warn( p_input, + "seems to have lost position, resync" ); + if( AVI_PacketSearch( p_input ) ) + { + msg_Err( p_input, "resync failed" ); + return( -1 ); + } + } + } + else + { + /* do will send this packet to decoder ? */ + if( ( !b_audio && avi_pk.i_cat == AUDIO_ES )|| + !p_stream->p_es || + !p_stream->p_es->p_decoder_fifo ) + { + if( AVI_PacketNext( p_input ) ) { - char psz_cat[ sizeof("Stream") + 10 ]; - input_info_category_t *p_cat; - sprintf( psz_cat, "Stream %d", i ); - p_cat = input_InfoCategory( p_input, psz_cat ); - input_AddInfo( p_cat, _("Type"), _("Video") ); - input_AddInfo( p_cat, _("Codec"), "%4.4s", - (const char*)&(p_info->i_codec) ); - input_AddInfo( p_cat, _("FOURCC"), "0x%x", - p_info->i_codec ); - input_AddInfo( p_cat, _("Resolution"), "%dx%d", - p_avi_strf_vids->p_bih->biWidth, - p_avi_strf_vids->p_bih->biHeight ); - input_AddInfo( p_cat, _("Frame Rate"), "%f", - (float)p_info->i_rate / - (float)p_info->i_scale ); - input_AddInfo( p_cat, _("Bits Per Pixel"), "%d", - p_avi_strf_vids->p_bih->biBitCount ); + return( 0 ); } -#ifdef __AVI_SUBTITLE__ - if( i_microsecperframe == 0 ) + } + else + { + /* it's a selected stream, check for time */ + if( __ABS( AVI_GetPTS( p_stream ) - + AVI_GetPTS( p_stream_master ) )< 600*1000 ) { - i_microsecperframe = (mtime_t)1000000 * - (mtime_t)p_info->i_scale / - (mtime_t)p_info->i_rate; + /* load it and send to decoder */ + pes_packet_t *p_pes; + if( AVI_PacketRead( p_input, &avi_pk, &p_pes ) || !p_pes) + { + return( -1 ); + } + p_pes->i_dts = + p_pes->i_pts = + input_ClockGetTS( p_input, + p_input->stream.p_selected_program, + AVI_GetPTS( p_stream ) * 9/100); + + p_pes->i_rate = p_input->stream.control.i_rate; + + input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes ); } -#endif - break; - default: - msg_Warn( p_input, "stream[%d] unknown type", i ); - p_info->i_cat = UNKNOWN_ES; - i_init_size = 0; - p_init_data = NULL; + else { - char psz_cat[32]; /* We'll clip i just in case */ - input_info_category_t *p_cat; - sprintf( psz_cat, "Stream %d", __MIN( i, 100000 ) ); - p_cat = input_InfoCategory( p_input, psz_cat ); - input_AddInfo( p_cat, _("Type"), _("Unknown") ); + if( AVI_PacketNext( p_input ) ) + { + return( 0 ); + } } - break; - } - p_info->b_activated = VLC_FALSE; - /* add one ES */ - vlc_mutex_lock( &p_input->stream.stream_lock ); - p_info->p_es = - p_es = input_AddES( p_input, p_input->stream.p_selected_program, - 1+i, p_info->i_cat, NULL, 0 ); - vlc_mutex_unlock( &p_input->stream.stream_lock ); - p_es->i_stream_id =i; /* XXX: i don't use it */ - p_es->i_fourcc = p_info->i_fourcc; - if( p_es->i_cat == AUDIO_ES ) - { - if( i_init_size < (int)sizeof( WAVEFORMATEX ) ) + } + + /* *** update stream time position *** */ + if( p_stream->i_samplesize ) { - i_init_size = sizeof( WAVEFORMATEX ); + p_stream->i_idxposb += avi_pk.i_size; } - p_es->p_waveformatex = malloc( i_init_size ); - memcpy( p_es->p_waveformatex, p_init_data, i_init_size ); - } - else if( p_es->i_cat == VIDEO_ES ) - { - p_es->p_bitmapinfoheader = malloc( i_init_size ); - memcpy( p_es->p_bitmapinfoheader, p_init_data, i_init_size ); + else + { + p_stream->i_idxposc++; + } + } -#undef p_info - } -#ifdef __AVI_SUBTITLE__ - if( ( p_avi->p_sub = subtitle_New( p_input, NULL, i_microsecperframe ) ) ) - { - subtitle_Select( p_avi->p_sub ); +#undef p_stream } -#endif - if( config_GetInt( p_input, "avi-index" ) ) + return( 1 ); +} + +/***************************************************************************** + * Seek: goto to i_date or i_percent + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise + *****************************************************************************/ +static int Seek ( input_thread_t *p_input, + mtime_t i_date, int i_percent ) +{ + + demux_sys_t *p_avi = p_input->p_demux_data; + unsigned int i_stream; + msg_Dbg( p_input, + "seek requested: "I64Fd" secondes %d%%", + i_date / 1000000, + i_percent ); + + if( p_avi->b_seekable ) { - if( p_avi->b_seekable ) - { - AVI_IndexCreate( p_input ); - } - else + if( !p_avi->i_length || p_avi->b_interleaved ) { - msg_Warn( p_input, "cannot create index (unseekable stream)" ); - AVI_IndexLoad( p_input ); - } - } - else - { - AVI_IndexLoad( p_input ); - } + avi_stream_t *p_stream; + int64_t i_pos; - /* *** movie length in sec *** */ - p_avi->i_length = AVI_MovieGetLength( p_input, p_avi ); - if( p_avi->i_length < (mtime_t)p_avih->i_totalframes * - (mtime_t)p_avih->i_microsecperframe / - (mtime_t)1000000 ) - { - msg_Warn( p_input, "broken or missing index, 'seek' will be axproximative or will have strange behavour" ); - } + /* use i_percent to create a true i_date */ + if( !p_avi->b_interleaved ) + { + msg_Warn( p_input, + "mmh, seeking without index at %d%%" + " work only for interleaved file", i_percent ); + } - /* fix some BeOS MediaKit generated file */ - for( i = 0 ; i < p_avi->i_streams; i++ ) - { - avi_chunk_list_t *p_avi_strl; - avi_chunk_strh_t *p_avi_strh; - avi_chunk_strf_auds_t *p_avi_strf_auds; -#define p_stream p_avi->pp_info[i] + if( i_percent >= 100 ) + { + msg_Warn( p_input, "cannot seek so far !" ); + return( -1 ); + } + i_percent = __MAX( i_percent, 0 ); - if( p_stream->i_cat != AUDIO_ES ) + /* try to find chunk that is at i_percent or the file */ + i_pos = __MAX( i_percent * + p_input->stream.p_selected_area->i_size / 100, + p_avi->i_movi_begin ); + /* search first selected stream */ + for( i_stream = 0, p_stream = NULL; + i_stream < p_avi->i_streams; i_stream++ ) + { + p_stream = p_avi->pp_info[i_stream]; + if( p_stream->b_activated ) + { + break; + } + } + if( !p_stream || !p_stream->b_activated ) + { + msg_Warn( p_input, "cannot find any selected stream" ); + return( -1 ); + } + + /* be sure that the index exit */ + if( AVI_StreamChunkSet( p_input, + i_stream, + 0 ) ) + { + msg_Warn( p_input, "cannot seek" ); + return( -1 ); + } + + while( i_pos >= p_stream->p_index[p_stream->i_idxposc].i_pos + + p_stream->p_index[p_stream->i_idxposc].i_length + 8 ) + { + /* search after i_idxposc */ + if( AVI_StreamChunkSet( p_input, + i_stream, p_stream->i_idxposc + 1 ) ) + { + msg_Warn( p_input, "cannot seek" ); + return( -1 ); + } + } + i_date = AVI_GetPTS( p_stream ); + /* TODO better support for i_samplesize != 0 */ + msg_Dbg( p_input, "estimate date "I64Fd, i_date ); + } + +#define p_stream p_avi->pp_info[i_stream] + p_avi->i_time = 0; + /* seek for chunk based streams */ + for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) { - continue; + if( p_stream->b_activated && !p_stream->i_samplesize ) +// if( p_stream->b_activated ) + { + AVI_StreamSeek( p_input, i_stream, i_date ); + p_avi->i_time = __MAX( AVI_GetPTS( p_stream ), + p_avi->i_time ); + } } - if( p_stream->i_idxnb < 1 || - p_stream->i_scale != 1 || - p_stream->i_samplesize != 0 ) +#if 1 + if( p_avi->i_time ) { - continue; + i_date = p_avi->i_time; } - p_avi_strl = (avi_chunk_list_t*)AVI_ChunkFind( p_hdrl, - AVIFOURCC_strl, i ); - p_avi_strh = (avi_chunk_strh_t*)AVI_ChunkFind( p_avi_strl, - AVIFOURCC_strh, 0 ); - p_avi_strf_auds = - (avi_chunk_strf_auds_t*)AVI_ChunkFind( p_avi_strl, - AVIFOURCC_strf, 0 ); - - if( p_avi_strf_auds->p_wf->wFormatTag != WAVE_FORMAT_PCM && - (unsigned int)p_stream->i_rate == p_avi_strf_auds->p_wf->nSamplesPerSec ) + /* seek for bytes based streams */ + for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) { - int64_t i_track_length = - p_stream->p_index[p_stream->i_idxnb-1].i_length + - p_stream->p_index[p_stream->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 ) + if( p_stream->b_activated && p_stream->i_samplesize ) { - msg_Warn( p_input, "track[%d] cannot be fixed (BeOS MediaKit generated)", i ); - continue; + AVI_StreamSeek( p_input, i_stream, i_date ); +// p_avi->i_time = __MAX( AVI_GetPTS( p_stream ), p_avi->i_time ); } - p_stream->i_samplesize = 1; - p_stream->i_rate = i_track_length * (int64_t)1000000/ i_length; - msg_Warn( p_input, "track[%d] fixed with rate=%d scale=%d (BeOS MediaKit generated)", i, p_stream->i_rate, p_stream->i_scale ); } -#undef p_stream - } - - vlc_mutex_lock( &p_input->stream.stream_lock ); - if( p_avi->i_length ) - { - p_input->stream.i_mux_rate = - p_input->stream.p_selected_area->i_size / 50 / p_avi->i_length; - - msg_Dbg( p_input, "checking interleaved" ); - p_avi->b_interleaved = AVI_Interleaved( p_input ); - msg_Dbg( p_input, "interleaved=%s", p_avi->b_interleaved ? "yes" : "no" ); - } - else - { - p_input->stream.i_mux_rate = 0; - } - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - b_stream_audio = VLC_FALSE; - b_stream_video = VLC_FALSE; - - for( i = 0; i < p_avi->i_streams; i++ ) - { -#define p_info p_avi->pp_info[i] - switch( p_info->p_es->i_cat ) + msg_Dbg( p_input, "seek: "I64Fd" secondes", p_avi->i_time /1000000 ); + /* set true movie time */ +#endif + if( !p_avi->i_time ) { - case( VIDEO_ES ): - - if( !b_stream_video ) - { - b_stream_video = AVI_StreamStart( p_input, p_avi, i ); - } - break; - - case( AUDIO_ES ): - if( !b_stream_audio ) - { - b_stream_audio = AVI_StreamStart( p_input, p_avi, i ); - } - break; - default: - break; + p_avi->i_time = i_date; } -#undef p_info - } - - if( !b_stream_video ) - { - msg_Warn( p_input, "no video stream found" ); - } - if( !b_stream_audio ) - { - msg_Warn( p_input, "no audio stream found!" ); - } - - vlc_mutex_lock( &p_input->stream.stream_lock ); - p_input->stream.p_selected_program->b_is_ok = 1; - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - if( p_avi->b_seekable ) - { - AVI_ChunkGoto( p_input, p_movi ); +#undef p_stream + return( 1 ); } else { - // already at begining of p_movi + msg_Err( p_input, "shouldn't yet be executed" ); + return( -1 ); } - AVI_SkipBytes( p_input, 12 ); // enter in p_movi - - p_avi->i_movi_begin = p_movi->i_chunk_pos; - return VLC_SUCCESS; } - - /***************************************************************************** * Function to convert pts to chunk or byte *****************************************************************************/ -static inline mtime_t AVI_PTSToChunk( avi_stream_t *p_info, - mtime_t i_pts ) +static mtime_t AVI_PTSToChunk( avi_stream_t *p_info, mtime_t i_pts ) { return (mtime_t)((int64_t)i_pts * (int64_t)p_info->i_rate / (int64_t)p_info->i_scale / (int64_t)1000000 ); } -static inline mtime_t AVI_PTSToByte( avi_stream_t *p_info, - mtime_t i_pts ) +static mtime_t AVI_PTSToByte( avi_stream_t *p_info, mtime_t i_pts ) { return (mtime_t)((int64_t)i_pts * (int64_t)p_info->i_rate / @@ -1559,7 +1416,7 @@ static int AVI_StreamChunkFind( input_thread_t *p_input, if( p_avi->i_movi_lastchunk_pos >= p_avi->i_movi_begin + 12 ) { - AVI_SeekAbsolute( p_input, p_avi->i_movi_lastchunk_pos ); + stream_Seek( p_avi->s, p_avi->i_movi_lastchunk_pos ); if( AVI_PacketNext( p_input ) ) { return VLC_EGENERIC; @@ -1567,7 +1424,7 @@ static int AVI_StreamChunkFind( input_thread_t *p_input, } else { - AVI_SeekAbsolute( p_input, p_avi->i_movi_begin + 12 ); + stream_Seek( p_avi->s, p_avi->i_movi_begin + 12 ); } for( ;; ) @@ -1614,7 +1471,7 @@ static int AVI_StreamChunkFind( input_thread_t *p_input, /* be sure that i_ck will be a valid index entry */ -static int AVI_SetStreamChunk( input_thread_t *p_input, +static int AVI_StreamChunkSet( input_thread_t *p_input, unsigned int i_stream, unsigned int i_ck ) { @@ -1643,7 +1500,7 @@ static int AVI_SetStreamChunk( input_thread_t *p_input, /* XXX FIXME up to now, we assume that all chunk are one after one */ -static int AVI_SetStreamBytes( input_thread_t *p_input, +static int AVI_StreamBytesSet( input_thread_t *p_input, unsigned int i_stream, off_t i_byte ) { @@ -1707,10 +1564,10 @@ static int AVI_SetStreamBytes( input_thread_t *p_input, } static int AVI_StreamSeek( input_thread_t *p_input, - demux_sys_t *p_avi, int i_stream, mtime_t i_date ) { + demux_sys_t *p_avi = p_input->p_demux_data; #define p_stream p_avi->pp_info[i_stream] mtime_t i_oldpts; @@ -1718,7 +1575,7 @@ static int AVI_StreamSeek( input_thread_t *p_input, if( !p_stream->i_samplesize ) { - if( AVI_SetStreamChunk( p_input, + if( AVI_StreamChunkSet( p_input, i_stream, AVI_PTSToChunk( p_stream, i_date ) ) ) { @@ -1740,7 +1597,7 @@ static int AVI_StreamSeek( input_thread_t *p_input, !( p_stream->p_index[p_stream->i_idxposc].i_flags & AVIIF_KEYFRAME ) ) { - if( AVI_SetStreamChunk( p_input, + if( AVI_StreamChunkSet( p_input, i_stream, p_stream->i_idxposc - 1 ) ) { @@ -1754,7 +1611,7 @@ static int AVI_StreamSeek( input_thread_t *p_input, !( p_stream->p_index[p_stream->i_idxposc].i_flags & AVIIF_KEYFRAME ) ) { - if( AVI_SetStreamChunk( p_input, + if( AVI_StreamChunkSet( p_input, i_stream, p_stream->i_idxposc + 1 ) ) { @@ -1766,781 +1623,824 @@ static int AVI_StreamSeek( input_thread_t *p_input, } else { - if( AVI_SetStreamBytes( p_input, + if( AVI_StreamBytesSet( p_input, i_stream, AVI_PTSToByte( p_stream, i_date ) ) ) { return VLC_EGENERIC; } } - return VLC_SUCCESS; -#undef p_stream + return VLC_SUCCESS; +#undef p_stream +} + +/***************************************************************************** + * AVI_Interleaved: check weither a file is interleaved or not. + *****************************************************************************/ +static vlc_bool_t AVI_Interleaved( input_thread_t *p_input ) +{ + demux_sys_t *p_sys = p_input->p_demux_data; + unsigned int i; + mtime_t i_time = 0; + vlc_bool_t b_ret = VLC_TRUE; + + int64_t i_max; + + if( p_input->stream.p_selected_area->i_size <= 100 ) + { + return VLC_FALSE; + } + + i_max = __MIN( 2000000, p_input->stream.p_selected_area->i_size / 100 ); + +#define tk p_sys->pp_info[i] + while( i_time < p_sys->i_length * (mtime_t)1000000) + { + int64_t i_ref; + + i_ref = -1; + i_time += 50000; + for( i = 0; i < p_sys->i_streams; i++ ) + { + while( AVI_GetPTS( tk ) < i_time && tk->i_idxposc < tk->i_idxnb - 1 ) + { + tk->i_idxposc++; + } + + if( i_ref == -1 ) + { + i_ref = tk->p_index[tk->i_idxposc].i_pos; + } + if( tk->p_index[tk->i_idxposc].i_pos - i_ref > i_max || + tk->p_index[tk->i_idxposc].i_pos - i_ref < -i_max || + tk->p_index[tk->i_idxposc].i_length > i_max ) + { + msg_Dbg( p_input, "interleaved=no because ref=%lld pos=%lld length=%d (max=%lld)", + i_ref, tk->p_index[tk->i_idxposc].i_pos, tk->p_index[tk->i_idxposc].i_length, i_max ); + b_ret = VLC_FALSE; + goto exit; + } + } + } + +exit: + for( i = 0; i < p_sys->i_streams; i++ ) + { + tk->i_idxposc = 0; + tk->i_idxposb = 0; + } +#undef tk + return b_ret; +} + +/**************************************************************************** + * Return VLC_TRUE if it's a key frame + ****************************************************************************/ +static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, uint8_t *p_byte ) +{ + switch( i_fourcc ) + { + case FOURCC_DIV1: + /* we have: + * startcode: 0x00000100 32bits + * framenumber ? 5bits + * piture type 0(I),1(P) 2bits + */ + if( GetDWBE( p_byte ) != 0x00000100 ) + { + /* it's not an msmpegv1 stream, strange...*/ + return AVIIF_KEYFRAME; + } + else + { + return p_byte[4] & 0x06 ? 0 : AVIIF_KEYFRAME; + } + case FOURCC_DIV2: + case FOURCC_DIV3: // wmv1 also + /* we have + * picture type 0(I),1(P) 2bits + */ + return p_byte[0] & 0xC0 ? 0 : AVIIF_KEYFRAME; + case FOURCC_mp4v: + /* we should find first occurence of 0x000001b6 (32bits) + * startcode: 0x000001b6 32bits + * piture type 0(I),1(P) 2bits + */ + if( GetDWBE( p_byte ) != 0x000001b6 ) + { + /* not true , need to find the first VOP header */ + return AVIIF_KEYFRAME; + } + else + { + return p_byte[4] & 0xC0 ? 0 : AVIIF_KEYFRAME; + } + default: + /* I can't do it, so say yes */ + return AVIIF_KEYFRAME; + } +} + +vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t i_codec ) +{ + switch( i_cat ) + { + case AUDIO_ES: + wf_tag_to_fourcc( i_codec, &i_codec, NULL ); + return i_codec; + + case VIDEO_ES: + // XXX DIV1 <- msmpeg4v1, DIV2 <- msmpeg4v2, DIV3 <- msmpeg4v3, mp4v for mpeg4 + switch( i_codec ) + { + case FOURCC_DIV1: + case FOURCC_div1: + case FOURCC_MPG4: + case FOURCC_mpg4: + return FOURCC_DIV1; + case FOURCC_DIV2: + case FOURCC_div2: + case FOURCC_MP42: + case FOURCC_mp42: + case FOURCC_MPG3: + case FOURCC_mpg3: + return FOURCC_DIV2; + case FOURCC_div3: + case FOURCC_MP43: + case FOURCC_mp43: + case FOURCC_DIV3: + case FOURCC_DIV4: + case FOURCC_div4: + case FOURCC_DIV5: + case FOURCC_div5: + case FOURCC_DIV6: + case FOURCC_div6: + case FOURCC_AP41: + case FOURCC_3IV1: + case FOURCC_3iv1: + case FOURCC_3IVD: + case FOURCC_3ivd: + case FOURCC_3VID: + case FOURCC_3vid: + return FOURCC_DIV3; + case FOURCC_DIVX: + case FOURCC_divx: + case FOURCC_MP4S: + case FOURCC_mp4s: + case FOURCC_M4S2: + case FOURCC_m4s2: + case FOURCC_xvid: + case FOURCC_XVID: + case FOURCC_XviD: + case FOURCC_DX50: + case FOURCC_mp4v: + case FOURCC_4: + case FOURCC_3IV2: + case FOURCC_3iv2: + return FOURCC_mp4v; + } + default: + return VLC_FOURCC( 'u', 'n', 'd', 'f' ); + } } -/***************************************************************************** - * AVI_Interleaved: check weither a file is interleaved or not. - *****************************************************************************/ -static vlc_bool_t AVI_Interleaved( input_thread_t *p_input ) +/**************************************************************************** + * + ****************************************************************************/ +static void AVI_ParseStreamHeader( vlc_fourcc_t i_id, + int *pi_number, int *pi_type ) { - demux_sys_t *p_sys = p_input->p_demux_data; - unsigned int i; - mtime_t i_time = 0; - vlc_bool_t b_ret = VLC_TRUE; +#define SET_PTR( p, v ) if( p ) *(p) = (v); + int c1, c2; - int64_t i_max; + c1 = ((uint8_t *)&i_id)[0]; + c2 = ((uint8_t *)&i_id)[1]; - if( p_input->stream.p_selected_area->i_size <= 100 ) + if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' ) { - return VLC_FALSE; + SET_PTR( pi_number, 100 ); /* > max stream number */ + SET_PTR( pi_type, UNKNOWN_ES ); } - - i_max = __MIN( 2000000, p_input->stream.p_selected_area->i_size / 100 ); - -#define tk p_sys->pp_info[i] - while( i_time < p_sys->i_length * (mtime_t)1000000) + else { - int64_t i_ref; - - i_ref = -1; - i_time += 50000; - for( i = 0; i < p_sys->i_streams; i++ ) + SET_PTR( pi_number, (c1 - '0') * 10 + (c2 - '0' ) ); + switch( VLC_TWOCC( ((uint8_t *)&i_id)[2], ((uint8_t *)&i_id)[3] ) ) { - while( AVI_GetPTS( tk ) < i_time && tk->i_idxposc < tk->i_idxnb - 1 ) - { - tk->i_idxposc++; - } - - if( i_ref == -1 ) - { - i_ref = tk->p_index[tk->i_idxposc].i_pos; - } - if( tk->p_index[tk->i_idxposc].i_pos - i_ref > i_max || - tk->p_index[tk->i_idxposc].i_pos - i_ref < -i_max || - tk->p_index[tk->i_idxposc].i_length > i_max ) - { - msg_Dbg( p_input, "interleaved=no because ref=%lld pos=%lld length=%d (max=%lld)", - i_ref, tk->p_index[tk->i_idxposc].i_pos, tk->p_index[tk->i_idxposc].i_length, i_max ); - b_ret = VLC_FALSE; - goto exit; - } + case AVITWOCC_wb: + SET_PTR( pi_type, AUDIO_ES ); + break; + case AVITWOCC_dc: + case AVITWOCC_db: + SET_PTR( pi_type, VIDEO_ES ); + break; + default: + SET_PTR( pi_type, UNKNOWN_ES ); + break; } } - -exit: - for( i = 0; i < p_sys->i_streams; i++ ) - { - tk->i_idxposc = 0; - tk->i_idxposb = 0; - } -#undef tk - return b_ret; +#undef SET_PTR } -/***************************************************************************** - * AVISeek: goto to i_date or i_percent - ***************************************************************************** - * Returns -1 in case of error, 0 in case of EOF, 1 otherwise - *****************************************************************************/ -static int AVISeek ( input_thread_t *p_input, - mtime_t i_date, int i_percent ) +/**************************************************************************** + * + ****************************************************************************/ +static int AVI_PacketGetHeader( input_thread_t *p_input, avi_packet_t *p_pk ) { + demux_sys_t *p_sys = p_input->p_demux_data; + uint8_t *p_peek; - demux_sys_t *p_avi = p_input->p_demux_data; - unsigned int i_stream; - msg_Dbg( p_input, - "seek requested: "I64Fd" secondes %d%%", - i_date / 1000000, - i_percent ); - - if( p_avi->b_seekable ) + if( stream_Peek( p_sys->s, &p_peek, 16 ) < 16 ) { - if( !p_avi->i_length || p_avi->b_interleaved ) - { - avi_stream_t *p_stream; - int64_t i_pos; - - /* use i_percent to create a true i_date */ - if( !p_avi->b_interleaved ) - { - msg_Warn( p_input, - "mmh, seeking without index at %d%%" - " work only for interleaved file", i_percent ); - } + return VLC_EGENERIC; + } + p_pk->i_fourcc = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] ); + p_pk->i_size = GetDWLE( p_peek + 4 ); + p_pk->i_pos = stream_Tell( p_sys->s ); + if( p_pk->i_fourcc == AVIFOURCC_LIST || p_pk->i_fourcc == AVIFOURCC_RIFF ) + { + p_pk->i_type = VLC_FOURCC( p_peek[8], p_peek[9], + p_peek[10], p_peek[11] ); + } + else + { + p_pk->i_type = 0; + } - if( i_percent >= 100 ) - { - msg_Warn( p_input, "cannot seek so far !" ); - return( -1 ); - } - i_percent = __MAX( i_percent, 0 ); + memcpy( p_pk->i_peek, p_peek + 8, 8 ); - /* try to find chunk that is at i_percent or the file */ - i_pos = __MAX( i_percent * - p_input->stream.p_selected_area->i_size / 100, - p_avi->i_movi_begin ); - /* search first selected stream */ - for( i_stream = 0, p_stream = NULL; - i_stream < p_avi->i_streams; i_stream++ ) - { - p_stream = p_avi->pp_info[i_stream]; - if( p_stream->b_activated ) - { - break; - } - } - if( !p_stream || !p_stream->b_activated ) - { - msg_Warn( p_input, "cannot find any selected stream" ); - return( -1 ); - } + AVI_ParseStreamHeader( p_pk->i_fourcc, &p_pk->i_stream, &p_pk->i_cat ); + return VLC_SUCCESS; +} - /* be sure that the index exit */ - if( AVI_SetStreamChunk( p_input, - i_stream, - 0 ) ) - { - msg_Warn( p_input, "cannot seek" ); - return( -1 ); - } +static int AVI_PacketNext( input_thread_t *p_input ) +{ + demux_sys_t *p_sys = p_input->p_demux_data; + avi_packet_t avi_ck; + int i_skip = 0; - while( i_pos >= p_stream->p_index[p_stream->i_idxposc].i_pos + - p_stream->p_index[p_stream->i_idxposc].i_length + 8 ) - { - /* search after i_idxposc */ - if( AVI_SetStreamChunk( p_input, - i_stream, p_stream->i_idxposc + 1 ) ) - { - msg_Warn( p_input, "cannot seek" ); - return( -1 ); - } - } - i_date = AVI_GetPTS( p_stream ); - /* TODO better support for i_samplesize != 0 */ - msg_Dbg( p_input, "estimate date "I64Fd, i_date ); - } + if( AVI_PacketGetHeader( p_input, &avi_ck ) ) + { + return VLC_EGENERIC; + } -#define p_stream p_avi->pp_info[i_stream] - p_avi->i_time = 0; - /* seek for chunk based streams */ - for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) - { - if( p_stream->b_activated && !p_stream->i_samplesize ) -// if( p_stream->b_activated ) - { - AVI_StreamSeek( p_input, p_avi, i_stream, i_date ); - p_avi->i_time = __MAX( AVI_GetPTS( p_stream ), - p_avi->i_time ); - } - } -#if 1 - if( p_avi->i_time ) - { - i_date = p_avi->i_time; - } - /* seek for bytes based streams */ - for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) - { - if( p_stream->b_activated && p_stream->i_samplesize ) - { - AVI_StreamSeek( p_input, p_avi, i_stream, i_date ); -// p_avi->i_time = __MAX( AVI_GetPTS( p_stream ), p_avi->i_time ); - } - } - msg_Dbg( p_input, "seek: "I64Fd" secondes", p_avi->i_time /1000000 ); - /* set true movie time */ -#endif - if( !p_avi->i_time ) - { - p_avi->i_time = i_date; - } -#undef p_stream - return( 1 ); + if( avi_ck.i_fourcc == AVIFOURCC_LIST && + ( avi_ck.i_type == AVIFOURCC_rec || avi_ck.i_type == AVIFOURCC_movi ) ) + { + i_skip = 12; + } + else if( avi_ck.i_fourcc == AVIFOURCC_RIFF && + avi_ck.i_type == AVIFOURCC_AVIX ) + { + i_skip = 24; } else { - msg_Err( p_input, "shouldn't yet be executed" ); - return( -1 ); + i_skip = __EVEN( avi_ck.i_size ) + 8; } -} -#if 0 -static pes_packet_t *PES_split( input_thread_t *p_input, avi_stream_t *p_stream, pes_packet_t *p_pes ) -{ - pes_packet_t *p_pes2; - data_packet_t *p_data; - int i_nb_data; - - if( p_pes->i_nb_data < 2 ) - { - return( NULL ); - } - p_pes2 = input_NewPES( p_input->p_method_data ); - p_pes2->i_pts = p_pes->i_pts; - p_pes2->i_dts = p_pes->i_dts; - p_pes2->i_nb_data = p_pes->i_nb_data/2; - p_pes2->i_pes_size = 0; - for( i_nb_data = 0, p_data = p_pes->p_first; - i_nb_data < p_pes2->i_nb_data; - i_nb_data++, p_data = p_data->p_next ) - { - p_pes2->i_pes_size += - p_data->p_payload_end - p_data->p_payload_start; - p_pes2->p_last = p_data; - } - p_pes2->p_first = p_pes->p_first; - p_pes2->p_last->p_next = NULL; - - p_pes->p_first = p_data; - p_pes->i_pes_size -= p_pes2->i_pes_size; - p_pes->i_nb_data -= p_pes2->i_nb_data; -// p_pes->i_pts += AVI_GetDPTS( p_stream, p_pes2->i_pes_size ); -// p_pes->i_dts += AVI_GetDPTS( p_stream, p_pes2->i_pes_size ); - p_pes->i_pts = 0; - p_pes->i_dts = 0; - return( p_pes2 ); + if( stream_Read( p_sys->s, NULL, i_skip ) != i_skip ) + { + return VLC_EGENERIC; + } + return VLC_SUCCESS; } -#endif - -/***************************************************************************** - * AVIDemux_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 avi_stream_toread_s +static int AVI_PacketRead( input_thread_t *p_input, + avi_packet_t *p_pk, + pes_packet_t **pp_pes ) { - vlc_bool_t b_ok; + demux_sys_t *p_sys = p_input->p_demux_data; - int i_toread; + size_t i_size; + vlc_bool_t b_pad; - 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_stream_toread_t; + i_size = __EVEN( p_pk->i_size + 8 ); + b_pad = ( i_size != p_pk->i_size + 8 ); + + if( ( *pp_pes = stream_PesPacket( p_sys->s, i_size ) ) == NULL ) + { + return VLC_EGENERIC; + } + (*pp_pes)->p_first->p_payload_start += 8; + (*pp_pes)->i_pes_size -= 8; -static int AVIDemux_Seekable( input_thread_t *p_input ) -{ - unsigned int i_stream_count; - unsigned int i_stream; - vlc_bool_t b_stream; - vlc_bool_t b_play_audio; - vlc_bool_t b_video; /* is there some video track selected */ - // cannot be more than 100 stream (dcXX or wbXX) - avi_stream_toread_t toread[100]; + if( b_pad ) + { + (*pp_pes)->p_last->p_payload_end--; + (*pp_pes)->i_pes_size--; + } - demux_sys_t *p_avi = p_input->p_demux_data; + return VLC_SUCCESS; +} +static int AVI_PacketSearch( input_thread_t *p_input ) +{ + demux_sys_t *p_avi = p_input->p_demux_data; - /* detect new selected/unselected streams */ - for( i_stream = 0,i_stream_count= 0, b_video = VLC_FALSE; - i_stream < p_avi->i_streams; i_stream++ ) + avi_packet_t avi_pk; + for( ;; ) { -#define p_stream p_avi->pp_info[i_stream] - if( p_stream->p_es ) + if( stream_Read( p_avi->s, NULL, 1 ) != 1 ) { - if( p_stream->p_es->p_decoder_fifo && - !p_stream->b_activated ) - { - AVI_StreamStart( p_input, p_avi, i_stream ); - } - else - if( !p_stream->p_es->p_decoder_fifo && - p_stream->b_activated ) - { - AVI_StreamStop( p_input, p_avi, i_stream ); - } + return VLC_EGENERIC; } - if( p_stream->b_activated ) + AVI_PacketGetHeader( p_input, &avi_pk ); + if( avi_pk.i_stream < p_avi->i_streams && + ( avi_pk.i_cat == AUDIO_ES || avi_pk.i_cat == VIDEO_ES ) ) { - i_stream_count++; - if( p_stream->i_cat == VIDEO_ES ) - { - b_video = VLC_TRUE; - } + return VLC_SUCCESS; + } + switch( avi_pk.i_fourcc ) + { + case AVIFOURCC_JUNK: + case AVIFOURCC_LIST: + case AVIFOURCC_RIFF: + case AVIFOURCC_idx1: + return VLC_SUCCESS; } -#undef p_stream } +} - if( i_stream_count <= 0 ) +/**************************************************************************** + * Index stuff. + ****************************************************************************/ +static void __AVI_AddEntryIndex( avi_stream_t *p_info, + AVIIndexEntry_t *p_index) +{ + if( p_info->p_index == NULL ) { - msg_Warn( p_input, "no track selected, exiting..." ); - return( 0 ); + p_info->i_idxmax = 16384; + p_info->i_idxnb = 0; + if( !( p_info->p_index = calloc( p_info->i_idxmax, + sizeof( AVIIndexEntry_t ) ) ) ) + { + return; + } } - - if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT ) + if( p_info->i_idxnb >= p_info->i_idxmax ) { - mtime_t i_date; - int i_percent; - /* first wait for empty buffer, arbitrary time FIXME */ - //msleep( DEFAULT_PTS_DELAY ); - - i_date = (mtime_t)1000000 * - (mtime_t)p_avi->i_length * - (mtime_t)AVI_TellAbsolute( p_input ) / - (mtime_t)p_input->stream.p_selected_area->i_size; - i_percent = 100 * AVI_TellAbsolute( p_input ) / - p_input->stream.p_selected_area->i_size; - -// input_ClockInit( p_input->stream.p_selected_program ); - AVISeek( p_input, i_date, i_percent); - -#ifdef __AVI_SUBTITLE__ - if( p_avi->p_sub ) + p_info->i_idxmax += 16384; + if( !( p_info->p_index = realloc( (void*)p_info->p_index, + p_info->i_idxmax * + sizeof( AVIIndexEntry_t ) ) ) ) { - subtitle_Seek( p_avi->p_sub, p_avi->i_time ); + return; } -#endif + } + /* calculate cumulate length */ + if( p_info->i_idxnb > 0 ) + { + p_index->i_lengthtotal = + p_info->p_index[p_info->i_idxnb - 1].i_length + + p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal; + } + else + { + p_index->i_lengthtotal = 0; } + p_info->p_index[p_info->i_idxnb] = *p_index; + p_info->i_idxnb++; - /* wait for the good time */ +} - p_avi->i_pcr = p_avi->i_time * 9 / 100; +static void AVI_IndexAddEntry( demux_sys_t *p_avi, + int i_stream, + AVIIndexEntry_t *p_index) +{ + __AVI_AddEntryIndex( p_avi->pp_info[i_stream], + p_index ); + if( p_avi->i_movi_lastchunk_pos < p_index->i_pos ) + { + p_avi->i_movi_lastchunk_pos = p_index->i_pos; + } +} - input_ClockManageRef( p_input, - p_input->stream.p_selected_program, - p_avi->i_pcr ); +static int AVI_IndexLoad_idx1( input_thread_t *p_input ) +{ + demux_sys_t *p_avi = p_input->p_demux_data; + avi_chunk_list_t *p_riff; + avi_chunk_list_t *p_movi; + avi_chunk_idx1_t *p_idx1; - p_avi->i_time += 25*1000; /* read 25ms */ + unsigned int i_stream; + unsigned int i_index; + off_t i_offset; + unsigned int i; -#ifdef __AVI_SUBTITLE__ - if( p_avi->p_sub ) + p_riff = AVI_ChunkFind( &p_avi->ck_root, AVIFOURCC_RIFF, 0); + p_idx1 = AVI_ChunkFind( p_riff, AVIFOURCC_idx1, 0); + p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0); + + if( !p_idx1 ) { - subtitle_Demux( p_avi->p_sub, p_avi->i_time ); + msg_Warn( p_input, "cannot find idx1 chunk, no index defined" ); + return VLC_EGENERIC; } -#endif - - /* Check if we need to send the audio data to decoder */ - b_play_audio = !p_input->stream.control.b_mute; - /* init toread */ - for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) + /* *** calculate offset *** */ + /* Well, avi is __SHIT__ so test more than one entry + * (needed for some avi files) */ + i_offset = 0; + for( i = 0; i < __MIN( p_idx1->i_entry_count, 10 ); i++ ) { -#define p_stream p_avi->pp_info[i_stream] - mtime_t i_dpts; - - toread[i_stream].b_ok = p_stream->b_activated; - if( p_stream->i_idxposc < p_stream->i_idxnb ) - { - toread[i_stream].i_posf = - p_stream->p_index[p_stream->i_idxposc].i_pos; - if( p_stream->i_idxposb > 0 ) - { - toread[i_stream].i_posf += 8 + p_stream->i_idxposb; - } - } - else + if( p_idx1->entry[i].i_pos < p_movi->i_chunk_pos ) { - toread[i_stream].i_posf = -1; + i_offset = p_movi->i_chunk_pos + 8; + break; } + } - i_dpts = p_avi->i_time - AVI_GetPTS( p_stream ); - - if( p_stream->i_samplesize ) - { - toread[i_stream].i_toread = AVI_PTSToByte( p_stream, - __ABS( i_dpts ) ); - } - else - { - toread[i_stream].i_toread = AVI_PTSToChunk( p_stream, - __ABS( i_dpts ) ); - } + for( i_index = 0; i_index < p_idx1->i_entry_count; i_index++ ) + { + unsigned int i_cat; - if( i_dpts < 0 ) + AVI_ParseStreamHeader( p_idx1->entry[i_index].i_fourcc, + &i_stream, + &i_cat ); + if( i_stream < p_avi->i_streams && + i_cat == p_avi->pp_info[i_stream]->i_cat ) { - toread[i_stream].i_toread *= -1; + AVIIndexEntry_t index; + index.i_id = p_idx1->entry[i_index].i_fourcc; + index.i_flags = + p_idx1->entry[i_index].i_flags&(~AVIIF_FIXKEYFRAME); + 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_avi, i_stream, &index ); } -#undef p_stream } + return VLC_SUCCESS; +} - b_stream = VLC_FALSE; +static void __Parse_indx( input_thread_t *p_input, + int i_stream, + avi_chunk_indx_t *p_indx ) +{ + demux_sys_t *p_avi = p_input->p_demux_data; + AVIIndexEntry_t index; + int32_t i; - for( ;; ) + msg_Dbg( p_input, "loading subindex(0x%x) %d entries", p_indx->i_indextype, p_indx->i_entriesinuse ); + if( p_indx->i_indexsubtype == 0 ) { -#define p_stream p_avi->pp_info[i_stream] - vlc_bool_t b_done; - pes_packet_t *p_pes; - 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_avi->i_streams; i++ ) + for( i = 0; i < p_indx->i_entriesinuse; i++ ) { - if( !toread[i].b_ok || - AVI_GetDPTS( p_avi->pp_info[i], - toread[i].i_toread ) <= -25 * 1000 ) - { - continue; - } - - if( toread[i].i_toread > 0 ) - { - b_done = VLC_FALSE; // not yet finished - } + index.i_id = p_indx->i_id; + index.i_flags = p_indx->idx.std[i].i_size & 0x80000000 ? 0 : AVIIF_KEYFRAME; + index.i_pos = p_indx->i_baseoffset + p_indx->idx.std[i].i_offset - 8; + index.i_length = p_indx->idx.std[i].i_size&0x7fffffff; - if( toread[i].i_posf > 0 ) - { - if( i_pos == -1 || i_pos > toread[i_stream].i_posf ) - { - i_stream = i; - i_pos = toread[i].i_posf; - } - } + AVI_IndexAddEntry( p_avi, i_stream, &index ); } - - if( b_done ) + } + else if( p_indx->i_indexsubtype == AVI_INDEX_2FIELD ) + { + for( i = 0; i < p_indx->i_entriesinuse; i++ ) { -// return( b_stream ? 1 : 0 ); - return( 1 ); + index.i_id = p_indx->i_id; + index.i_flags = p_indx->idx.field[i].i_size & 0x80000000 ? 0 : AVIIF_KEYFRAME; + index.i_pos = p_indx->i_baseoffset + p_indx->idx.field[i].i_offset - 8; + index.i_length = p_indx->idx.field[i].i_size; + + AVI_IndexAddEntry( p_avi, i_stream, &index ); } + } + else + { + msg_Warn( p_input, "unknow subtype index(0x%x)", p_indx->i_indexsubtype ); + } +} - if( i_pos == -1 ) - { - /* no valid index, we will parse directly the stream - * in case we fail we will disable all finished stream */ - if( p_avi->i_movi_lastchunk_pos >= p_avi->i_movi_begin + 12 ) - { - AVI_SeekAbsolute( p_input, p_avi->i_movi_lastchunk_pos ); - if( AVI_PacketNext( p_input ) ) - { - return( AVI_StreamStopFinishedStreams( p_input, p_avi ) ? 0 : 1 ); - } - } - else - { - AVI_SeekAbsolute( p_input, p_avi->i_movi_begin + 12 ); - } +static void AVI_IndexLoad_indx( input_thread_t *p_input ) +{ + demux_sys_t *p_avi = p_input->p_demux_data; + unsigned int i_stream; + int32_t i; - for( ;; ) - { - avi_packet_t avi_pk; + avi_chunk_list_t *p_riff; + avi_chunk_list_t *p_hdrl; - if( AVI_PacketGetHeader( p_input, &avi_pk ) ) - { - msg_Warn( p_input, - "cannot get packet header, track disabled" ); - return( AVI_StreamStopFinishedStreams( p_input, p_avi ) ? 0 : 1 ); - } - if( avi_pk.i_stream >= p_avi->i_streams || - ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) ) - { - if( AVI_PacketNext( p_input ) ) - { - msg_Warn( p_input, - "cannot skip packet, track disabled" ); - return( AVI_StreamStopFinishedStreams( p_input, p_avi ) ? 0 : 1 ); - } - continue; - } - else - { - /* add this chunk to the index */ - AVIIndexEntry_t index; + p_riff = AVI_ChunkFind( &p_avi->ck_root, AVIFOURCC_RIFF, 0); + p_hdrl = AVI_ChunkFind( p_riff, AVIFOURCC_hdrl, 0 ); - index.i_id = avi_pk.i_fourcc; - index.i_flags = - AVI_GetKeyFlag(p_avi->pp_info[avi_pk.i_stream]->i_codec, - avi_pk.i_peek); - index.i_pos = avi_pk.i_pos; - index.i_length = avi_pk.i_size; - AVI_IndexAddEntry( p_avi, avi_pk.i_stream, &index ); + for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) + { + avi_chunk_list_t *p_strl; + avi_chunk_indx_t *p_indx; - i_stream = avi_pk.i_stream; - /* do we will read this data ? */ - if( AVI_GetDPTS( p_stream, - toread[i_stream].i_toread ) > -25 * 1000 ) - { - break; - } - else - { - if( AVI_PacketNext( p_input ) ) - { - msg_Warn( p_input, - "cannot skip packet, track disabled" ); - return( AVI_StreamStopFinishedStreams( p_input, p_avi ) ? 0 : 1 ); - } - } - } - } +#define p_stream p_avi->pp_info[i_stream] + p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i_stream ); + p_indx = AVI_ChunkFind( p_strl, AVIFOURCC_indx, 0 ); - } - else + if( !p_indx ) { - AVI_SeekAbsolute( p_input, i_pos ); + msg_Warn( p_input, "cannot find indx (misdetect/broken OpenDML file?)" ); + continue; } - /* read thoses data */ - if( p_stream->i_samplesize ) + if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS ) { - unsigned int i_toread; - - if( ( i_toread = toread[i_stream].i_toread ) <= 0 ) + __Parse_indx( p_input, i_stream, p_indx ); + } + else if( p_indx->i_indextype == AVI_INDEX_OF_INDEXES ) + { + avi_chunk_indx_t ck_sub; + for( i = 0; i < p_indx->i_entriesinuse; i++ ) { - if( p_stream->i_samplesize > 1 ) + if( stream_Seek( p_avi->s, p_indx->idx.super[i].i_offset ) ) { - i_toread = p_stream->i_samplesize; + break; } - else + + if( AVI_ChunkRead( p_avi->s, &ck_sub, NULL ) ) { - i_toread = __MAX( AVI_PTSToByte( p_stream, 20 * 1000 ), 100 ); + break; } + __Parse_indx( p_input, i_stream, &ck_sub ); } - i_size = __MIN( p_stream->p_index[p_stream->i_idxposc].i_length - - p_stream->i_idxposb, - i_toread ); } else { - i_size = p_stream->p_index[p_stream->i_idxposc].i_length; + msg_Warn( p_input, "unknow type index(0x%x)", p_indx->i_indextype ); } +#undef p_stream + } +} - if( p_stream->i_idxposb == 0 ) - { - i_size += 8; // need to read and skip header - } +static void AVI_IndexLoad( input_thread_t *p_input ) +{ + demux_sys_t *p_avi = p_input->p_demux_data; + unsigned int i_stream; - if( input_ReadInPES( p_input, &p_pes, __EVEN( i_size ) ) < 0 ) - { - msg_Warn( p_input, "failled reading data" ); - AVI_StreamStop( p_input, p_avi, i_stream ); - toread[i_stream].b_ok = VLC_FALSE; - continue; - } + for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) + { + p_avi->pp_info[i_stream]->i_idxnb = 0; + p_avi->pp_info[i_stream]->i_idxmax = 0; + p_avi->pp_info[i_stream]->p_index = NULL; + } - if( i_size % 2 ) // read was padded on word boundary - { - p_pes->p_last->p_payload_end--; - p_pes->i_pes_size--; - } - // skip header - if( p_stream->i_idxposb == 0 ) + if( p_avi->b_odml ) + { + AVI_IndexLoad_indx( p_input ); + } + else + { + if( AVI_IndexLoad_idx1( p_input ) ) { - p_pes->p_first->p_payload_start += 8; - p_pes->i_pes_size -= 8; + /* try indx if idx1 failed as some "normal" file have indx too */ + AVI_IndexLoad_indx( p_input ); } + } - p_pes->i_pts = AVI_GetPTS( p_stream ); - + for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) + { + msg_Dbg( p_input, + "stream[%d] created %d index entries", + i_stream, + p_avi->pp_info[i_stream]->i_idxnb ); #if 0 - /* fix pts for audio: ie pts sould be for the first byte of the first frame */ - if( p_stream->i_samplesize == 1 ) + for( i = 0; i < p_avi->pp_info[i_stream]->i_idxnb; i++ ) { - AVI_FixPTS( p_stream, p_pes ); + msg_Dbg( p_input, "stream[%d] idx[%d] pos=%lld size=%d", + i_stream, + i, + p_avi->pp_info[i_stream]->p_index[i].i_pos, + p_avi->pp_info[i_stream]->p_index[i].i_length ); } #endif + } +} - /* read data */ - if( p_stream->i_samplesize ) +static void AVI_IndexCreate( input_thread_t *p_input ) +{ + demux_sys_t *p_avi = p_input->p_demux_data; + + avi_chunk_list_t *p_riff; + avi_chunk_list_t *p_movi; + + unsigned int i_stream; + off_t i_movi_end; + + p_riff = AVI_ChunkFind( &p_avi->ck_root, AVIFOURCC_RIFF, 0); + p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0); + + if( !p_movi ) + { + msg_Err( p_input, "cannot find p_movi" ); + return; + } + + for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) + { + p_avi->pp_info[i_stream]->i_idxnb = 0; + p_avi->pp_info[i_stream]->i_idxmax = 0; + p_avi->pp_info[i_stream]->p_index = NULL; + } + i_movi_end = __MIN( (off_t)(p_movi->i_chunk_pos + p_movi->i_chunk_size), + p_input->stream.p_selected_area->i_size ); + + stream_Seek( p_avi->s, p_movi->i_chunk_pos + 12 ); + msg_Warn( p_input, "creating index from LIST-movi, will take time !" ); + for( ;; ) + { + avi_packet_t pk; + + if( AVI_PacketGetHeader( p_input, &pk ) ) { - if( p_stream->i_idxposb == 0 ) - { - i_size -= 8; - } - toread[i_stream].i_toread -= i_size; - p_stream->i_idxposb += i_size; - if( p_stream->i_idxposb >= - p_stream->p_index[p_stream->i_idxposc].i_length ) - { - p_stream->i_idxposb = 0; - p_stream->i_idxposc++; - } + break; } - else + if( pk.i_stream < p_avi->i_streams && + pk.i_cat == p_avi->pp_info[pk.i_stream]->i_cat ) { - toread[i_stream].i_toread--; - p_stream->i_idxposc++; + AVIIndexEntry_t index; + index.i_id = pk.i_fourcc; + index.i_flags = + AVI_GetKeyFlag(p_avi->pp_info[pk.i_stream]->i_codec, pk.i_peek); + index.i_pos = pk.i_pos; + index.i_length = pk.i_size; + AVI_IndexAddEntry( p_avi, pk.i_stream, &index ); } - - if( p_stream->i_idxposc < p_stream->i_idxnb) + else { - toread[i_stream].i_posf = - p_stream->p_index[p_stream->i_idxposc].i_pos; - if( p_stream->i_idxposb > 0 ) + switch( pk.i_fourcc ) { - toread[i_stream].i_posf += 8 + p_stream->i_idxposb; + case AVIFOURCC_idx1: + if( p_avi->b_odml ) + { + avi_chunk_list_t *p_avix; + p_avix = AVI_ChunkFind( &p_avi->ck_root, + AVIFOURCC_RIFF, 1 ); + + msg_Dbg( p_input, "looking for new RIFF chunk" ); + if( stream_Seek( p_avi->s, p_avix->i_chunk_pos + 24 ) ) + { + goto print_stat; + } + break; + } + goto print_stat; + case AVIFOURCC_RIFF: + msg_Dbg( p_input, "new RIFF chunk found" ); + case AVIFOURCC_rec: + case AVIFOURCC_JUNK: + break; + default: + msg_Warn( p_input, "need resync, probably broken avi" ); + if( AVI_PacketSearch( p_input ) ) + { + msg_Warn( p_input, "lost sync, abord index creation" ); + goto print_stat; + } } - } - else + + if( ( !p_avi->b_odml && pk.i_pos + pk.i_size >= i_movi_end ) || + AVI_PacketNext( p_input ) ) { - toread[i_stream].i_posf = -1; + break; } + } - b_stream = VLC_TRUE; // at least one read succeed +print_stat: + for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ ) + { + msg_Dbg( p_input, + "stream[%d] creating %d index entries", + i_stream, + p_avi->pp_info[i_stream]->i_idxnb ); + } +} - if( p_stream->p_es && p_stream->p_es->p_decoder_fifo && - ( b_play_audio || p_stream->i_cat != AUDIO_ES ) ) - { - p_pes->i_dts = - p_pes->i_pts = - input_ClockGetTS( p_input, - p_input->stream.p_selected_program, - p_pes->i_pts * 9/100); +/***************************************************************************** + * Stream management + *****************************************************************************/ +static vlc_bool_t AVI_StreamStart( input_thread_t *p_input, int i_stream ) +{ + demux_sys_t *p_avi = p_input->p_demux_data; - p_pes->i_rate = p_input->stream.control.i_rate; +#define p_stream p_avi->pp_info[i_stream] + if( !p_stream->p_es ) + { + msg_Warn( p_input, "stream[%d] unselectable", i_stream ); + return VLC_FALSE; + } + if( p_stream->b_activated ) + { + msg_Warn( p_input, "stream[%d] already selected", i_stream ); + return VLC_TRUE; + } - input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes ); - } - else - { - input_DeletePES( p_input->p_method_data, p_pes ); - } + if( !p_stream->p_es->p_decoder_fifo ) + { + vlc_mutex_lock( &p_input->stream.stream_lock ); + input_SelectES( p_input, p_stream->p_es ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + p_stream->b_activated = p_stream->p_es->p_decoder_fifo ? VLC_TRUE + : VLC_FALSE; + if( p_stream->b_activated && p_avi->b_seekable) + { + AVI_StreamSeek( p_input, i_stream, p_avi->i_time ); } + + return p_stream->b_activated; +#undef p_stream } +static void AVI_StreamStop( input_thread_t *p_input, int i_stream ) +{ + demux_sys_t *p_avi = p_input->p_demux_data; -/***************************************************************************** - * AVIDemux_UnSeekable: reads and demuxes data packets for unseekable file - ***************************************************************************** - * Returns -1 in case of error, 0 in case of EOF, 1 otherwise - *****************************************************************************/ -static int AVIDemux_UnSeekable( input_thread_t *p_input ) +#define p_stream p_avi->pp_info[i_stream] + + if( !p_stream->b_activated ) + { + msg_Warn( p_input, "stream[%d] already unselected", i_stream ); + return; + } + + if( p_stream->p_es->p_decoder_fifo ) + { + vlc_mutex_lock( &p_input->stream.stream_lock ); + input_UnselectES( p_input, p_stream->p_es ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + + + p_stream->b_activated = VLC_FALSE; + +#undef p_stream +} + +static int AVI_StreamStopFinishedStreams( input_thread_t *p_input ) { - demux_sys_t *p_avi = p_input->p_demux_data; - avi_stream_t *p_stream_master; - vlc_bool_t b_audio; + demux_sys_t *p_avi = p_input->p_demux_data; unsigned int i_stream; - unsigned int i_packet; - - /* Check if we need to send the audio data to decoder */ - b_audio = !p_input->stream.control.b_mute; + int b_end; - input_ClockManageRef( p_input, - p_input->stream.p_selected_program, - p_avi->i_pcr ); - /* *** find master stream for data packet skipping algo *** */ - /* *** -> first video, if any, or first audio ES *** */ - for( i_stream = 0, p_stream_master = NULL; + for( i_stream = 0,b_end = VLC_TRUE; i_stream < p_avi->i_streams; i_stream++ ) { #define p_stream p_avi->pp_info[i_stream] - if( p_stream->p_es && - p_stream->p_es->p_decoder_fifo ) + if( p_stream->i_idxposc >= p_stream->i_idxnb ) { - if( p_stream->i_cat == VIDEO_ES ) - { - p_stream_master = p_stream; - break; - } - if( p_stream->i_cat == AUDIO_ES && !p_stream_master ) - { - p_stream_master = p_stream; - } + AVI_StreamStop( p_input, i_stream ); } -#undef p_stream - } - if( !p_stream_master ) - { - msg_Warn( p_input, "no more stream selected" ); - return( 0 ); + else + { + b_end = VLC_FALSE; + } +#undef p_stream } + return( b_end ); +} - p_avi->i_pcr = AVI_GetPTS( p_stream_master ) * 9 / 100; +/**************************************************************************** + * AVI_MovieGetLength give max streams length in second + ****************************************************************************/ +static mtime_t AVI_MovieGetLength( input_thread_t *p_input ) +{ + demux_sys_t *p_sys = p_input->p_demux_data; + unsigned int i_stream; + mtime_t i_maxlength; - for( i_packet = 0; i_packet < 10; i_packet++) + i_maxlength = 0; + for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ ) { -#define p_stream p_avi->pp_info[avi_pk.i_stream] - - avi_packet_t avi_pk; - - if( AVI_PacketGetHeader( p_input, &avi_pk ) ) +#define p_stream p_sys->pp_info[i_stream] + mtime_t i_length; + /* fix length for each stream */ + if( p_stream->i_idxnb < 1 || !p_stream->p_index ) { - return( 0 ); + continue; } -// AVI_ParseStreamHeader( avi_pk.i_fourcc, &i_stream, &i_cat ); - if( avi_pk.i_stream >= p_avi->i_streams || - ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) ) + if( p_stream->i_samplesize ) { - /* we haven't found an audio or video packet: - * - we have seek, found first next packet - * - others packets could be found, skip them - */ - switch( avi_pk.i_fourcc ) - { - case AVIFOURCC_JUNK: - case AVIFOURCC_LIST: - case AVIFOURCC_RIFF: - return( !AVI_PacketNext( p_input ) ? 1 : 0 ); - case AVIFOURCC_idx1: - if( p_avi->b_odml ) - { - return( !AVI_PacketNext( p_input ) ? 1 : 0 ); - } - return( 0 ); // eof - default: - msg_Warn( p_input, - "seems to have lost position, resync" ); - if( AVI_PacketSearch( p_input ) ) - { - msg_Err( p_input, "resync failed" ); - return( -1 ); - } - } + i_length = + (mtime_t)( p_stream->p_index[p_stream->i_idxnb-1].i_lengthtotal + + p_stream->p_index[p_stream->i_idxnb-1].i_length ) * + (mtime_t)p_stream->i_scale / + (mtime_t)p_stream->i_rate / + (mtime_t)p_stream->i_samplesize; } else { - /* do will send this packet to decoder ? */ - if( ( !b_audio && avi_pk.i_cat == AUDIO_ES )|| - !p_stream->p_es || - !p_stream->p_es->p_decoder_fifo ) - { - if( AVI_PacketNext( p_input ) ) - { - return( 0 ); - } - } - else - { - /* it's a selected stream, check for time */ - if( __ABS( AVI_GetPTS( p_stream ) - - AVI_GetPTS( p_stream_master ) )< 600*1000 ) - { - /* load it and send to decoder */ - pes_packet_t *p_pes; - if( AVI_PacketRead( p_input, &avi_pk, &p_pes ) || !p_pes) - { - return( -1 ); - } - p_pes->i_dts = - p_pes->i_pts = - input_ClockGetTS( p_input, - p_input->stream.p_selected_program, - AVI_GetPTS( p_stream ) * 9/100); - - p_pes->i_rate = p_input->stream.control.i_rate; - - input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes ); - } - else - { - if( AVI_PacketNext( p_input ) ) - { - return( 0 ); - } - } - } - - /* *** update stream time position *** */ - if( p_stream->i_samplesize ) - { - p_stream->i_idxposb += avi_pk.i_size; - } - else - { - p_stream->i_idxposc++; - } - + i_length = (mtime_t)p_stream->i_idxnb * + (mtime_t)p_stream->i_scale / + (mtime_t)p_stream->i_rate; } + msg_Dbg( p_input, + "stream[%d] length:"I64Fd" (based on index)", + i_stream, + i_length ); + i_maxlength = __MAX( i_maxlength, i_length ); #undef p_stream } - return( 1 ); + return i_maxlength; } + diff --git a/modules/demux/avi/avi.h b/modules/demux/avi/avi.h index 2f54fbb7b5..bff9f2a33d 100644 --- a/modules/demux/avi/avi.h +++ b/modules/demux/avi/avi.h @@ -2,7 +2,7 @@ * avi.h : AVI file Stream input module for vlc ***************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: avi.h,v 1.11 2003/06/24 23:11:35 fenrir Exp $ + * $Id: avi.h,v 1.12 2003/08/22 20:31:47 fenrir Exp $ * Authors: Laurent Aimar * * This program is free software; you can redistribute it and/or modify @@ -69,6 +69,8 @@ typedef struct avi_stream_s struct demux_sys_t { + stream_t *s; + mtime_t i_time; mtime_t i_length; mtime_t i_pcr; diff --git a/modules/demux/avi/libavi.c b/modules/demux/avi/libavi.c index 2cb0a2aefb..6c776e9f5c 100644 --- a/modules/demux/avi/libavi.c +++ b/modules/demux/avi/libavi.c @@ -2,7 +2,7 @@ * libavi.c : ***************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: libavi.c,v 1.22 2003/08/17 23:02:52 fenrir Exp $ + * $Id: libavi.c,v 1.23 2003/08/22 20:31:47 fenrir Exp $ * Authors: Laurent Aimar * * This program is free software; you can redistribute it and/or modify @@ -21,12 +21,11 @@ *****************************************************************************/ #include /* malloc(), free() */ -#include /* strdup() */ -#include -#include #include #include +#include "ninput.h" +#include "codecs.h" /* BITMAPINFOHEADER */ #include "libavi.h" @@ -41,207 +40,40 @@ static vlc_fourcc_t GetFOURCC( byte_t *p_buff ) { return VLC_FOURCC( p_buff[0], p_buff[1], p_buff[2], p_buff[3] ); } -/***************************************************************************** - * Some basic functions to manipulate stream more easily in vlc - * - * AVI_TellAbsolute get file position - * - * AVI_SeekAbsolute seek in the file - * - * AVI_ReadData read data from the file in a buffer - * - * AVI_SkipBytes skip bytes - * - *****************************************************************************/ -off_t AVI_TellAbsolute( input_thread_t *p_input ) -{ - off_t i_pos; - vlc_mutex_lock( &p_input->stream.stream_lock ); +#define AVI_ChunkFree( a, b ) _AVI_ChunkFree( (a), (avi_chunk_t*)(b) ) +void _AVI_ChunkFree( stream_t *, avi_chunk_t *p_chk ); - i_pos= p_input->stream.p_selected_area->i_tell; - vlc_mutex_unlock( &p_input->stream.stream_lock ); - return i_pos; -} - -int AVI_SeekAbsolute( input_thread_t *p_input, - off_t i_pos) -{ - off_t i_filepos; - - if( p_input->stream.p_selected_area->i_size > 0 && - i_pos >= p_input->stream.p_selected_area->i_size ) - { - return VLC_EGENERIC; - } - - i_filepos = AVI_TellAbsolute( p_input ); - - if( i_filepos == i_pos ) - { - return VLC_SUCCESS; - } - - if( p_input->stream.b_seekable && - ( p_input->stream.i_method == INPUT_METHOD_FILE || - i_pos - i_filepos < 0 || - i_pos - i_filepos > 1024 ) ) - { - input_AccessReinit( p_input ); - p_input->pf_seek( p_input, i_pos ); - return VLC_SUCCESS; - } - else if( i_pos - i_filepos > 0 ) - { - data_packet_t *p_data; - int i_skip = i_pos - i_filepos; - - msg_Warn( p_input, "will skip %d bytes, slow", i_skip ); - if( i_skip < 0 ) - { - return VLC_EGENERIC; // failed - } - while (i_skip > 0 ) - { - int i_read; - - i_read = input_SplitBuffer( p_input, &p_data, - __MIN( 4096, i_skip ) ); - if( i_read <= 0 ) - { - /* Error or eof */ - return VLC_EGENERIC; - } - i_skip -= i_read; - - input_DeletePacket( p_input->p_method_data, p_data ); - } - return VLC_SUCCESS; - } - else - { - return VLC_EGENERIC; - } -} - -/* return amount read if success, 0 if failed */ -int AVI_ReadData( input_thread_t *p_input, uint8_t *p_buff, int i_size ) -{ - data_packet_t *p_data; - - int i_count; - int i_read = 0; - - - if( !i_size ) - { - return 0; - } - - do - { - i_count = input_SplitBuffer(p_input, &p_data, __MIN( i_size, 1024 ) ); - if( i_count <= 0 ) - { - return i_read; - } - memcpy( p_buff, p_data->p_payload_start, i_count ); - input_DeletePacket( p_input->p_method_data, p_data ); - - p_buff += i_count; - i_size -= i_count; - i_read += i_count; - - } while( i_size ); - - return i_read; -} - -int AVI_SkipBytes( input_thread_t *p_input, int64_t i_count ) -{ - /* broken with new use of i_tell */ -#if 0 - int i_buff_size; - vlc_mutex_lock( &p_input->stream.stream_lock ); - i_buff_size = p_input->p_last_data - p_input->p_current_data; - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - if( i_count > 0 && i_count + 1 < i_buff_size ) - { - uint8_t *p_peek; - - input_Peek( p_input, &p_peek, i_count + 1 ); - - vlc_mutex_lock( &p_input->stream.stream_lock ); - p_input->p_current_data += i_count; // skip them - vlc_mutex_unlock( &p_input->stream.stream_lock ); - return VLC_SUCCESS; - } - else -#endif - { - return AVI_SeekAbsolute( p_input, - AVI_TellAbsolute( p_input ) + i_count ); - } -} - -/***************************************************************************** - * - * AVI_TestFile: look at first bytes to see if it's a valid avi file - * - * unseekable: ok - * - *****************************************************************************/ -int AVI_TestFile( input_thread_t *p_input ) -{ - uint8_t *p_peek; - - if( input_Peek( p_input, &p_peek, 8 ) < 8 ) - { - msg_Err( p_input, "cannot peek()" ); - return VLC_EGENERIC; - } - - if( GetFOURCC( p_peek ) == AVIFOURCC_RIFF && - GetFOURCC( p_peek + 8 ) == AVIFOURCC_AVI ) - { - return VLC_SUCCESS; - } - else - { - return VLC_EGENERIC; - } -} /**************************************************************************** * * Basics functions to manipulates chunks * ****************************************************************************/ -static int AVI_ChunkReadCommon( input_thread_t *p_input, - avi_chunk_t *p_chk ) +static int AVI_ChunkReadCommon( stream_t *s, avi_chunk_t *p_chk ) { uint8_t *p_peek; int i_peek; memset( p_chk, 0, sizeof( avi_chunk_t ) ); - if( ( i_peek = input_Peek( p_input, &p_peek, 8 ) ) < 8 ) + if( ( i_peek = stream_Peek( s, &p_peek, 8 ) ) < 8 ) { return VLC_EGENERIC; } p_chk->common.i_chunk_fourcc = GetFOURCC( p_peek ); p_chk->common.i_chunk_size = GetDWLE( p_peek + 4 ); - p_chk->common.i_chunk_pos = AVI_TellAbsolute( p_input ); + p_chk->common.i_chunk_pos = stream_Tell( s ); p_chk->common.p_father = NULL; p_chk->common.p_next = NULL; p_chk->common.p_first = NULL; p_chk->common.p_next = NULL; + #ifdef AVI_DEBUG - msg_Dbg( p_input, + msg_Dbg( (vlc_object_t*)s, "Found Chunk fourcc:%8.8x (%4.4s) size:"I64Fd" pos:"I64Fd, p_chk->common.i_chunk_fourcc, (char*)&p_chk->common.i_chunk_fourcc, @@ -251,14 +83,13 @@ static int AVI_ChunkReadCommon( input_thread_t *p_input, return VLC_SUCCESS; } -static int AVI_NextChunk( input_thread_t *p_input, - avi_chunk_t *p_chk ) +static int AVI_NextChunk( stream_t *s, avi_chunk_t *p_chk ) { avi_chunk_t chk; if( !p_chk ) { - if( AVI_ChunkReadCommon( p_input, &chk ) ) + if( AVI_ChunkReadCommon( s, &chk ) ) { return VLC_EGENERIC; } @@ -267,79 +98,68 @@ static int AVI_NextChunk( input_thread_t *p_input, if( p_chk->common.p_father ) { - if( p_chk->common.p_father->common.i_chunk_pos + + if( p_chk->common.p_father->common.i_chunk_pos + __EVEN( p_chk->common.p_father->common.i_chunk_size ) + 8 < - p_chk->common.i_chunk_pos + + p_chk->common.i_chunk_pos + __EVEN( p_chk->common.i_chunk_size ) + 8 ) { return VLC_EGENERIC; } } - return AVI_SeekAbsolute( p_input, - p_chk->common.i_chunk_pos + + return stream_Seek( s, p_chk->common.i_chunk_pos + __EVEN( p_chk->common.i_chunk_size ) + 8 ); } -int _AVI_ChunkGoto( input_thread_t *p_input, - avi_chunk_t *p_chk ) -{ - if( !p_chk ) - { - return VLC_EGENERIC; - } - return AVI_SeekAbsolute( p_input, p_chk->common.i_chunk_pos ); -} - /**************************************************************************** * - * Functions to read chunks + * Functions to read chunks * ****************************************************************************/ -static int AVI_ChunkRead_list( input_thread_t *p_input, - avi_chunk_t *p_container, - vlc_bool_t b_seekable ) +static int AVI_ChunkRead_list( stream_t *s, avi_chunk_t *p_container ) { avi_chunk_t *p_chk; uint8_t *p_peek; + vlc_bool_t b_seekable; if( p_container->common.i_chunk_size < 8 ) { /* empty box */ - msg_Warn( p_input, "empty list chunk" ); + msg_Warn( (vlc_object_t*)s, "empty list chunk" ); return VLC_EGENERIC; } - if( input_Peek( p_input, &p_peek, 12 ) < 12 ) + if( stream_Peek( s, &p_peek, 12 ) < 12 ) { - msg_Warn( p_input, "cannot peek while reading list chunk" ); + msg_Warn( (vlc_object_t*)s, "cannot peek while reading list chunk" ); return VLC_EGENERIC; } + + stream_Control( s, STREAM_CAN_FASTSEEK, &b_seekable ); + p_container->list.i_type = GetFOURCC( p_peek + 8 ); if( p_container->common.i_chunk_fourcc == AVIFOURCC_LIST && p_container->list.i_type == AVIFOURCC_movi ) { - msg_Dbg( p_input, "Skipping movi chunk" ); + msg_Dbg( (vlc_object_t*)s, "Skipping movi chunk" ); if( b_seekable ) { - return AVI_NextChunk( p_input, p_container ); - } - else - { - return VLC_SUCCESS; // point at begining of LIST-movi + return AVI_NextChunk( s, p_container ); } + return VLC_SUCCESS; // point at begining of LIST-movi } - if( AVI_SkipBytes( p_input, 12 ) ) + if( stream_Read( s, NULL, 12 ) != 12 ) { - msg_Warn( p_input, "cannot enter chunk" ); + msg_Warn( (vlc_object_t*)s, "cannot enter chunk" ); return VLC_EGENERIC; } + #ifdef AVI_DEBUG - msg_Dbg( p_input, + msg_Dbg( (vlc_object_t*)s, "found LIST chunk: \'%4.4s\'", (char*)&p_container->list.i_type ); #endif - msg_Dbg( p_input, "", (char*)&p_container->list.i_type ); + msg_Dbg( (vlc_object_t*)s, "", (char*)&p_container->list.i_type ); for( ; ; ) { p_chk = malloc( sizeof( avi_chunk_t ) ); @@ -354,8 +174,8 @@ static int AVI_ChunkRead_list( input_thread_t *p_input, } p_container->common.p_last = p_chk; - if( AVI_ChunkRead( p_input, p_chk, p_container, b_seekable ) || - ( AVI_TellAbsolute( p_input ) >= + if( AVI_ChunkRead( s, p_chk, p_container ) || + ( stream_Tell( s ) >= (off_t)p_chk->common.p_father->common.i_chunk_pos + (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) ) { @@ -369,7 +189,7 @@ static int AVI_ChunkRead_list( input_thread_t *p_input, } } - msg_Dbg( p_input, "", (char*)&p_container->list.i_type ); + msg_Dbg( (vlc_object_t*)s, "", (char*)&p_container->list.i_type ); return VLC_SUCCESS; } @@ -381,7 +201,7 @@ static int AVI_ChunkRead_list( input_thread_t *p_input, { \ return 0; \ } \ - i_read = AVI_ReadData( p_input, p_read, i_read ); \ + i_read = stream_Read( s, p_read, i_read ); \ p_read += 8; \ i_read -= 8 @@ -389,7 +209,7 @@ static int AVI_ChunkRead_list( input_thread_t *p_input, free( p_buff ); \ if( i_read < 0 ) \ { \ - msg_Warn( p_input, "not enough data" ); \ + msg_Warn( (vlc_object_t*)s, "not enough data" ); \ } \ return code @@ -418,9 +238,7 @@ static int AVI_ChunkRead_list( input_thread_t *p_input, p_read += 4; \ i_read -= 4 -static int AVI_ChunkRead_avih( input_thread_t *p_input, - avi_chunk_t *p_chk, - vlc_bool_t b_seekable ) +static int AVI_ChunkRead_avih( stream_t *s, avi_chunk_t *p_chk ) { AVI_READCHUNK_ENTER; @@ -439,21 +257,19 @@ static int AVI_ChunkRead_avih( input_thread_t *p_input, AVI_READ4BYTES( p_chk->avih.i_start ); AVI_READ4BYTES( p_chk->avih.i_length ); #ifdef AVI_DEBUG - msg_Dbg( p_input, - "avih: streams:%d flags:%s%s%s%s %dx%d", + msg_Dbg( (vlc_object_t*)s, + "avih: streams:%d flags:%s%s%s%s %dx%d", p_chk->avih.i_streams, p_chk->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"", p_chk->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"", p_chk->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"", p_chk->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"", p_chk->avih.i_width, p_chk->avih.i_height ); -#endif +#endif AVI_READCHUNK_EXIT( VLC_SUCCESS ); } -static int AVI_ChunkRead_strh( input_thread_t *p_input, - avi_chunk_t *p_chk, - vlc_bool_t b_seekable ) +static int AVI_ChunkRead_strh( stream_t *s, avi_chunk_t *p_chk ) { AVI_READCHUNK_ENTER; @@ -470,33 +286,31 @@ static int AVI_ChunkRead_strh( input_thread_t *p_input, AVI_READ4BYTES( p_chk->strh.i_quality ); AVI_READ4BYTES( p_chk->strh.i_samplesize ); #ifdef AVI_DEBUG - msg_Dbg( p_input, + msg_Dbg( (vlc_object_t*)s, "strh: type:%4.4s handler:0x%8.8x samplesize:%d %.2ffps", (char*)&p_chk->strh.i_type, p_chk->strh.i_handler, p_chk->strh.i_samplesize, - ( p_chk->strh.i_scale ? + ( p_chk->strh.i_scale ? (float)p_chk->strh.i_rate / (float)p_chk->strh.i_scale : -1) ); #endif AVI_READCHUNK_EXIT( VLC_SUCCESS ); } -static int AVI_ChunkRead_strf( input_thread_t *p_input, - avi_chunk_t *p_chk, - vlc_bool_t b_seekable ) +static int AVI_ChunkRead_strf( stream_t *s, avi_chunk_t *p_chk ) { avi_chunk_t *p_strh; AVI_READCHUNK_ENTER; if( p_chk->common.p_father == NULL ) { - msg_Err( p_input, "malformed avi file" ); + msg_Err( (vlc_object_t*)s, "malformed avi file" ); AVI_READCHUNK_EXIT( VLC_EGENERIC ); } if( !( p_strh = AVI_ChunkFind( p_chk->common.p_father, AVIFOURCC_strh, 0 ) ) ) { - msg_Err( p_input, "malformed avi file" ); + msg_Err( (vlc_object_t*)s, "malformed avi file" ); AVI_READCHUNK_EXIT( VLC_EGENERIC ); } @@ -534,7 +348,7 @@ static int AVI_ChunkRead_strf( input_thread_t *p_input, p_chk->strf.auds.p_wf->cbSize ); } #ifdef AVI_DEBUG - msg_Dbg( p_input, + msg_Dbg( (vlc_object_t*)s, "strf: audio:0x%4.4x channels:%d %dHz %dbits/sample %dkb/s", p_chk->strf.auds.p_wf->wFormatTag, p_chk->strf.auds.p_wf->nChannels, @@ -571,7 +385,7 @@ static int AVI_ChunkRead_strf( input_thread_t *p_input, sizeof(BITMAPINFOHEADER) ); } #ifdef AVI_DEBUG - msg_Dbg( p_input, + msg_Dbg( (vlc_object_t*)s, "strf: video:%4.4s %dx%d planes:%d %dbpp", (char*)&p_chk->strf.vids.p_bih->biCompression, p_chk->strf.vids.p_bih->biWidth, @@ -581,32 +395,26 @@ static int AVI_ChunkRead_strf( input_thread_t *p_input, #endif break; default: - msg_Warn( p_input, "unknown stream type" ); + msg_Warn( (vlc_object_t*)s, "unknown stream type" ); p_chk->strf.common.i_cat = UNKNOWN_ES; break; } AVI_READCHUNK_EXIT( VLC_SUCCESS ); } -static void AVI_ChunkFree_strf( input_thread_t *p_input, - avi_chunk_t *p_chk ) +static void AVI_ChunkFree_strf( avi_chunk_t *p_chk ) { avi_chunk_strf_t *p_strf = (avi_chunk_strf_t*)p_chk; - switch( p_strf->common.i_cat ) + if( p_strf->common.i_cat == AUDIO_ES ) { - case AUDIO_ES: - FREE( p_strf->auds.p_wf ); - break; - case VIDEO_ES: - FREE( p_strf->vids.p_bih ); - break; - default: - break; + FREE( p_strf->auds.p_wf ); + } + else if( p_strf->common.i_cat == VIDEO_ES ) + { + FREE( p_strf->vids.p_bih ); } } -static int AVI_ChunkRead_strd( input_thread_t *p_input, - avi_chunk_t *p_chk, - vlc_bool_t b_seekable ) +static int AVI_ChunkRead_strd( stream_t *s, avi_chunk_t *p_chk ) { AVI_READCHUNK_ENTER; p_chk->strd.p_data = malloc( p_chk->common.i_chunk_size ); @@ -616,9 +424,7 @@ static int AVI_ChunkRead_strd( input_thread_t *p_input, AVI_READCHUNK_EXIT( VLC_SUCCESS ); } -static int AVI_ChunkRead_idx1( input_thread_t *p_input, - avi_chunk_t *p_chk, - vlc_bool_t b_seekable ) +static int AVI_ChunkRead_idx1( stream_t *s, avi_chunk_t *p_chk ) { unsigned int i_count, i_index; @@ -645,13 +451,12 @@ static int AVI_ChunkRead_idx1( input_thread_t *p_input, p_chk->idx1.entry = NULL; } #ifdef AVI_DEBUG - msg_Dbg( p_input, "idx1: index entry:%d", i_count ); + msg_Dbg( (vlc_object_t*)s, "idx1: index entry:%d", i_count ); #endif AVI_READCHUNK_EXIT( VLC_SUCCESS ); } -static void AVI_ChunkFree_idx1( input_thread_t *p_input, - avi_chunk_t *p_chk ) +static void AVI_ChunkFree_idx1( avi_chunk_t *p_chk ) { p_chk->idx1.i_entry_count = 0; p_chk->idx1.i_entry_max = 0; @@ -660,9 +465,7 @@ static void AVI_ChunkFree_idx1( input_thread_t *p_input, -static int AVI_ChunkRead_indx( input_thread_t *p_input, - avi_chunk_t *p_chk, - vlc_bool_t b_seekable ) +static int AVI_ChunkRead_indx( stream_t *s, avi_chunk_t *p_chk ) { unsigned int i_count, i; int32_t i_dummy; @@ -730,16 +533,15 @@ static int AVI_ChunkRead_indx( input_thread_t *p_input, } else { - msg_Warn( p_input, "unknow type/subtype index" ); + msg_Warn( (vlc_object_t*)s, "unknow type/subtype index" ); } #ifdef AVI_DEBUG - msg_Dbg( p_input, "indx: type=%d subtype=%d entry=%d", p_indx->i_indextype, p_indx->i_indexsubtype, p_indx->i_entriesinuse ); + msg_Dbg( (vlc_object_t*)s, "indx: type=%d subtype=%d entry=%d", p_indx->i_indextype, p_indx->i_indexsubtype, p_indx->i_entriesinuse ); #endif AVI_READCHUNK_EXIT( VLC_SUCCESS ); } -static void AVI_ChunkFree_indx( input_thread_t *p_input, - avi_chunk_t *p_chk ) +static void AVI_ChunkFree_indx( avi_chunk_t *p_chk ) { avi_chunk_indx_t *p_indx = (avi_chunk_indx_t*)p_chk; @@ -784,9 +586,7 @@ static struct { AVIFOURCC_strn, "stream name" }, { 0, "???" } }; -static int AVI_ChunkRead_strz( input_thread_t *p_input, - avi_chunk_t *p_chk, - vlc_bool_t b_seekable ) +static int AVI_ChunkRead_strz( stream_t *s, avi_chunk_t *p_chk ) { int i_index; avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk; @@ -810,27 +610,23 @@ static int AVI_ChunkRead_strz( input_thread_t *p_input, p_strz->p_str[i_read] = 0; #ifdef AVI_DEBUG - msg_Dbg( p_input, "%4.4s: %s : %s", + msg_Dbg( (vlc_object_t*)s, "%4.4s: %s : %s", (char*)&p_strz->i_chunk_fourcc, p_strz->p_type, p_strz->p_str); #endif AVI_READCHUNK_EXIT( VLC_SUCCESS ); } -static void AVI_ChunkFree_strz( input_thread_t *p_input, - avi_chunk_t *p_chk ) +static void AVI_ChunkFree_strz( avi_chunk_t *p_chk ) { avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk; FREE( p_strz->p_type ); FREE( p_strz->p_str ); } -static int AVI_ChunkRead_nothing( input_thread_t *p_input, - avi_chunk_t *p_chk, - vlc_bool_t b_seekable ) +static int AVI_ChunkRead_nothing( stream_t *s, avi_chunk_t *p_chk ) { - return AVI_NextChunk( p_input, p_chk ); + return AVI_NextChunk( s, p_chk ); } -static void AVI_ChunkFree_nothing( input_thread_t *p_input, - avi_chunk_t *p_chk ) +static void AVI_ChunkFree_nothing( avi_chunk_t *p_chk ) { } @@ -838,11 +634,8 @@ static void AVI_ChunkFree_nothing( input_thread_t *p_input, static struct { vlc_fourcc_t i_fourcc; - int (*AVI_ChunkRead_function)( input_thread_t *p_input, - avi_chunk_t *p_chk, - vlc_bool_t b_seekable ); - void (*AVI_ChunkFree_function)( input_thread_t *p_input, - avi_chunk_t *p_chk ); + int (*AVI_ChunkRead_function)( stream_t *s, avi_chunk_t *p_chk ); + void (*AVI_ChunkFree_function)( avi_chunk_t *p_chk ); } AVI_Chunk_Function [] = { { AVIFOURCC_RIFF, AVI_ChunkRead_list, AVI_ChunkFree_nothing }, @@ -898,10 +691,7 @@ static int AVI_ChunkFunctionFind( vlc_fourcc_t i_fourcc ) } } -int _AVI_ChunkRead( input_thread_t *p_input, - avi_chunk_t *p_chk, - avi_chunk_t *p_father, - vlc_bool_t b_seekable ) +int _AVI_ChunkRead( stream_t *s, avi_chunk_t *p_chk, avi_chunk_t *p_father ) { int i_index; @@ -910,14 +700,14 @@ int _AVI_ChunkRead( input_thread_t *p_input, return VLC_EGENERIC; } - if( AVI_ChunkReadCommon( p_input, p_chk ) ) + if( AVI_ChunkReadCommon( s, p_chk ) ) { - msg_Warn( p_input, "cannot read one chunk" ); + msg_Warn( (vlc_object_t*)s, "cannot read one chunk" ); return VLC_EGENERIC; } if( p_chk->common.i_chunk_fourcc == VLC_FOURCC( 0, 0, 0, 0 ) ) { - msg_Warn( p_input, "found null fourcc chunk (corrupted file?)" ); + msg_Warn( (vlc_object_t*)s, "found null fourcc chunk (corrupted file?)" ); return VLC_EGENERIC; } p_chk->common.p_father = p_father; @@ -925,20 +715,19 @@ int _AVI_ChunkRead( input_thread_t *p_input, i_index = AVI_ChunkFunctionFind( p_chk->common.i_chunk_fourcc ); if( AVI_Chunk_Function[i_index].AVI_ChunkRead_function ) { - return AVI_Chunk_Function[i_index]. - AVI_ChunkRead_function( p_input, p_chk, b_seekable ); + return AVI_Chunk_Function[i_index].AVI_ChunkRead_function( s, p_chk ); } else if( ((char*)&p_chk->common.i_chunk_fourcc)[0] == 'i' && ((char*)&p_chk->common.i_chunk_fourcc)[1] == 'x' ) { p_chk->common.i_chunk_fourcc = AVIFOURCC_indx; - return AVI_ChunkRead_indx( p_input, p_chk, b_seekable ); + return AVI_ChunkRead_indx( s, p_chk ); } - msg_Warn( p_input, "unknown chunk (not loaded)" ); - return AVI_NextChunk( p_input, p_chk ); + msg_Warn( (vlc_object_t*)s, "unknown chunk (not loaded)" ); + return AVI_NextChunk( s, p_chk ); } -void _AVI_ChunkFree( input_thread_t *p_input, +void _AVI_ChunkFree( stream_t *s, avi_chunk_t *p_chk ) { int i_index; @@ -954,7 +743,7 @@ void _AVI_ChunkFree( input_thread_t *p_input, while( p_child ) { p_next = p_child->common.p_next; - AVI_ChunkFree( p_input, p_child ); + AVI_ChunkFree( s, p_child ); free( p_child ); p_child = p_next; } @@ -963,14 +752,14 @@ void _AVI_ChunkFree( input_thread_t *p_input, if( AVI_Chunk_Function[i_index].AVI_ChunkFree_function ) { #ifdef AVI_DEBUG - msg_Dbg( p_input, "free chunk %4.4s", + msg_Dbg( (vlc_object_t*)s, "free chunk %4.4s", (char*)&p_chk->common.i_chunk_fourcc ); #endif - AVI_Chunk_Function[i_index].AVI_ChunkFree_function( p_input, p_chk); + AVI_Chunk_Function[i_index].AVI_ChunkFree_function( p_chk); } else { - msg_Warn( p_input, "unknown chunk (not unloaded)" ); + msg_Warn( (vlc_object_t*)s, "unknown chunk (not unloaded)" ); } p_chk->common.p_first = NULL; p_chk->common.p_last = NULL; @@ -978,15 +767,18 @@ void _AVI_ChunkFree( input_thread_t *p_input, return; } -int AVI_ChunkReadRoot( input_thread_t *p_input, - avi_chunk_t *p_root, - vlc_bool_t b_seekable ) +static void AVI_ChunkDumpDebug( stream_t *, avi_chunk_t *); + +int AVI_ChunkReadRoot( stream_t *s, avi_chunk_t *p_root ) { avi_chunk_list_t *p_list = (avi_chunk_list_t*)p_root; avi_chunk_t *p_chk; + vlc_bool_t b_seekable; + + stream_Control( s, STREAM_CAN_FASTSEEK, &b_seekable ); p_list->i_chunk_pos = 0; - p_list->i_chunk_size = p_input->stream.p_selected_area->i_size; + p_list->i_chunk_size = stream_Size( s ); p_list->i_chunk_fourcc = AVIFOURCC_LIST; p_list->p_father = NULL; p_list->p_next = NULL; @@ -1009,8 +801,8 @@ int AVI_ChunkReadRoot( input_thread_t *p_input, } p_root->common.p_last = p_chk; - if( AVI_ChunkRead( p_input, p_chk, p_root, b_seekable ) || - ( AVI_TellAbsolute( p_input ) >= + if( AVI_ChunkRead( s, p_chk, p_root ) || + ( stream_Tell( s ) >= (off_t)p_chk->common.p_father->common.i_chunk_pos + (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) ) { @@ -1022,15 +814,16 @@ int AVI_ChunkReadRoot( input_thread_t *p_input, { break; } - } + } + AVI_ChunkDumpDebug( s, p_root ); return VLC_SUCCESS; } -void AVI_ChunkFreeRoot( input_thread_t *p_input, +void AVI_ChunkFreeRoot( stream_t *s, avi_chunk_t *p_chk ) { - AVI_ChunkFree( p_input, p_chk ); + AVI_ChunkFree( s, p_chk ); } @@ -1049,7 +842,7 @@ int _AVI_ChunkCount( avi_chunk_t *p_chk, vlc_fourcc_t i_fourcc ) while( p_child ) { if( p_child->common.i_chunk_fourcc == i_fourcc || - ( p_child->common.i_chunk_fourcc == AVIFOURCC_LIST && + ( p_child->common.i_chunk_fourcc == AVIFOURCC_LIST && p_child->list.i_type == i_fourcc ) ) { i_count++; @@ -1059,8 +852,8 @@ int _AVI_ChunkCount( avi_chunk_t *p_chk, vlc_fourcc_t i_fourcc ) return i_count; } -avi_chunk_t *_AVI_ChunkFind( avi_chunk_t *p_chk, - vlc_fourcc_t i_fourcc, int i_number ) +void *_AVI_ChunkFind( avi_chunk_t *p_chk, + vlc_fourcc_t i_fourcc, int i_number ) { avi_chunk_t *p_child; if( !p_chk ) @@ -1072,7 +865,7 @@ avi_chunk_t *_AVI_ChunkFind( avi_chunk_t *p_chk, while( p_child ) { if( p_child->common.i_chunk_fourcc == i_fourcc || - ( p_child->common.i_chunk_fourcc == AVIFOURCC_LIST && + ( p_child->common.i_chunk_fourcc == AVIFOURCC_LIST && p_child->list.i_type == i_fourcc ) ) { if( i_number == 0 ) @@ -1088,13 +881,13 @@ avi_chunk_t *_AVI_ChunkFind( avi_chunk_t *p_chk, return NULL; } -static void AVI_ChunkDumpDebug_level( input_thread_t *p_input, +static void AVI_ChunkDumpDebug_level( vlc_object_t *p_obj, avi_chunk_t *p_chk, int i_level ) { char str[1024]; int i; avi_chunk_t *p_child; - + memset( str, ' ', sizeof( str ) ); for( i = 1; i < i_level; i++ ) { @@ -1103,7 +896,7 @@ static void AVI_ChunkDumpDebug_level( input_thread_t *p_input, if( p_chk->common.i_chunk_fourcc == AVIFOURCC_RIFF|| p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST ) { - sprintf( str + i_level * 5, + sprintf( str + i_level * 5, "%c %4.4s-%4.4s size:"I64Fu" pos:"I64Fu, i_level ? '+' : '*', (char*)&p_chk->common.i_chunk_fourcc, @@ -1113,24 +906,25 @@ static void AVI_ChunkDumpDebug_level( input_thread_t *p_input, } else { - sprintf( str + i_level * 5, + sprintf( str + i_level * 5, "+ %4.4s size:"I64Fu" pos:"I64Fu, (char*)&p_chk->common.i_chunk_fourcc, p_chk->common.i_chunk_size, p_chk->common.i_chunk_pos ); } - msg_Dbg( p_input, "%s", str ); + msg_Dbg( p_obj, "%s", str ); p_child = p_chk->common.p_first; while( p_child ) { - AVI_ChunkDumpDebug_level( p_input, p_child, i_level + 1 ); + AVI_ChunkDumpDebug_level( p_obj, p_child, i_level + 1 ); p_child = p_child->common.p_next; } } -void _AVI_ChunkDumpDebug( input_thread_t *p_input, - avi_chunk_t *p_chk ) + +static void AVI_ChunkDumpDebug( stream_t *s, avi_chunk_t *p_chk ) { - AVI_ChunkDumpDebug_level( p_input, p_chk, 0 ); + AVI_ChunkDumpDebug_level( (vlc_object_t*)s, p_chk, 0 ); } + diff --git a/modules/demux/avi/libavi.h b/modules/demux/avi/libavi.h index f6d3f60bc2..efdc3ee702 100644 --- a/modules/demux/avi/libavi.h +++ b/modules/demux/avi/libavi.h @@ -1,15 +1,15 @@ /***************************************************************************** - * libavi.h : LibAVI library + * libavi.h : LibAVI library ****************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: libavi.h,v 1.10 2003/04/27 13:55:51 fenrir Exp $ + * $Id: libavi.h,v 1.11 2003/08/22 20:31:47 fenrir Exp $ * Authors: Laurent Aimar - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -19,9 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/ - -#include "codecs.h" /* BITMAPINFOHEADER */ - /* flags for use in in AVIFileHdr */ #define AVIF_HASINDEX 0x00000010 /* Index at end of file? */ #define AVIF_MUSTUSEINDEX 0x00000020 @@ -40,135 +37,6 @@ the keyframe flag isn't a true flag but have to be verified */ - /* *** avi stuff *** */ - -#define AVIFOURCC_RIFF VLC_FOURCC('R','I','F','F') -#define AVIFOURCC_LIST VLC_FOURCC('L','I','S','T') -#define AVIFOURCC_JUNK VLC_FOURCC('J','U','N','K') -#define AVIFOURCC_AVI VLC_FOURCC('A','V','I',' ') -#define AVIFOURCC_AVIX VLC_FOURCC('A','V','I','X') -#define AVIFOURCC_WAVE VLC_FOURCC('W','A','V','E') -#define AVIFOURCC_INFO VLC_FOURCC('I','N','F','O') - -#define AVIFOURCC_avih VLC_FOURCC('a','v','i','h') -#define AVIFOURCC_hdrl VLC_FOURCC('h','d','r','l') -#define AVIFOURCC_movi VLC_FOURCC('m','o','v','i') -#define AVIFOURCC_idx1 VLC_FOURCC('i','d','x','1') - -#define AVIFOURCC_strl VLC_FOURCC('s','t','r','l') -#define AVIFOURCC_strh VLC_FOURCC('s','t','r','h') -#define AVIFOURCC_strf VLC_FOURCC('s','t','r','f') -#define AVIFOURCC_strd VLC_FOURCC('s','t','r','d') -#define AVIFOURCC_strn VLC_FOURCC('s','t','r','n') -#define AVIFOURCC_indx VLC_FOURCC('i','n','d','x') - -#define AVIFOURCC_rec VLC_FOURCC('r','e','c',' ') -#define AVIFOURCC_auds VLC_FOURCC('a','u','d','s') -#define AVIFOURCC_vids VLC_FOURCC('v','i','d','s') - -#define AVIFOURCC_IARL VLC_FOURCC('I','A','R','L') -#define AVIFOURCC_IART VLC_FOURCC('I','A','R','T') -#define AVIFOURCC_ICMS VLC_FOURCC('I','C','M','S') -#define AVIFOURCC_ICMT VLC_FOURCC('I','C','M','T') -#define AVIFOURCC_ICOP VLC_FOURCC('I','C','O','P') -#define AVIFOURCC_ICRD VLC_FOURCC('I','C','R','D') -#define AVIFOURCC_ICRP VLC_FOURCC('I','C','R','P') -#define AVIFOURCC_IDIM VLC_FOURCC('I','D','I','M') -#define AVIFOURCC_IDPI VLC_FOURCC('I','D','P','I') -#define AVIFOURCC_IENG VLC_FOURCC('I','E','N','G') -#define AVIFOURCC_IGNR VLC_FOURCC('I','G','N','R') -#define AVIFOURCC_IKEY VLC_FOURCC('I','K','E','Y') -#define AVIFOURCC_ILGT VLC_FOURCC('I','L','G','T') -#define AVIFOURCC_IMED VLC_FOURCC('I','M','E','D') -#define AVIFOURCC_INAM VLC_FOURCC('I','N','A','M') -#define AVIFOURCC_IPLT VLC_FOURCC('I','P','L','T') -#define AVIFOURCC_IPRD VLC_FOURCC('I','P','R','D') -#define AVIFOURCC_ISBJ VLC_FOURCC('I','S','B','J') -#define AVIFOURCC_ISFT VLC_FOURCC('I','S','F','T') -#define AVIFOURCC_ISHP VLC_FOURCC('I','S','H','P') -#define AVIFOURCC_ISRC VLC_FOURCC('I','S','R','C') -#define AVIFOURCC_ISRF VLC_FOURCC('I','S','R','F') -#define AVIFOURCC_ITCH VLC_FOURCC('I','T','C','H') -#define AVIFOURCC_ISMP VLC_FOURCC('I','S','M','P') -#define AVIFOURCC_IDIT VLC_FOURCC('I','D','I','T') - - -#define AVITWOCC_wb VLC_TWOCC('w','b') -#define AVITWOCC_db VLC_TWOCC('d','b') -#define AVITWOCC_dc VLC_TWOCC('d','c') -#define AVITWOCC_pc VLC_TWOCC('p','c') - /* *** codex stuff *** */ - - /* MPEG4 video */ -#define FOURCC_DIVX VLC_FOURCC('D','I','V','X') -#define FOURCC_divx VLC_FOURCC('d','i','v','x') -#define FOURCC_DIV1 VLC_FOURCC('D','I','V','1') -#define FOURCC_div1 VLC_FOURCC('d','i','v','1') -#define FOURCC_MP4S VLC_FOURCC('M','P','4','S') -#define FOURCC_mp4s VLC_FOURCC('m','p','4','s') -#define FOURCC_M4S2 VLC_FOURCC('M','4','S','2') -#define FOURCC_m4s2 VLC_FOURCC('m','4','s','2') -#define FOURCC_xvid VLC_FOURCC('x','v','i','d') -#define FOURCC_XVID VLC_FOURCC('X','V','I','D') -#define FOURCC_XviD VLC_FOURCC('X','v','i','D') -#define FOURCC_DX50 VLC_FOURCC('D','X','5','0') -#define FOURCC_mp4v VLC_FOURCC('m','p','4','v') -#define FOURCC_4 VLC_FOURCC( 4, 0, 0, 0 ) - - /* MSMPEG4 v2 */ -#define FOURCC_MPG4 VLC_FOURCC('M','P','G','4') -#define FOURCC_mpg4 VLC_FOURCC('m','p','g','4') -#define FOURCC_DIV2 VLC_FOURCC('D','I','V','2') -#define FOURCC_div2 VLC_FOURCC('d','i','v','2') -#define FOURCC_MP42 VLC_FOURCC('M','P','4','2') -#define FOURCC_mp42 VLC_FOURCC('m','p','4','2') - - /* MSMPEG4 v3 / M$ mpeg4 v3 */ -#define FOURCC_MPG3 VLC_FOURCC('M','P','G','3') -#define FOURCC_mpg3 VLC_FOURCC('m','p','g','3') -#define FOURCC_div3 VLC_FOURCC('d','i','v','3') -#define FOURCC_MP43 VLC_FOURCC('M','P','4','3') -#define FOURCC_mp43 VLC_FOURCC('m','p','4','3') - - /* DivX 3.20 */ -#define FOURCC_DIV3 VLC_FOURCC('D','I','V','3') -#define FOURCC_DIV4 VLC_FOURCC('D','I','V','4') -#define FOURCC_div4 VLC_FOURCC('d','i','v','4') -#define FOURCC_DIV5 VLC_FOURCC('D','I','V','5') -#define FOURCC_div5 VLC_FOURCC('d','i','v','5') -#define FOURCC_DIV6 VLC_FOURCC('D','I','V','6') -#define FOURCC_div6 VLC_FOURCC('d','i','v','6') - - /* AngelPotion stuff */ -#define FOURCC_AP41 VLC_FOURCC('A','P','4','1') - - /* 3IVX */ -#define FOURCC_3IV1 VLC_FOURCC('3','I','V','1') -#define FOURCC_3iv1 VLC_FOURCC('2','i','v','1') -#define FOURCC_3IV2 VLC_FOURCC('3','I','V','2') -#define FOURCC_3iv2 VLC_FOURCC('3','i','v','2') -#define FOURCC_3IVD VLC_FOURCC('3','I','V','D') -#define FOURCC_3ivd VLC_FOURCC('3','i','v','d') -#define FOURCC_3VID VLC_FOURCC('3','V','I','D') -#define FOURCC_3vid VLC_FOURCC('3','v','i','d') - - /* H263 and H263i */ -#define FOURCC_H263 VLC_FOURCC('H','2','6','3') -#define FOURCC_h263 VLC_FOURCC('h','2','6','3') -#define FOURCC_U263 VLC_FOURCC('U','2','6','3') -#define FOURCC_I263 VLC_FOURCC('I','2','6','3') -#define FOURCC_i263 VLC_FOURCC('i','2','6','3') - -/* Sound formats */ -#define WAVE_FORMAT_UNKNOWN 0x0000 -#define WAVE_FORMAT_PCM 0x0001 -#define WAVE_FORMAT_MPEG 0x0050 -#define WAVE_FORMAT_MPEGLAYER3 0x0055 -#define WAVE_FORMAT_A52 0x2000 -#define WAVE_FORMAT_WMA1 0x0160 -#define WAVE_FORMAT_WMA2 0x0161 - - #define AVI_CHUNK_COMMON \ vlc_fourcc_t i_chunk_fourcc; \ uint64_t i_chunk_size; \ @@ -341,52 +209,23 @@ typedef union avi_chunk_u avi_chunk_STRING_t strz; } avi_chunk_t; -/**************************************************************************** - * AVI_TestFile : test file header to see if it's an avi file - ****************************************************************************/ -int AVI_TestFile( input_thread_t *p_input ); - /**************************************************************************** * Stream(input) access functions ****************************************************************************/ -off_t AVI_TellAbsolute( input_thread_t *p_input ); -int AVI_SeekAbsolute( input_thread_t *p_input, off_t i_pos); -int AVI_ReadData( input_thread_t *p_input, uint8_t *p_buff, int i_size ); -int AVI_SkipBytes( input_thread_t *p_input, int64_t i_count ); - -int _AVI_ChunkRead( input_thread_t *p_input, +int _AVI_ChunkRead( stream_t *, avi_chunk_t *p_chk, - avi_chunk_t *p_father, - vlc_bool_t b_seekable ); -void _AVI_ChunkFree( input_thread_t *p_input, - avi_chunk_t *p_chk ); -int _AVI_ChunkGoto( input_thread_t *p_input, - avi_chunk_t *p_chk ); -void _AVI_ChunkDumpDebug( input_thread_t *p_input, - avi_chunk_t *p_chk ); + avi_chunk_t *p_father ); int _AVI_ChunkCount( avi_chunk_t *, vlc_fourcc_t ); -avi_chunk_t *_AVI_ChunkFind( avi_chunk_t *, vlc_fourcc_t, int ); - -int AVI_ChunkReadRoot( input_thread_t *p_input, - avi_chunk_t *p_root, - vlc_bool_t b_seekable ); -void AVI_ChunkFreeRoot( input_thread_t *p_input, - avi_chunk_t *p_chk ); -#define AVI_ChunkRead( p_input, p_chk, p_father, b_seekable ) \ - _AVI_ChunkRead( p_input, \ - (avi_chunk_t*)p_chk, \ - (avi_chunk_t*)p_father, \ - b_seekable ) -#define AVI_ChunkFree( p_input, p_chk ) \ - _AVI_ChunkFree( p_input, (avi_chunk_t*)p_chk ) - -#define AVI_ChunkGoto( p_input, p_chk ) \ - _AVI_ChunkGoto( p_input, (avi_chunk_t*)p_chk ) - -#define AVI_ChunkDumpDebug( p_input, p_chk ) \ - _AVI_ChunkDumpDebug( p_input, (avi_chunk_t*)p_chk ) +void *_AVI_ChunkFind ( avi_chunk_t *, vlc_fourcc_t, int ); + +int AVI_ChunkReadRoot( stream_t *, avi_chunk_t *p_root ); +void AVI_ChunkFreeRoot( stream_t *, avi_chunk_t *p_chk ); +#define AVI_ChunkRead( s, p_chk, p_father ) \ + _AVI_ChunkRead( s, \ + (avi_chunk_t*)p_chk, \ + (avi_chunk_t*)p_father ) #define AVI_ChunkCount( p_chk, i_fourcc ) \ _AVI_ChunkCount( (avi_chunk_t*)p_chk, i_fourcc ) @@ -394,4 +233,123 @@ void AVI_ChunkFreeRoot( input_thread_t *p_input, _AVI_ChunkFind( (avi_chunk_t*)p_chk, i_fourcc, i_number ) + /* *** avi stuff *** */ + +#define AVIFOURCC_RIFF VLC_FOURCC('R','I','F','F') +#define AVIFOURCC_LIST VLC_FOURCC('L','I','S','T') +#define AVIFOURCC_JUNK VLC_FOURCC('J','U','N','K') +#define AVIFOURCC_AVI VLC_FOURCC('A','V','I',' ') +#define AVIFOURCC_AVIX VLC_FOURCC('A','V','I','X') +#define AVIFOURCC_WAVE VLC_FOURCC('W','A','V','E') +#define AVIFOURCC_INFO VLC_FOURCC('I','N','F','O') + +#define AVIFOURCC_avih VLC_FOURCC('a','v','i','h') +#define AVIFOURCC_hdrl VLC_FOURCC('h','d','r','l') +#define AVIFOURCC_movi VLC_FOURCC('m','o','v','i') +#define AVIFOURCC_idx1 VLC_FOURCC('i','d','x','1') + +#define AVIFOURCC_strl VLC_FOURCC('s','t','r','l') +#define AVIFOURCC_strh VLC_FOURCC('s','t','r','h') +#define AVIFOURCC_strf VLC_FOURCC('s','t','r','f') +#define AVIFOURCC_strd VLC_FOURCC('s','t','r','d') +#define AVIFOURCC_strn VLC_FOURCC('s','t','r','n') +#define AVIFOURCC_indx VLC_FOURCC('i','n','d','x') + +#define AVIFOURCC_rec VLC_FOURCC('r','e','c',' ') +#define AVIFOURCC_auds VLC_FOURCC('a','u','d','s') +#define AVIFOURCC_vids VLC_FOURCC('v','i','d','s') + +#define AVIFOURCC_IARL VLC_FOURCC('I','A','R','L') +#define AVIFOURCC_IART VLC_FOURCC('I','A','R','T') +#define AVIFOURCC_ICMS VLC_FOURCC('I','C','M','S') +#define AVIFOURCC_ICMT VLC_FOURCC('I','C','M','T') +#define AVIFOURCC_ICOP VLC_FOURCC('I','C','O','P') +#define AVIFOURCC_ICRD VLC_FOURCC('I','C','R','D') +#define AVIFOURCC_ICRP VLC_FOURCC('I','C','R','P') +#define AVIFOURCC_IDIM VLC_FOURCC('I','D','I','M') +#define AVIFOURCC_IDPI VLC_FOURCC('I','D','P','I') +#define AVIFOURCC_IENG VLC_FOURCC('I','E','N','G') +#define AVIFOURCC_IGNR VLC_FOURCC('I','G','N','R') +#define AVIFOURCC_IKEY VLC_FOURCC('I','K','E','Y') +#define AVIFOURCC_ILGT VLC_FOURCC('I','L','G','T') +#define AVIFOURCC_IMED VLC_FOURCC('I','M','E','D') +#define AVIFOURCC_INAM VLC_FOURCC('I','N','A','M') +#define AVIFOURCC_IPLT VLC_FOURCC('I','P','L','T') +#define AVIFOURCC_IPRD VLC_FOURCC('I','P','R','D') +#define AVIFOURCC_ISBJ VLC_FOURCC('I','S','B','J') +#define AVIFOURCC_ISFT VLC_FOURCC('I','S','F','T') +#define AVIFOURCC_ISHP VLC_FOURCC('I','S','H','P') +#define AVIFOURCC_ISRC VLC_FOURCC('I','S','R','C') +#define AVIFOURCC_ISRF VLC_FOURCC('I','S','R','F') +#define AVIFOURCC_ITCH VLC_FOURCC('I','T','C','H') +#define AVIFOURCC_ISMP VLC_FOURCC('I','S','M','P') +#define AVIFOURCC_IDIT VLC_FOURCC('I','D','I','T') + + +#define AVITWOCC_wb VLC_TWOCC('w','b') +#define AVITWOCC_db VLC_TWOCC('d','b') +#define AVITWOCC_dc VLC_TWOCC('d','c') +#define AVITWOCC_pc VLC_TWOCC('p','c') + /* *** codex stuff *** */ + + /* MPEG4 video */ +#define FOURCC_DIVX VLC_FOURCC('D','I','V','X') +#define FOURCC_divx VLC_FOURCC('d','i','v','x') +#define FOURCC_DIV1 VLC_FOURCC('D','I','V','1') +#define FOURCC_div1 VLC_FOURCC('d','i','v','1') +#define FOURCC_MP4S VLC_FOURCC('M','P','4','S') +#define FOURCC_mp4s VLC_FOURCC('m','p','4','s') +#define FOURCC_M4S2 VLC_FOURCC('M','4','S','2') +#define FOURCC_m4s2 VLC_FOURCC('m','4','s','2') +#define FOURCC_xvid VLC_FOURCC('x','v','i','d') +#define FOURCC_XVID VLC_FOURCC('X','V','I','D') +#define FOURCC_XviD VLC_FOURCC('X','v','i','D') +#define FOURCC_DX50 VLC_FOURCC('D','X','5','0') +#define FOURCC_mp4v VLC_FOURCC('m','p','4','v') +#define FOURCC_4 VLC_FOURCC( 4, 0, 0, 0 ) + + /* MSMPEG4 v2 */ +#define FOURCC_MPG4 VLC_FOURCC('M','P','G','4') +#define FOURCC_mpg4 VLC_FOURCC('m','p','g','4') +#define FOURCC_DIV2 VLC_FOURCC('D','I','V','2') +#define FOURCC_div2 VLC_FOURCC('d','i','v','2') +#define FOURCC_MP42 VLC_FOURCC('M','P','4','2') +#define FOURCC_mp42 VLC_FOURCC('m','p','4','2') + + /* MSMPEG4 v3 / M$ mpeg4 v3 */ +#define FOURCC_MPG3 VLC_FOURCC('M','P','G','3') +#define FOURCC_mpg3 VLC_FOURCC('m','p','g','3') +#define FOURCC_div3 VLC_FOURCC('d','i','v','3') +#define FOURCC_MP43 VLC_FOURCC('M','P','4','3') +#define FOURCC_mp43 VLC_FOURCC('m','p','4','3') + + /* DivX 3.20 */ +#define FOURCC_DIV3 VLC_FOURCC('D','I','V','3') +#define FOURCC_DIV4 VLC_FOURCC('D','I','V','4') +#define FOURCC_div4 VLC_FOURCC('d','i','v','4') +#define FOURCC_DIV5 VLC_FOURCC('D','I','V','5') +#define FOURCC_div5 VLC_FOURCC('d','i','v','5') +#define FOURCC_DIV6 VLC_FOURCC('D','I','V','6') +#define FOURCC_div6 VLC_FOURCC('d','i','v','6') + + /* AngelPotion stuff */ +#define FOURCC_AP41 VLC_FOURCC('A','P','4','1') + + /* 3IVX */ +#define FOURCC_3IV1 VLC_FOURCC('3','I','V','1') +#define FOURCC_3iv1 VLC_FOURCC('2','i','v','1') +#define FOURCC_3IV2 VLC_FOURCC('3','I','V','2') +#define FOURCC_3iv2 VLC_FOURCC('3','i','v','2') +#define FOURCC_3IVD VLC_FOURCC('3','I','V','D') +#define FOURCC_3ivd VLC_FOURCC('3','i','v','d') +#define FOURCC_3VID VLC_FOURCC('3','V','I','D') +#define FOURCC_3vid VLC_FOURCC('3','v','i','d') + + /* H263 and H263i */ +#define FOURCC_H263 VLC_FOURCC('H','2','6','3') +#define FOURCC_h263 VLC_FOURCC('h','2','6','3') +#define FOURCC_U263 VLC_FOURCC('U','2','6','3') +#define FOURCC_I263 VLC_FOURCC('I','2','6','3') +#define FOURCC_i263 VLC_FOURCC('i','2','6','3') + -- 2.20.1