* avi.c : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: avi.c,v 1.7 2002/04/27 22:54:00 fenrir Exp $
+ * $Id: avi.c,v 1.34 2002/08/01 17:55:31 fenrir Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
#include <errno.h>
#include <sys/types.h>
-#include <videolan/vlc.h>
-
-#include "stream_control.h"
-#include "input_ext-intf.h"
-#include "input_ext-dec.h"
-#include "input_ext-plugins.h"
+#include <vlc/vlc.h>
+#include <vlc/input.h>
#include "video.h"
-/*****************************************************************************
- * Constants
- *****************************************************************************/
+#include "libioRIFF.h"
+#include "avi.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
-static void input_getfunctions( function_list_t * p_function_list );
-static int AVIDemux ( struct input_thread_s * );
-static int AVIInit ( struct input_thread_s * );
-static void AVIEnd ( struct input_thread_s * );
+static int AVIInit ( vlc_object_t * );
+static void __AVIEnd ( vlc_object_t * );
+static int AVIDemux ( input_thread_t * );
+
+#define AVIEnd(a) __AVIEnd(VLC_OBJECT(a))
/*****************************************************************************
- * Build configuration tree.
+ * Module descriptor
*****************************************************************************/
-MODULE_CONFIG_START
-MODULE_CONFIG_STOP
-
-MODULE_INIT_START
- SET_DESCRIPTION( "RIFF-AVI Stream input" )
- ADD_CAPABILITY( DEMUX, 150 )
- ADD_SHORTCUT( "avi" )
-MODULE_INIT_STOP
-
-MODULE_ACTIVATE_START
- input_getfunctions( &p_module->p_functions->demux );
-MODULE_ACTIVATE_STOP
-
-MODULE_DEACTIVATE_START
-MODULE_DEACTIVATE_STOP
+vlc_module_begin();
+ set_description( "RIFF-AVI demuxer" );
+ set_capability( "demux", 150 );
+ set_callbacks( AVIInit, __AVIEnd );
+vlc_module_end();
/*****************************************************************************
- * Definition of structures and libraries for this plugins
+ * Some usefull functions to manipulate memory
*****************************************************************************/
-#include "libLE.c"
-#include "libioRIFF.c"
-#include "avi.h"
+static u16 GetWLE( byte_t *p_buff )
+{
+ u16 i;
+ i = (*p_buff) + ( *(p_buff + 1) <<8 );
+ return ( i );
+}
+static u32 GetDWLE( byte_t *p_buff )
+{
+ u32 i;
+ i = (*p_buff) + ( *(p_buff + 1) <<8 ) +
+ ( *(p_buff + 2) <<16 ) + ( *(p_buff + 3) <<24 );
+ return ( i );
+}
+static u32 GetDWBE( byte_t *p_buff )
+{
+ u32 i;
+ i = ((*p_buff)<<24) + ( *(p_buff + 1) <<16 ) +
+ ( *(p_buff + 2) <<8 ) + ( *(p_buff + 3) );
+ return ( i );
+}
+static inline off_t __EVEN( off_t i )
+{
+ return( (i & 1) ? i+1 : i );
+}
+
/*****************************************************************************
- * Functions exported as capabilities. They are declared as static so that
- * we don't pollute the namespace too much.
+ * Functions for parsing the headers in an avi file
*****************************************************************************/
-static void input_getfunctions( function_list_t * p_function_list )
+static void AVI_Parse_avih( MainAVIHeader_t *p_avih, byte_t *p_buff )
+{
+ p_avih->i_microsecperframe = GetDWLE( p_buff );
+ p_avih->i_maxbytespersec = GetDWLE( p_buff + 4);
+ p_avih->i_reserved1 = GetDWLE( p_buff + 8);
+ p_avih->i_flags = GetDWLE( p_buff + 12);
+ p_avih->i_totalframes = GetDWLE( p_buff + 16);
+ p_avih->i_initialframes = GetDWLE( p_buff + 20);
+ p_avih->i_streams = GetDWLE( p_buff + 24);
+ p_avih->i_suggestedbuffersize = GetDWLE( p_buff + 28);
+ p_avih->i_width = GetDWLE( p_buff + 32 );
+ p_avih->i_height = GetDWLE( p_buff + 36 );
+ p_avih->i_scale = GetDWLE( p_buff + 40 );
+ p_avih->i_rate = GetDWLE( p_buff + 44 );
+ p_avih->i_start = GetDWLE( p_buff + 48);
+ p_avih->i_length = GetDWLE( p_buff + 52);
+}
+static void AVI_Parse_Header( AVIStreamHeader_t *p_strh, byte_t *p_buff )
+{
+ p_strh->i_type = GetDWLE( p_buff );
+ p_strh->i_handler = GetDWLE( p_buff + 4 );
+ p_strh->i_flags = GetDWLE( p_buff + 8 );
+ p_strh->i_reserved1 = GetDWLE( p_buff + 12);
+ p_strh->i_initialframes = GetDWLE( p_buff + 16);
+ p_strh->i_scale = GetDWLE( p_buff + 20);
+ p_strh->i_rate = GetDWLE( p_buff + 24);
+ p_strh->i_start = GetDWLE( p_buff + 28);
+ p_strh->i_length = GetDWLE( p_buff + 32);
+ p_strh->i_suggestedbuffersize = GetDWLE( p_buff + 36);
+ p_strh->i_quality = GetDWLE( p_buff + 40);
+ p_strh->i_samplesize = GetDWLE( p_buff + 44);
+}
+static void AVI_Parse_BitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
+{
+ h->i_size = GetDWLE( p_data );
+ h->i_width = GetDWLE( p_data + 4 );
+ h->i_height = GetDWLE( p_data + 8 );
+ h->i_planes = GetWLE( p_data + 12 );
+ h->i_bitcount = GetWLE( p_data + 14 );
+ h->i_compression = GetDWLE( p_data + 16 );
+ h->i_sizeimage = GetDWLE( p_data + 20 );
+ h->i_xpelspermeter = GetDWLE( p_data + 24 );
+ h->i_ypelspermeter = GetDWLE( p_data + 28 );
+ h->i_clrused = GetDWLE( p_data + 32 );
+ h->i_clrimportant = GetDWLE( p_data + 36 );
+}
+static void AVI_Parse_WaveFormatEx( waveformatex_t *h, byte_t *p_data )
{
-#define input p_function_list->functions.demux
- input.pf_init = AVIInit;
- input.pf_end = AVIEnd;
- input.pf_demux = AVIDemux;
- input.pf_rewind = NULL;
-#undef input
+ h->i_formattag = GetWLE( p_data );
+ h->i_channels = GetWLE( p_data + 2 );
+ h->i_samplespersec = GetDWLE( p_data + 4 );
+ h->i_avgbytespersec= GetDWLE( p_data + 8 );
+ h->i_blockalign = GetWLE( p_data + 12 );
+ h->i_bitspersample = GetWLE( p_data + 14 );
+ h->i_size = GetWLE( p_data + 16 );
}
-/********************************************************************/
+static inline int AVI_GetESTypeFromTwoCC( u16 i_type )
+{
+ switch( i_type )
+ {
+ case( TWOCC_wb ):
+ return( AUDIO_ES );
+ case( TWOCC_dc ):
+ case( TWOCC_db ):
+ return( VIDEO_ES );
+ default:
+ return( UNKNOWN_ES );
+ }
+}
+static vlc_fourcc_t AVI_AudioGetType( u32 i_type )
+{
+ switch( i_type )
+ {
+/* case( WAVE_FORMAT_PCM ):
+ return VLC_FOURCC('l','p','c','m'); */
+ case( WAVE_FORMAT_AC3 ):
+ return VLC_FOURCC('a','5','2',' ');
+ case( WAVE_FORMAT_MPEG):
+ case( WAVE_FORMAT_MPEGLAYER3):
+ return VLC_FOURCC('m','p','g','a'); /* for mpeg2 layer 1 2 ou 3 */
+ default:
+ return 0;
+ }
+}
-static void __AVIFreeDemuxData( input_thread_t *p_input )
+/* Test if it seems that it's a key frame */
+static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, u8 *p_byte )
{
- int i;
- demux_data_avi_file_t *p_avi_demux;
- p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data ;
-
- if( p_avi_demux->p_riff != NULL )
- RIFF_DeleteChunk( p_input, p_avi_demux->p_riff );
- if( p_avi_demux->p_hdrl != NULL )
- RIFF_DeleteChunk( p_input, p_avi_demux->p_hdrl );
- if( p_avi_demux->p_movi != NULL )
- RIFF_DeleteChunk( p_input, p_avi_demux->p_movi );
- if( p_avi_demux->p_idx1 != NULL )
- RIFF_DeleteChunk( p_input, p_avi_demux->p_idx1 );
- if( p_avi_demux->pp_info != NULL )
+ switch( i_fourcc )
{
- for( i = 0; i < p_avi_demux->i_streams; i++ )
- {
- if( p_avi_demux->pp_info[i] != NULL )
+ case FOURCC_DIV1:
+ case FOURCC_div1:
+ case FOURCC_MPG4:
+ case FOURCC_mpg4:
+ if( GetDWBE( p_byte ) != 0x00000100 )
+ /* startcode perhaps swapped, I haven't tested */
{
-#define p_info p_avi_demux->pp_info[i]
-
- if( p_info->p_index != NULL )
- {
- free( p_info->p_index );
- }
- free( p_info );
-#undef p_info
+ /* it's seems it's not an msmpegv1 stream
+ but perhaps I'm wrong so return yes */
+ return( AVIIF_KEYFRAME );
}
- }
- free( p_avi_demux->pp_info );
+ else
+ {
+ return( (*(p_byte+4))&0x06 ? 0 : AVIIF_KEYFRAME);
+ }
+ case FOURCC_DIV2:
+ case FOURCC_div2:
+ case FOURCC_MP42:
+ case FOURCC_mp42:
+ case FOURCC_MPG3:
+ case FOURCC_mpg3:
+ 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:
+ return( (*p_byte)&0xC0 ? 0 : AVIIF_KEYFRAME );
+ 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:
+ if( GetDWBE( p_byte ) != 0x000001b6 )
+ {
+ /* not true , need to find the first VOP header
+ but, I'm lazy */
+ return( AVIIF_KEYFRAME );
+ }
+ else
+ {
+ return( (*(p_byte+4))&0xC0 ? 0 : AVIIF_KEYFRAME );
+ }
+ default:
+ /* I can't do it, so said yes */
+ return( AVIIF_KEYFRAME );
}
-}
-static void __AVI_Parse_avih( MainAVIHeader_t *p_avih, byte_t *p_buff )
+}
+/*****************************************************************************
+ * Data and functions to manipulate pes buffer
+ *****************************************************************************/
+#define BUFFER_MAXTOTALSIZE 512*1024 /* 1/2 Mo */
+#define BUFFER_MAXSPESSIZE 1024*200
+static int AVI_PESBuffer_IsFull( AVIStreamInfo_t *p_info )
{
- p_avih->i_microsecperframe = __GetDoubleWordLittleEndianFromBuff( p_buff );
- p_avih->i_maxbytespersec = __GetDoubleWordLittleEndianFromBuff( p_buff + 4);
- p_avih->i_reserved1 = __GetDoubleWordLittleEndianFromBuff( p_buff + 8);
- p_avih->i_flags = __GetDoubleWordLittleEndianFromBuff( p_buff + 12);
- p_avih->i_totalframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 16);
- p_avih->i_initialframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 20);
- p_avih->i_streams = __GetDoubleWordLittleEndianFromBuff( p_buff + 24);
- p_avih->i_suggestedbuffersize =
- __GetDoubleWordLittleEndianFromBuff( p_buff + 28);
- p_avih->i_width = __GetDoubleWordLittleEndianFromBuff( p_buff + 32 );
- p_avih->i_height = __GetDoubleWordLittleEndianFromBuff( p_buff + 36 );
- p_avih->i_scale = __GetDoubleWordLittleEndianFromBuff( p_buff + 40 );
- p_avih->i_rate = __GetDoubleWordLittleEndianFromBuff( p_buff + 44 );
- p_avih->i_start = __GetDoubleWordLittleEndianFromBuff( p_buff + 48);
- p_avih->i_length = __GetDoubleWordLittleEndianFromBuff( p_buff + 52);
+ return( p_info->i_pes_totalsize > BUFFER_MAXTOTALSIZE ? 1 : 0);
}
-
-static void __AVI_Parse_Header( AVIStreamHeader_t *p_strh, byte_t *p_buff )
+static void AVI_PESBuffer_Add( input_buffers_t *p_method_data,
+ AVIStreamInfo_t *p_info,
+ pes_packet_t *p_pes,
+ int i_posc,
+ int i_posb )
{
- p_strh->i_type = __GetDoubleWordLittleEndianFromBuff( p_buff );
- p_strh->i_handler = __GetDoubleWordLittleEndianFromBuff( p_buff + 4 );
- p_strh->i_flags = __GetDoubleWordLittleEndianFromBuff( p_buff + 8 );
- p_strh->i_reserved1 = __GetDoubleWordLittleEndianFromBuff( p_buff + 12);
- p_strh->i_initialframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 16);
- p_strh->i_scale = __GetDoubleWordLittleEndianFromBuff( p_buff + 20);
- p_strh->i_rate = __GetDoubleWordLittleEndianFromBuff( p_buff + 24);
- p_strh->i_start = __GetDoubleWordLittleEndianFromBuff( p_buff + 28);
- p_strh->i_length = __GetDoubleWordLittleEndianFromBuff( p_buff + 32);
- p_strh->i_suggestedbuffersize =
- __GetDoubleWordLittleEndianFromBuff( p_buff + 36);
- p_strh->i_quality = __GetDoubleWordLittleEndianFromBuff( p_buff + 40);
- p_strh->i_samplesize = __GetDoubleWordLittleEndianFromBuff( p_buff + 44);
+ AVIESBuffer_t *p_buffer_pes;
+
+ if( p_info->i_pes_totalsize > BUFFER_MAXTOTALSIZE )
+ {
+ input_DeletePES( p_method_data, p_pes );
+ return;
+ }
+
+ if( !( p_buffer_pes = malloc( sizeof( AVIESBuffer_t ) ) ) )
+ {
+ input_DeletePES( p_method_data, p_pes );
+ return;
+ }
+ p_buffer_pes->p_next = NULL;
+ p_buffer_pes->p_pes = p_pes;
+ p_buffer_pes->i_posc = i_posc;
+ p_buffer_pes->i_posb = i_posb;
+
+ if( p_info->p_pes_last )
+ {
+ p_info->p_pes_last->p_next = p_buffer_pes;
+ }
+ p_info->p_pes_last = p_buffer_pes;
+ if( !p_info->p_pes_first )
+ {
+ p_info->p_pes_first = p_buffer_pes;
+ }
+ p_info->i_pes_count++;
+ p_info->i_pes_totalsize += p_pes->i_pes_size;
}
+static pes_packet_t *AVI_PESBuffer_Get( AVIStreamInfo_t *p_info )
+{
+ AVIESBuffer_t *p_buffer_pes;
+ pes_packet_t *p_pes;
+ if( p_info->p_pes_first )
+ {
+ p_buffer_pes = p_info->p_pes_first;
+ p_info->p_pes_first = p_buffer_pes->p_next;
+ if( !p_info->p_pes_first )
+ {
+ p_info->p_pes_last = NULL;
+ }
+ p_pes = p_buffer_pes->p_pes;
-int avi_ParseBitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
+ free( p_buffer_pes );
+ p_info->i_pes_count--;
+ p_info->i_pes_totalsize -= p_pes->i_pes_size;
+ return( p_pes );
+ }
+ else
+ {
+ return( NULL );
+ }
+}
+static int AVI_PESBuffer_Drop( input_buffers_t *p_method_data,
+ AVIStreamInfo_t *p_info )
{
- h->i_size = __GetDoubleWordLittleEndianFromBuff( p_data );
- h->i_width = __GetDoubleWordLittleEndianFromBuff( p_data + 4 );
- h->i_height = __GetDoubleWordLittleEndianFromBuff( p_data + 8 );
- h->i_planes = __GetWordLittleEndianFromBuff( p_data + 12 );
- h->i_bitcount = __GetWordLittleEndianFromBuff( p_data + 14 );
- h->i_compression = __GetDoubleWordLittleEndianFromBuff( p_data + 16 );
- h->i_sizeimage = __GetDoubleWordLittleEndianFromBuff( p_data + 20 );
- h->i_xpelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 24 );
- h->i_ypelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 28 );
- h->i_clrused = __GetDoubleWordLittleEndianFromBuff( p_data + 32 );
- h->i_clrimportant = __GetDoubleWordLittleEndianFromBuff( p_data + 36 );
- return( 0 );
+ pes_packet_t *p_pes = AVI_PESBuffer_Get( p_info );
+ if( p_pes )
+ {
+ input_DeletePES( p_method_data, p_pes );
+ return( 1 );
+ }
+ else
+ {
+ return( 0 );
+ }
}
-
-int avi_ParseWaveFormatEx( waveformatex_t *h, byte_t *p_data )
+static void AVI_PESBuffer_Flush( input_buffers_t *p_method_data,
+ AVIStreamInfo_t *p_info )
{
- h->i_formattag = __GetWordLittleEndianFromBuff( p_data );
- h->i_channels = __GetWordLittleEndianFromBuff( p_data + 2 );
- h->i_samplespersec = __GetDoubleWordLittleEndianFromBuff( p_data + 4 );
- h->i_avgbytespersec= __GetDoubleWordLittleEndianFromBuff( p_data + 8 );
- h->i_blockalign = __GetWordLittleEndianFromBuff( p_data + 12 );
- h->i_bitspersample = __GetWordLittleEndianFromBuff( p_data + 14 );
- h->i_size = __GetWordLittleEndianFromBuff( p_data + 16 );
- return( 0 );
+ while( p_info->p_pes_first )
+ {
+ AVI_PESBuffer_Drop( p_method_data, p_info );
+ }
}
-static int __AVI_ParseStreamHeader( u32 i_id, int *i_number, u16 *i_type )
+static void AVI_ParseStreamHeader( u32 i_id, int *i_number, int *i_type )
{
- int c1,c2,c3,c4;
+ int c1,c2;
c1 = ( i_id ) & 0xFF;
c2 = ( i_id >> 8 ) & 0xFF;
- c3 = ( i_id >> 16 ) & 0xFF;
- c4 = ( i_id >> 24 ) & 0xFF;
if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' )
{
- return( -1 );
+ *i_number = 100; /* > max stream number */
+ *i_type = 0;
}
- *i_number = (c1 - '0') * 10 + (c2 - '0' );
- *i_type = ( c4 << 8) + c3;
- return( 0 );
-}
+ else
+ {
+ *i_number = (c1 - '0') * 10 + (c2 - '0' );
+ *i_type = ( i_id >> 16 ) & 0xFFFF;
+ }
+}
+
+/* Function to manipulate stream easily */
+static off_t AVI_TellAbsolute( input_thread_t *p_input )
+{
+ off_t i_pos;
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ i_pos= p_input->stream.p_selected_area->i_tell -
+ ( p_input->p_last_data - p_input->p_current_data );
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ return( i_pos );
+}
+
+static int AVI_SeekAbsolute( input_thread_t *p_input,
+ off_t i_pos)
+{
+ off_t i_filepos;
+ /* FIXME add support for not seekable stream */
+
+ i_filepos = AVI_TellAbsolute( p_input );
+ if( i_pos != i_filepos )
+ {
+// msg_Err( p_input, "Seek --> delta %d", i_pos - i_filepos );
+ p_input->pf_seek( p_input, i_pos );
+ input_AccessReinit( p_input );
+ }
+ return( 1 );
+}
+
static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
AVIIndexEntry_t *p_index)
p_tmp = realloc( (void*)p_info->p_index,
p_info->i_idxmax *
sizeof( AVIIndexEntry_t ) );
- if( p_tmp == NULL )
+ if( !p_tmp )
{
p_info->i_idxmax -= 16384;
return;
/* calculate cumulate length */
if( p_info->i_idxnb > 0 )
{
- p_index->i_lengthtotal = p_index->i_length +
- p_info->p_index[p_info->i_idxnb-1].i_lengthtotal;
+ 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
{
static void __AVI_GetIndex( input_thread_t *p_input )
{
- demux_data_avi_file_t *p_avi_demux;
AVIIndexEntry_t index;
byte_t *p_buff;
riffchunk_t *p_idx1;
int i_read;
int i;
int i_number;
- u16 i_type;
+ int i_type;
int i_totalentry = 0;
-
- p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data ;
+ demux_data_avi_file_t *p_avi_demux =
+ (demux_data_avi_file_t*)p_input->p_demux_data ;
if( RIFF_FindAndGotoDataChunk( p_input,
p_avi_demux->p_riff,
&p_idx1,
FOURCC_idx1)!=0 )
{
- intf_WarnMsg( 1, "input init: cannot find index" );
+ msg_Warn( p_input, "cannot find index" );
RIFF_GoToChunk( p_input, p_avi_demux->p_hdrl );
return;
}
p_avi_demux->p_idx1 = p_idx1;
- intf_WarnMsg( 1, "input init: loading index" );
+ msg_Dbg( p_input, "loading index" );
for(;;)
{
- if( ((i_read = input_Peek( p_input, &p_buff, 16*1024 )) < 16 )
+ i_read = __MIN( 16*1024, p_idx1->i_size - i_totalentry *16);
+ if( ((i_read = input_Peek( p_input, &p_buff, i_read )) < 16 )
||( i_totalentry *16 >= p_idx1->i_size ) )
{
- intf_WarnMsg( 1,"input info: read %d idx chunk", i_totalentry );
+ msg_Dbg( p_input, "read %d idx entries", i_totalentry );
return;
}
i_read /= 16 ;
- /* TODO try to verify if we are beyond end of p_idx1 */
for( i = 0; i < i_read; i++ )
{
byte_t *p_peek = p_buff + i * 16;
i_totalentry++;
- index.i_id = __GetDoubleWordLittleEndianFromBuff( p_peek );
- index.i_flags = __GetDoubleWordLittleEndianFromBuff( p_peek+4);
- index.i_offset = __GetDoubleWordLittleEndianFromBuff( p_peek+8);
- index.i_length = __GetDoubleWordLittleEndianFromBuff(p_peek+12);
+ index.i_id = GetDWLE( p_peek );
+ index.i_flags = GetDWLE( p_peek+4)&(~AVIIF_FIXKEYFRAME);
+ index.i_pos = GetDWLE( p_peek+8);
+ index.i_length = GetDWLE(p_peek+12);
+ AVI_ParseStreamHeader( index.i_id, &i_number, &i_type );
- if( (__AVI_ParseStreamHeader( index.i_id, &i_number, &i_type ) != 0)
- ||(i_number > p_avi_demux->i_streams))
+ if( ( i_number < p_avi_demux->i_streams )
+ &&(p_avi_demux->pp_info[i_number]->i_cat ==
+ AVI_GetESTypeFromTwoCC( i_type )))
{
- continue;
+ __AVI_AddEntryIndex( p_avi_demux->pp_info[i_number],
+ &index );
}
- __AVI_AddEntryIndex( p_avi_demux->pp_info[i_number],
- &index );
}
__RIFF_SkipBytes( p_input, 16 * i_read );
}
}
-static int __AVI_SeekToChunk( input_thread_t *p_input, AVIStreamInfo_t *p_info )
-{
- demux_data_avi_file_t *p_avi_demux;
- p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
-
- if( (p_info->p_index != NULL)&&(p_info->i_idxpos < p_info->i_idxnb) )
- {
- /* perfect */
- off_t i_pos;
- i_pos = (off_t)p_info->p_index[p_info->i_idxpos].i_offset +
- p_info->i_idxoffset;
-
- p_input->pf_seek( p_input, i_pos );
- input_AccessReinit( p_input );
- return( 0 );
- }
- /* no index can't arrive but ...*/
- intf_WarnMsg( 1, "input error: can't seek");
- return( -1 );
-}
-
/* XXX call after get p_movi */
-static void __AVI_GetIndexOffset( input_thread_t *p_input )
+static void __AVI_UpdateIndexOffset( input_thread_t *p_input )
{
- riffchunk_t *p_chunk;
- demux_data_avi_file_t *p_avi_demux;
- int i;
+ int i_stream;
+ int b_start = 1;/* if index pos is based on start of file or not (p_movi) */
+ demux_data_avi_file_t *p_avi_demux =
+ (demux_data_avi_file_t*)p_input->p_demux_data;
- p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
- for( i = 0; i < p_avi_demux->i_streams; i++ )
+/* FIXME some work to do :
+ * test in the file if it's true, if not do a RIFF_Find...
+*/
+#define p_info p_avi_demux->pp_info[i_stream]
+ for( i_stream = 0; i_stream < p_avi_demux->i_streams; i_stream++ )
{
-#define p_info p_avi_demux->pp_info[i]
- if( p_info->p_index == NULL )
+ if( ( p_info->p_index )
+ && ( p_info->p_index[0].i_pos < p_avi_demux->p_movi->i_pos + 8 ))
{
- intf_WarnMsg( 1, "input demux: can't find offset for stream %d",i);
- continue;
+ b_start = 0;
+ break;
}
- p_info->i_idxoffset = 0;
- __AVI_SeekToChunk( p_input, p_info );
- p_chunk = RIFF_ReadChunk( p_input );
- if( (p_chunk == NULL)||(p_chunk->i_id != p_info->p_index[0].i_id) )
+ }
+ if( !b_start )
+ {
+ for( i_stream = 0; i_stream < p_avi_demux->i_streams; i_stream++ )
{
- p_info->i_idxoffset = p_avi_demux->p_movi->i_pos + 8;
- __AVI_SeekToChunk( p_input, p_info );
- p_chunk = RIFF_ReadChunk( p_input );
- if( (p_chunk == NULL)||(p_chunk->i_id != p_info->p_index[0].i_id) )
+ int i;
+ if( p_info->p_index )
{
- intf_WarnMsg( 1, "input demux: can't find offset for stream %d",
- i);
- continue; /* TODO: search manually from p_movi */
+ for( i = 0; i < p_info->i_idxnb; i++ )
+ {
+ p_info->p_index[i].i_pos += p_avi_demux->p_movi->i_pos + 8;
+ }
}
}
-#undef p_info
- }
- return;
-}
-
-static int __AVI_AudioGetType( u32 i_type )
-{
- switch( i_type )
- {
-/* case( WAVE_FORMAT_PCM ):
- return( WAVE_AUDIO_ES ); */
- case( WAVE_FORMAT_AC3 ):
- return( AC3_AUDIO_ES );
- case( WAVE_FORMAT_MPEG):
- case( WAVE_FORMAT_MPEGLAYER3):
- return( MPEG2_AUDIO_ES ); /* 2 for mpeg-2 layer 1 2 ou 3 */
- default:
- return( 0 );
}
+#undef p_info
}
-static int __AVI_VideoGetType( u32 i_type )
-{
- switch( i_type )
+/*****************************************************************************
+ * AVIEnd: frees unused data
+ *****************************************************************************/
+static void __AVIEnd ( vlc_object_t * p_this )
+{
+ input_thread_t * p_input = (input_thread_t *)p_this;
+ int i;
+ demux_data_avi_file_t *p_avi_demux;
+ p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data ;
+
+ if( p_avi_demux->p_riff )
+ RIFF_DeleteChunk( p_input, p_avi_demux->p_riff );
+ if( p_avi_demux->p_hdrl )
+ RIFF_DeleteChunk( p_input, p_avi_demux->p_hdrl );
+ if( p_avi_demux->p_movi )
+ RIFF_DeleteChunk( p_input, p_avi_demux->p_movi );
+ if( p_avi_demux->p_idx1 )
+ RIFF_DeleteChunk( p_input, p_avi_demux->p_idx1 );
+ if( p_avi_demux->pp_info )
{
- case( FOURCC_DIV3 ):
- case( FOURCC_div3 ):
- case( FOURCC_DIV4 ):
- case( FOURCC_div4 ):
- case( FOURCC_DIV5 ):
- case( FOURCC_div5 ):
- case( FOURCC_DIV6 ):
- case( FOURCC_div6 ):
- case( FOURCC_3IV1 ):
- case( FOURCC_AP41 ):
- case( FOURCC_MP43 ):
- case( FOURCC_mp43 ):
- return( MSMPEG4_VIDEO_ES );
-
- case( FOURCC_DIVX ):
- case( FOURCC_divx ):
- case( FOURCC_DX50 ):
- case( FOURCC_MP4S ):
- case( FOURCC_MPG4 ):
- case( FOURCC_mpg4 ):
- case( FOURCC_mp4v ):
- return( MPEG4_VIDEO_ES );
-
- default:
- return( 0 );
+ for( i = 0; i < p_avi_demux->i_streams; i++ )
+ {
+ if( p_avi_demux->pp_info[i] )
+ {
+ if( p_avi_demux->pp_info[i]->p_index )
+ {
+ free( p_avi_demux->pp_info[i]->p_index );
+ AVI_PESBuffer_Flush( p_input->p_method_data,
+ p_avi_demux->pp_info[i] );
+ }
+ free( p_avi_demux->pp_info[i] );
+ }
+ }
+ free( p_avi_demux->pp_info );
}
}
-/**************************************************************************/
-static int AVIInit( input_thread_t *p_input )
-{
+/*****************************************************************************
+ * 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;
riffchunk_t *p_riff,*p_hdrl,*p_movi;
riffchunk_t *p_avih;
riffchunk_t *p_strl,*p_strh,*p_strf;
demux_data_avi_file_t *p_avi_demux;
es_descriptor_t *p_es = NULL; /* for not warning */
- es_descriptor_t *p_es_video;
- es_descriptor_t *p_es_audio;
-
int i;
- /* we need to seek to be able to readcorrectly */
- if( !p_input->stream.b_seekable )
- {
- intf_ErrMsg( "input error: need the ability to seek in stream" );
- return( -1 );
- }
+ p_input->pf_demux = AVIDemux;
- p_input->p_demux_data =
- p_avi_demux = malloc( sizeof(demux_data_avi_file_t) );
- if( p_avi_demux == NULL )
+ if( !( p_input->p_demux_data =
+ p_avi_demux = malloc( sizeof(demux_data_avi_file_t) ) ) )
{
- intf_ErrMsg( "input error: not enough memory" );
+ msg_Err( p_input, "out of memory" );
return( -1 );
}
memset( p_avi_demux, 0, sizeof( demux_data_avi_file_t ) );
+ p_avi_demux->i_rate = DEFAULT_RATE;
+ p_avi_demux->b_seekable = ( ( p_input->stream.b_seekable )
+ &&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
- /* FIXME I don't know what it's do, copied from ESInit */
/* Initialize access plug-in structures. */
if( p_input->i_mtu == 0 )
{
if( RIFF_TestFileHeader( p_input, &p_riff, FOURCC_AVI ) != 0 )
{
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input: RIFF-AVI plug-in discarded (avi_file)" );
+ AVIEnd( p_input );
+ msg_Warn( p_input, "RIFF-AVI module discarded" );
return( -1 );
}
p_avi_demux->p_riff = p_riff;
if ( RIFF_DescendChunk(p_input) != 0 )
{
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot look for subchunk" );
return ( -1 );
}
/* it's a riff-avi file, so search for LIST-hdrl */
if( RIFF_FindListChunk(p_input ,&p_hdrl,p_riff, FOURCC_hdrl) != 0 )
{
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot find \"LIST-hdrl\" (avi_file)" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot find \"LIST-hdrl\"" );
return( -1 );
}
p_avi_demux->p_hdrl = p_hdrl;
if( RIFF_DescendChunk(p_input) != 0 )
{
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot look for subchunk" );
return ( -1 );
}
/* in LIST-hdrl search avih */
if( RIFF_FindAndLoadChunk( p_input, p_hdrl,
&p_avih, FOURCC_avih ) != 0 )
{
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot find \"avih\" chunk (avi_file)" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot find \"avih\" chunk" );
return( -1 );
}
- __AVI_Parse_avih( &p_avi_demux->avih, p_avih->p_data->p_payload_start );
+ AVI_Parse_avih( &p_avi_demux->avih, p_avih->p_data->p_payload_start );
RIFF_DeleteChunk( p_input, p_avih );
if( p_avi_demux->avih.i_streams == 0 )
/* no stream found, perhaps it would be cool to find it */
{
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: no defined stream !" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "no stream defined!" );
return( -1 );
}
/* create one program */
- vlc_mutex_lock( &p_input->stream.stream_lock );
+ vlc_mutex_lock( &p_input->stream.stream_lock );
if( input_InitStream( p_input, 0 ) == -1)
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot init stream" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot init stream" );
return( -1 );
}
if( input_AddProgram( p_input, 0, 0) == NULL )
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot add program" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot add program" );
return( -1 );
}
p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
- p_input->stream.p_new_program = p_input->stream.pp_programs[0] ;
p_input->stream.i_mux_rate = p_avi_demux->avih.i_maxbytespersec / 50;
vlc_mutex_unlock( &p_input->stream.stream_lock );
p_avi_demux->pp_info = calloc( p_avi_demux->i_streams,
sizeof( AVIStreamInfo_t* ) );
- memset( p_avi_demux->pp_info, 0,
- sizeof( AVIStreamInfo_t* ) * p_avi_demux->i_streams );
+ memset( p_avi_demux->pp_info,
+ 0,
+ sizeof( AVIStreamInfo_t* ) * p_avi_demux->i_streams );
for( i = 0 ; i < p_avi_demux->i_streams; i++ )
{
&p_strl,p_hdrl, FOURCC_strl) != 0 )
||( RIFF_DescendChunk(p_input) != 0 ))
{
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot find \"LIST-strl\" (avi_file)" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot find \"LIST-strl\"" );
return( -1 );
}
&p_strh, FOURCC_strh ) != 0 )
{
RIFF_DeleteChunk( p_input, p_strl );
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot find \"strh\" (avi_file)" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot find \"strh\"" );
return( -1 );
}
- __AVI_Parse_Header( &p_info->header,
- p_strh->p_data->p_payload_start);
+ AVI_Parse_Header( &p_info->header,
+ p_strh->p_data->p_payload_start);
RIFF_DeleteChunk( p_input, p_strh );
/* in LIST-strl search strf */
&p_strf, FOURCC_strf ) != 0 )
{
RIFF_DeleteChunk( p_input, p_strl );
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot find \"strf\" (avi_file)" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot find \"strf\"" );
return( -1 );
}
/* we don't get strd, it's useless for divx,opendivx,mepgaudio */
{
RIFF_DeleteChunk( p_input, p_strf );
RIFF_DeleteChunk( p_input, p_strl );
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot go out (\"strl\") (avi_file)" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot go out (\"strl\")" );
return( -1 );
}
{
case( FOURCC_auds ):
p_es->i_cat = AUDIO_ES;
- avi_ParseWaveFormatEx( &p_info->audio_format,
+ AVI_Parse_WaveFormatEx( &p_info->audio_format,
p_strf->p_data->p_payload_start );
- p_es->b_audio = 1;
- p_es->i_type =
- __AVI_AudioGetType( p_info->audio_format.i_formattag );
- if( p_es->i_type == 0 )
- {
- intf_ErrMsg( "input error: stream(%d,0x%x) not supported",
- i,
- p_info->audio_format.i_formattag );
- p_es->i_cat = UNKNOWN_ES;
- }
+ p_es->i_fourcc = AVI_AudioGetType(
+ p_info->audio_format.i_formattag );
break;
case( FOURCC_vids ):
p_es->i_cat = VIDEO_ES;
- avi_ParseBitMapInfoHeader( &p_info->video_format,
+ AVI_Parse_BitMapInfoHeader( &p_info->video_format,
p_strf->p_data->p_payload_start );
- p_es->b_audio = 0;
- p_es->i_type =
- __AVI_VideoGetType( p_info->video_format.i_compression );
- if( p_es->i_type == 0 )
- {
- intf_ErrMsg( "input error: stream(%d,%4.4s) not supported",
- i,
- (char*)&p_info->video_format.i_compression);
- p_es->i_cat = UNKNOWN_ES;
- }
+
+ /* XXX quick hack for playing ffmpeg video, I don't know
+ who is doing something wrong */
+ p_info->header.i_samplesize = 0;
+ p_es->i_fourcc = p_info->video_format.i_compression;
break;
default:
- intf_ErrMsg( "input error: unknown stream(%d) type",
- i );
+ msg_Err( p_input, "unknown stream(%d) type", i );
p_es->i_cat = UNKNOWN_ES;
break;
}
/* go out of p_hdrl */
if( RIFF_AscendChunk(p_input, p_hdrl) != 0)
{
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot go out (\"hdrl\") (avi_file)" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot go out (\"hdrl\")" );
return( -1 );
}
/* go to movi chunk to get it*/
if( RIFF_FindListChunk(p_input ,&p_movi,p_riff, FOURCC_movi) != 0 )
{
- intf_ErrMsg( "input error: cannot find \"LIST-movi\" (avi_file)" );
- __AVIFreeDemuxData( p_input );
+ msg_Err( p_input, "cannot find \"LIST-movi\"" );
+ AVIEnd( p_input );
return( -1 );
}
p_avi_demux->p_movi = p_movi;
/* get index XXX need to have p_movi */
- if( (p_avi_demux->avih.i_flags&AVIF_HASINDEX) != 0 )
+ if( p_avi_demux->b_seekable )
{
/* get index */
__AVI_GetIndex( p_input );
/* try to get i_idxoffset for each stream */
- __AVI_GetIndexOffset( p_input );
+ __AVI_UpdateIndexOffset( p_input );
+ /* to make sure to go the begining unless demux will see a seek */
+ RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
+
}
else
{
- intf_WarnMsg( 1, "input init: no index !" );
- }
-
-
- /* we verify that each stream have at least one entry or create it */
- for( i = 0; i < p_avi_demux->i_streams ; i++ )
- {
- AVIIndexEntry_t index;
- riffchunk_t *p_chunk;
-#define p_info p_avi_demux->pp_info[i]
- if( p_info->p_index == NULL )
- {
- intf_WarnMsg( 3, "input init: add index entry for stream %d", i );
- RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
- if( RIFF_DescendChunk(p_input) != 0 ) { continue; }
- p_chunk = NULL;
- switch( p_info->i_cat )
- {
- case( AUDIO_ES ):
- p_info->i_idxoffset = 0; /* ref: begining of file */
- if( RIFF_FindChunk( p_input,
- MAKEFOURCC('0'+i/10, '0'+i%10,'w','b' ),
- p_movi ) == 0)
- {
- p_chunk = RIFF_ReadChunk( p_input );
- }
- break;
-
- case( VIDEO_ES ):
- p_info->i_idxoffset = 0;
- if( (RIFF_FindChunk( p_input,
- MAKEFOURCC('0'+i/10, '0'+i%10,'d','c' ),
- p_movi ) == 0) )
- {
- p_chunk = RIFF_ReadChunk( p_input );
- }
- else
- {
- RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
- if( RIFF_DescendChunk(p_input) != 0 ) { continue; }
- if( (RIFF_FindChunk( p_input,
- MAKEFOURCC('0'+i/10, '0'+i%10,'d','b' ),
- p_movi ) == 0) )
- {
- p_chunk = RIFF_ReadChunk( p_input );
- }
- }
- break;
- }
- if( p_chunk != NULL )
- {
- index.i_id = p_chunk->i_id;
- index.i_flags = AVIIF_KEYFRAME;
- index.i_offset = p_chunk->i_pos;
- index.i_length = p_chunk->i_size;
- __AVI_AddEntryIndex( p_info, &index );
- }
- }
-#undef p_info
+ msg_Warn( p_input, "no index!" );
}
- /* to make sure to go the begining because unless demux will see a seek */
- RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
if( RIFF_DescendChunk( p_input ) != 0 )
{
- __AVIFreeDemuxData( p_input );
- intf_ErrMsg( "input error: cannot go in (\"movi\") (avi_file)" );
+ AVIEnd( p_input );
+ msg_Err( p_input, "cannot go in (\"movi\")" );
return( -1 );
}
/* print informations on streams */
- intf_Msg( "input init: AVIH: %d stream, flags %s%s%s%s%s%s ",
- p_avi_demux->i_streams,
- p_avi_demux->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
- p_avi_demux->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
- p_avi_demux->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
- p_avi_demux->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"",
- p_avi_demux->avih.i_flags&AVIF_WASCAPTUREFILE?" CAPTUREFILE":"",
- p_avi_demux->avih.i_flags&AVIF_COPYRIGHTED?" COPYRIGHTED":"" );
-
- p_es_video = NULL;
- p_es_audio = NULL;
-
+ msg_Dbg( p_input, "AVIH: %d stream, flags %s%s%s%s ",
+ p_avi_demux->i_streams,
+ p_avi_demux->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
+ p_avi_demux->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
+ p_avi_demux->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
+ p_avi_demux->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
+
for( i = 0; i < p_avi_demux->i_streams; i++ )
{
#define p_info p_avi_demux->pp_info[i]
switch( p_info->p_es->i_cat )
{
case( VIDEO_ES ):
- intf_Msg("input init: video(%4.4s) %dx%d %dbpp %ffps (size %d)",
- (char*)&p_info->video_format.i_compression,
- p_info->video_format.i_width,
- p_info->video_format.i_height,
- p_info->video_format.i_bitcount,
- (float)p_info->header.i_rate /
- (float)p_info->header.i_scale,
- p_info->header.i_samplesize );
- if( (p_es_video == NULL) )
+
+ msg_Dbg( p_input, "video(%4.4s) %dx%d %dbpp %ffps",
+ (char*)&p_info->video_format.i_compression,
+ p_info->video_format.i_width,
+ p_info->video_format.i_height,
+ p_info->video_format.i_bitcount,
+ (float)p_info->header.i_rate /
+ (float)p_info->header.i_scale );
+ if( (p_avi_demux->p_info_video == NULL) )
{
- p_es_video = p_info->p_es;
+ p_avi_demux->p_info_video = p_info;
+ /* TODO add test to see if a decoder has been found */
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ input_SelectES( p_input, p_info->p_es );
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
}
break;
case( AUDIO_ES ):
- intf_Msg( "input init: audio(0x%x) %d channels %dHz %dbits %ffps (size %d)",
- p_info->audio_format.i_formattag,
- p_info->audio_format.i_channels,
- p_info->audio_format.i_samplespersec,
- p_info->audio_format.i_bitspersample,
- (float)p_info->header.i_rate /
- (float)p_info->header.i_scale,
- p_info->header.i_samplesize );
- if( (p_es_audio == NULL) )
+ msg_Dbg( p_input, "audio(0x%x) %d channels %dHz %dbits",
+ p_info->audio_format.i_formattag,
+ p_info->audio_format.i_channels,
+ p_info->audio_format.i_samplespersec,
+ p_info->audio_format.i_bitspersample );
+ if( (p_avi_demux->p_info_audio == NULL) )
{
- p_es_audio = p_info->p_es;
+ p_avi_demux->p_info_audio = p_info;
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ input_SelectES( p_input, p_info->p_es );
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
}
break;
+ default:
+ break;
}
#undef p_info
}
+
/* we select the first audio and video ES */
vlc_mutex_lock( &p_input->stream.stream_lock );
- if( p_es_video != NULL )
- {
- input_SelectES( p_input, p_es_video );
- /* it seems that it's useless to select es because there are selected
- * by the interface but i'm not sure of that */
- }
- else
- {
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- intf_ErrMsg( "input error: no video stream found !" );
- return( -1 );
- }
- if( p_es_audio != NULL )
+ if( !p_avi_demux->p_info_video )
{
- input_SelectES( p_input, p_es_audio );
+ msg_Warn( p_input, "no video stream found" );
}
- else
+ if( !p_avi_demux->p_info_audio )
{
- intf_Msg( "input init: no audio stream found !" );
+ msg_Warn( p_input, "no audio stream found!" );
}
p_input->stream.p_selected_program->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
return( 0 );
}
-static void AVIEnd( input_thread_t *p_input )
-{
- __AVIFreeDemuxData( p_input );
- return;
-}
-static mtime_t __AVI_GetPTS( AVIStreamInfo_t *p_info )
-{
- /* XXX you need to add p_info->i_date to have correct pts */
- /* p_info->p_index[p_info->i_idxpos] need to be valid !! */
- mtime_t i_pts;
- /* be careful to *1000000 before round ! */
- if( p_info->header.i_samplesize != 0 )
- {
- i_pts = (mtime_t)( (double)1000000.0 *
- (double)p_info->p_index[p_info->i_idxpos].i_lengthtotal *
- (double)p_info->header.i_scale /
- (double)p_info->header.i_rate /
- (double)p_info->header.i_samplesize );
- }
- else
- {
- i_pts = (mtime_t)( (double)1000000.0 *
- (double)p_info->i_idxpos *
- (double)p_info->header.i_scale /
- (double)p_info->header.i_rate);
- }
- return( i_pts );
-}
+/*****************************************************************************
+ * Function to convert pts to chunk or byte
+ *****************************************************************************/
-static int __AVI_NextIndexEntry( input_thread_t *p_input,
- AVIStreamInfo_t *p_info )
+static inline mtime_t AVI_PTSToChunk( AVIStreamInfo_t *p_info,
+ mtime_t i_pts )
{
- AVIIndexEntry_t index;
- riffchunk_t *p_chunk;
- demux_data_avi_file_t *p_avi_demux;
- AVIStreamInfo_t *p_info_tmp;
- int i;
- int i_idxpos;
- int b_inc = 0;
- p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
-
- p_info->i_idxpos++;
+ return( (mtime_t)((s64)i_pts *
+ (s64)p_info->header.i_rate /
+ (s64)p_info->header.i_scale /
+ (s64)1000000 ) );
+}
+static inline mtime_t AVI_PTSToByte( AVIStreamInfo_t *p_info,
+ mtime_t i_pts )
+{
+ return( (mtime_t)((s64)i_pts *
+ (s64)p_info->header.i_samplesize *
+ (s64)p_info->header.i_rate /
+ (s64)p_info->header.i_scale /
+ (s64)1000000 ) );
- if( p_info->i_idxpos < p_info->i_idxnb )
+}
+static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
+{
+
+ if( p_info->header.i_samplesize )
{
- return( 0 );
+ /* we need a valid entry we will emulate one */
+ int i_len;
+ if( p_info->i_idxposc == p_info->i_idxnb )
+ {
+ if( p_info->i_idxposc )
+ {
+ /* use the last entry */
+ i_len = p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal
+ + p_info->p_index[p_info->i_idxnb - 1].i_length
+ + p_info->i_idxposb; /* should be 0 */
+ }
+ else
+ {
+ i_len = p_info->i_idxposb;
+ /* no valid entry use only offset*/
+ }
+ }
+ else
+ {
+ i_len = p_info->p_index[p_info->i_idxposc].i_lengthtotal
+ + p_info->i_idxposb;
+ }
+ return( (mtime_t)( (s64)1000000 *
+ (s64)i_len *
+ (s64)p_info->header.i_scale /
+ (s64)p_info->header.i_rate /
+ (s64)p_info->header.i_samplesize ) );
+ }
+ else
+ {
+ /* even if p_info->i_idxposc isn't valid, there isn't any probllem */
+ return( (mtime_t)( (s64)1000000 *
+ (s64)(p_info->i_idxposc ) *
+ (s64)p_info->header.i_scale /
+ (s64)p_info->header.i_rate) );
+ }
+}
+
+
+/*****************************************************************************
+ * Functions to acces streams data
+ * Uses it, because i plane to read unseekable stream
+ * Don't work for the moment for unseekable stream
+ * XXX NEVER set directly i_idxposc and i_idxposb unless you know what you do
+ *****************************************************************************/
+
+/* FIXME FIXME change b_pad to number of bytes to skipp after reading */
+static int __AVI_GetDataInPES( input_thread_t *p_input,
+ pes_packet_t **pp_pes,
+ int i_size,
+ int b_pad )
+{
+
+ int i_read;
+ data_packet_t *p_data;
+
+
+ if( !(*pp_pes = input_NewPES( p_input->p_method_data ) ) )
+ {
+ return( 0 );
+ }
+
+
+ if( !i_size )
+ {
+ p_data = input_NewPacket( p_input->p_method_data, 0 );
+ (*pp_pes)->p_first = (*pp_pes)->p_last = p_data;
+ (*pp_pes)->i_nb_data = 1;
+ (*pp_pes)->i_pes_size = 0;
+ return( 0 );
}
- p_info->i_idxpos--;
- /* create entry on the fly */
- /* TODO: when parsing for a stream take care of the other to not do
- the same things two time */
- /* search for the less advance stream and parse from it for all streams*/
- p_info_tmp = p_info;
- for( i = 0; i < p_avi_demux->i_streams; i++ )
+ if( ( i_size&1 )&&( b_pad ) )
+ {
+ b_pad = 1;
+ i_size++;
+ }
+ else
+ {
+ b_pad = 0;
+ }
+
+ do
+ {
+ i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size -
+ (*pp_pes)->i_pes_size, 1024 ) );
+ if( i_read < 0 )
+ {
+ return( (*pp_pes)->i_pes_size );
+ }
+ if( !(*pp_pes)->p_first )
+ {
+ (*pp_pes)->p_first =
+ (*pp_pes)->p_last = p_data;
+ (*pp_pes)->i_nb_data = 1;
+ (*pp_pes)->i_pes_size = i_read;
+ }
+ else
+ {
+ (*pp_pes)->p_last->p_next =
+ (*pp_pes)->p_last = p_data;
+ (*pp_pes)->i_nb_data++;
+ (*pp_pes)->i_pes_size += i_read;
+ }
+ } while( ((*pp_pes)->i_pes_size < i_size)&&( i_read ) );
+
+ if( b_pad )
+ {
+ (*pp_pes)->i_pes_size--;
+ (*pp_pes)->p_last->p_payload_end--;
+ i_size--;
+ }
+
+ return( i_size );
+}
+
+static int __AVI_SeekAndGetChunk( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info )
+{
+ pes_packet_t *p_pes;
+ int i_length, i_ret;
+
+ i_length = __MIN( p_info->p_index[p_info->i_idxposc].i_length
+ - p_info->i_idxposb,
+ BUFFER_MAXSPESSIZE );
+
+ AVI_SeekAbsolute( p_input,
+ (off_t)p_info->p_index[p_info->i_idxposc].i_pos +
+ p_info->i_idxposb + 8);
+
+ i_ret = __AVI_GetDataInPES( p_input, &p_pes, i_length , 0);
+
+ if( i_ret != i_length )
+ {
+ return( 0 );
+ }
+ /* TODO test key frame if i_idxposb == 0*/
+ AVI_PESBuffer_Add( p_input->p_method_data,
+ p_info,
+ p_pes,
+ p_info->i_idxposc,
+ p_info->i_idxposb );
+ return( 1 );
+}
+/* TODO check if it's correct (humm...) and optimisation ... */
+/* return 0 if we choose to get only the ck we want
+ * 1 if index is invalid
+ * 2 if there is a ck_other before ck_info and the last proced ck_info*/
+/* XXX XXX XXX avi file is some BIG shit, and sometime index give
+ * a refenrence to the same chunk BUT with a different size ( usually 0 )
+ */
+
+static inline int __AVI_GetChunkMethod( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info,
+ AVIStreamInfo_t *p_other )
+{
+ int i_info_pos;
+ int i_other_pos;
+
+ int i_info_pos_last;
+ int i_other_pos_last;
+
+ /*If we don't have a valid entry we need to parse from last
+ defined chunk and it's the only way that we return 1*/
+ if( p_info->i_idxposc >= p_info->i_idxnb )
+ {
+ return( 1 );
+ }
+
+ /* KNOW we have a valid entry for p_info */
+ /* we return 0 if we haven't an valid entry for p_other */
+ if( ( !p_other )||( p_other->i_idxposc >= p_other->i_idxnb ) )
{
+ return( 0 );
+ }
+
+ /* KNOW there are 2 streams with valid entry */
+
+ /* we return 0 if for one of the two streams we will not read
+ chunk-aligned */
+ if( ( p_info->i_idxposb )||( p_other->i_idxposb ) )
+ {
+ return( 0 );
+ }
+
+ /* KNOW we have a valid entry for the 2 streams
+ and for the 2 we want an aligned chunk (given by i_idxposc )*/
+ /* if in stream, the next chunk is back than the one we
+ have just read, it's useless to parse */
+ i_info_pos = p_info->p_index[p_info->i_idxposc].i_pos;
+ i_other_pos = p_other->p_index[p_other->i_idxposc].i_pos ;
+
+ i_info_pos_last = p_info->i_idxposc ?
+ p_info->p_index[p_info->i_idxposc - 1].i_pos : 0;
+ i_other_pos_last = p_other->i_idxposc ?
+ p_other->p_index[p_other->i_idxposc - 1].i_pos : 0 ;
+
+
+ if( ( ( p_info->i_idxposc )&&( i_info_pos <= i_info_pos_last ) ) ||
+ ( ( p_other->i_idxposc )&&( i_other_pos <= i_other_pos_last ) ) )
+ {
+ return( 0 );
+ }
+
+ /* KNOW for the 2 streams, the ck we want are after the last read
+ or it's the first */
+
+ /* if the first ck_other we want isn't between ck_info_last
+ and ck_info, don't parse */
+ /* TODO fix this, use also number in buffered PES */
+ if( ( i_other_pos > i_info_pos) /* ck_other too far */
+ ||( i_other_pos < i_info_pos_last ) ) /* it's too late for ck_other */
+ {
+ return( 0 );
+ }
+
+ /* we Know we will find ck_other, and before ck_info
+ "if ck_info is too far" will be handle after */
+ return( 2 );
+}
+
+
+static inline int __AVI_ChooseSize( int l1, int l2 )
+{
+ /* XXX l2 is prefered if 0 otherwise min not equal to 0 */
+ if( !l2 )
+ {
+ return( 0 );
+ }
+ return( !l1 ? l2 : __MIN( l1,l2 ) );
+}
+
+/* We know we will read chunk align */
+static int __AVI_GetAndPutChunkInBuffer( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info,
+ int i_size,
+ int i_ck )
+{
+
+ pes_packet_t *p_pes;
+ int i_length;
+
+ i_length = __MIN( i_size, BUFFER_MAXSPESSIZE );
+
+ /* Skip chunk header */
+
+ if( __AVI_GetDataInPES( p_input, &p_pes, i_length + 8,1 ) != i_length +8 )
+ {
+ return( 0 );
+ }
+ p_pes->p_first->p_payload_start += 8;
+ p_pes->i_pes_size -= 8;
+
+ i_size = GetDWLE( p_pes->p_first->p_demux_start + 4);
+
+ AVI_PESBuffer_Add( p_input->p_method_data,
+ p_info,
+ p_pes,
+ i_ck,
+ 0 );
+ /* skip unwanted bytes */
+ if( i_length != i_size)
+ {
+ msg_Err( p_input, "Chunk Size mismatch" );
+ AVI_SeekAbsolute( p_input,
+ __EVEN( AVI_TellAbsolute( p_input ) +
+ i_size - i_length ) );
+ }
+ return( 1 );
+}
+
+/* XXX Don't use this function directly ! XXX */
+static int __AVI_GetChunk( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info,
+ int b_load )
+{
+ demux_data_avi_file_t *p_avi_demux =
+ (demux_data_avi_file_t*)p_input->p_demux_data;
+ AVIStreamInfo_t *p_other;
+ int i_method;
+ off_t i_posmax;
+ int i;
+
#define p_info_i p_avi_demux->pp_info[i]
- if( p_info_i->p_index[p_info_i->i_idxnb - 1].i_offset +
- p_info_i->i_idxoffset <
- p_info_tmp->p_index[p_info_tmp->i_idxnb - 1].i_offset +
- p_info_tmp->i_idxoffset )
+ while( p_info->p_pes_first )
+ {
+ if( ( p_info->p_pes_first->i_posc == p_info->i_idxposc )
+ &&( p_info->i_idxposb >= p_info->p_pes_first->i_posb )
+ &&( p_info->i_idxposb < p_info->p_pes_first->i_posb +
+ p_info->p_pes_first->p_pes->i_pes_size ) )
+
+ {
+ return( 1 ); /* we have it in buffer */
+ }
+ else
{
- p_info_tmp = p_info_i;
+ AVI_PESBuffer_Drop( p_input->p_method_data, p_info );
}
-#undef p_info_i
}
- /* go to last defined entry */
- i_idxpos = p_info_tmp->i_idxpos; /* save p_info_tmp->i_idxpos */
- p_info_tmp->i_idxpos = p_info_tmp->i_idxnb - 1;
- __AVI_SeekToChunk( p_input, p_info_tmp );
- p_info_tmp->i_idxpos = i_idxpos;
+ /* up to now we handle only one audio and video streams at the same time */
+ p_other = (p_info == p_avi_demux->p_info_video ) ?
+ p_avi_demux->p_info_audio : p_avi_demux->p_info_video ;
+
+ i_method = __AVI_GetChunkMethod( p_input, p_info, p_other );
- if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+ if( !i_method )
{
- __AVI_SeekToChunk( p_input, p_info );
- return( -1 );
+ /* get directly the good chunk */
+ return( b_load ? __AVI_SeekAndGetChunk( p_input, p_info ) : 1 );
}
- /* save idxpos of p_info */
- /* now parse for all stream and stop when reach next chunk for p_info */
- for( i = 0; (i < 20)||(!b_inc); i++)
+ /* We will parse
+ * because invalid index
+ * or will find ck_other before ck_info
+ */
+// msg_Warn( p_input, "method %d", i_method );
+ /* we will calculate the better position we have to reach */
+ if( i_method == 1 )
{
- int i_number;
- u16 i_type;
- if( (p_chunk = RIFF_ReadChunk( p_input )) == NULL )
+ /* invalid index */
+ /* the position max we have already reached */
+ /* FIXME this isn't the better because sometime will fail to
+ put in buffer p_other since it could be too far */
+ AVIStreamInfo_t *p_info_max = p_info;
+
+ for( i = 0; i < p_avi_demux->i_streams; i++ )
{
- if( b_inc )
+ if( p_info_i->i_idxnb )
+ {
+ if( p_info_max->i_idxnb )
+ {
+ if( p_info_i->p_index[p_info_i->i_idxnb -1 ].i_pos >
+ p_info_max->p_index[p_info_max->i_idxnb -1 ].i_pos )
+ {
+ p_info_max = p_info_i;
+ }
+ }
+ else
+ {
+ p_info_max = p_info_i;
+ }
+ }
+ }
+ if( p_info_max->i_idxnb )
+ {
+ /* be carefull that size between index and ck can sometime be
+ different without any error (and other time it's an error) */
+ i_posmax = p_info_max->p_index[p_info_max->i_idxnb -1 ].i_pos;
+ /* so choose this, and I know that we have already reach it */
+ }
+ else
+ {
+ i_posmax = p_avi_demux->p_movi->i_pos + 12;
+ }
+ }
+ else
+ {
+ if( !b_load )
+ {
+ return( 1 ); /* all is ok */
+ }
+ /* valid index */
+ /* we know that the entry and the last one are valid for the 2 stream */
+ /* and ck_other will come *before* index so go directly to it*/
+ i_posmax = p_other->p_index[p_other->i_idxposc].i_pos;
+ }
+
+ AVI_SeekAbsolute( p_input, i_posmax );
+ /* the first chunk we will see is :
+ * the last chunk that we have already seen for broken index
+ * the first ck for other with good index */
+ for( ; ; ) /* infinite parsing until the ck we want */
+ {
+ riffchunk_t *p_ck;
+ int i_type;
+
+ /* Get the actual chunk in the stream */
+ if( !(p_ck = RIFF_ReadChunk( p_input )) )
+ {
+ return( 0 );
+ }
+// msg_Dbg( p_input, "ck: %4.4s len %d", &p_ck->i_id, p_ck->i_size );
+ /* special case for LIST-rec chunk */
+ if( ( p_ck->i_id == FOURCC_LIST )&&( p_ck->i_type == FOURCC_rec ) )
+ {
+ RIFF_DescendChunk( p_input );
+ RIFF_DeleteChunk( p_input, p_ck );
+ continue;
+ }
+ AVI_ParseStreamHeader( p_ck->i_id, &i, &i_type );
+ /* littles checks but not too much if you want to read all file */
+ if( i >= p_avi_demux->i_streams )
+ /* (AVI_GetESTypeFromTwoCC(i_type) != p_info_i->i_cat) perhaps add it*/
+
+ {
+ RIFF_DeleteChunk( p_input, p_ck );
+ if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
{
return( 0 );
}
+ }
+ else
+ {
+ int i_size;
+
+ /* have we found a new entry (not present in index)? */
+ if( ( !p_info_i->i_idxnb )
+ ||(p_info_i->p_index[p_info_i->i_idxnb-1].i_pos < p_ck->i_pos))
+ {
+ AVIIndexEntry_t index;
+
+ index.i_id = p_ck->i_id;
+ index.i_flags = AVI_GetKeyFlag( p_info_i->p_es->i_fourcc,
+ (u8*)&p_ck->i_8bytes);
+ index.i_pos = p_ck->i_pos;
+ index.i_length = p_ck->i_size;
+ __AVI_AddEntryIndex( p_info_i, &index );
+ }
+
+
+ /* TODO check if p_other is full and then if is possible
+ go directly to the good chunk */
+ if( ( p_info_i == p_other )
+ &&( !AVI_PESBuffer_IsFull( p_other ) )
+ &&( ( !p_other->p_pes_last )||
+ ( p_other->p_pes_last->p_pes->i_pes_size !=
+ BUFFER_MAXSPESSIZE ) ) )
+ {
+ int i_ck = p_other->p_pes_last ?
+ p_other->p_pes_last->i_posc + 1 : p_other->i_idxposc;
+ i_size = __AVI_ChooseSize( p_ck->i_size,
+ p_other->p_index[i_ck].i_length);
+
+ if( p_other->p_index[i_ck].i_pos == p_ck->i_pos )
+ {
+ if( !__AVI_GetAndPutChunkInBuffer( p_input, p_other,
+ i_size, i_ck ) )
+ {
+ RIFF_DeleteChunk( p_input, p_ck );
+ return( 0 );
+ }
+ }
+ else
+ {
+ if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+ {
+ RIFF_DeleteChunk( p_input, p_ck );
+
+ return( 0 );
+ }
+
+ }
+
+ RIFF_DeleteChunk( p_input, p_ck );
+ }
else
+ if( ( p_info_i == p_info)
+ &&( p_info->i_idxposc < p_info->i_idxnb ) )
{
- return( -1 );
+ /* the first ck_info is ok otherwise it should be
+ loaded without parsing */
+ i_size = __AVI_ChooseSize( p_ck->i_size,
+ p_info->p_index[p_info->i_idxposc].i_length);
+
+
+ RIFF_DeleteChunk( p_input, p_ck );
+
+ return( b_load ? __AVI_GetAndPutChunkInBuffer( p_input,
+ p_info,
+ i_size,
+ p_info->i_idxposc ) : 1 );
+ }
+ else
+ {
+ /* skip it */
+ RIFF_DeleteChunk( p_input, p_ck );
+ if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+ {
+ return( 0 );
+ }
}
}
- index.i_id = p_chunk->i_id;
- index.i_flags = AVIIF_KEYFRAME;
- index.i_offset = p_chunk->i_pos;
- index.i_length = p_chunk->i_size;
- RIFF_DeleteChunk( p_input, p_chunk );
-#define p_info_i p_avi_demux->pp_info[i_number]
- if( (__AVI_ParseStreamHeader( index.i_id, &i_number, &i_type ) == 0)
- &&( i_number < p_avi_demux->i_streams )
- && (p_info_i->p_index[p_info_i->i_idxnb - 1].i_offset +
- p_info_i->p_index[p_info_i->i_idxnb - 1].i_length + 8<=
- index.i_offset ) )
+
+ }
+
+#undef p_info_i
+}
+
+/* be sure that i_ck will be a valid index entry */
+static int AVI_SetStreamChunk( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info,
+ int i_ck )
+{
+
+ p_info->i_idxposc = i_ck;
+ p_info->i_idxposb = 0;
+
+ if( i_ck < p_info->i_idxnb )
+ {
+ return( 1 );
+ }
+ else
+ {
+ p_info->i_idxposc = p_info->i_idxnb - 1;
+ do
+ {
+ p_info->i_idxposc++;
+ if( !__AVI_GetChunk( p_input, p_info, 0 ) )
+ {
+ return( 0 );
+ }
+ } while( p_info->i_idxposc < i_ck );
+
+ return( 1 );
+ }
+}
+
+
+/* XXX FIXME up to now, we assume that all chunk are one after one */
+static int AVI_SetStreamBytes( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info,
+ off_t i_byte )
+{
+ if( ( p_info->i_idxnb > 0 )
+ &&( i_byte < p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal +
+ p_info->p_index[p_info->i_idxnb - 1].i_length ) )
+ {
+ /* index is valid to find the ck */
+ /* uses dichototmie to be fast enougth */
+ int i_idxposc = __MIN( p_info->i_idxposc, p_info->i_idxnb - 1 );
+ int i_idxmax = p_info->i_idxnb;
+ int i_idxmin = 0;
+ for( ;; )
+ {
+ if( p_info->p_index[i_idxposc].i_lengthtotal > i_byte )
+ {
+ i_idxmax = i_idxposc ;
+ i_idxposc = ( i_idxmin + i_idxposc ) / 2 ;
+ }
+ else
+ {
+ if( p_info->p_index[i_idxposc].i_lengthtotal +
+ p_info->p_index[i_idxposc].i_length <= i_byte)
+ {
+ i_idxmin = i_idxposc ;
+ i_idxposc = (i_idxmax + i_idxposc ) / 2 ;
+ }
+ else
+ {
+ p_info->i_idxposc = i_idxposc;
+ p_info->i_idxposb = i_byte -
+ p_info->p_index[i_idxposc].i_lengthtotal;
+ return( 1 );
+ }
+ }
+ }
+
+ }
+ else
+ {
+ p_info->i_idxposc = p_info->i_idxnb - 1;
+ p_info->i_idxposb = 0;
+ do
+ {
+ p_info->i_idxposc++;
+ if( !__AVI_GetChunk( p_input, p_info, 0 ) )
+ {
+ return( 0 );
+ }
+ } while( p_info->p_index[p_info->i_idxposc].i_lengthtotal +
+ p_info->p_index[p_info->i_idxposc].i_length <= i_byte );
+
+ p_info->i_idxposb = i_byte -
+ p_info->p_index[p_info->i_idxposc].i_lengthtotal;
+ return( 1 );
+ }
+}
+
+static pes_packet_t *AVI_ReadStreamChunkInPES( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info )
+
+{
+ if( p_info->i_idxposc > p_info->i_idxnb )
+ {
+ return( NULL );
+ }
+
+ /* we want chunk (p_info->i_idxposc,0) */
+ p_info->i_idxposb = 0;
+ if( !__AVI_GetChunk( p_input, p_info, 1) )
+ {
+ msg_Err( p_input, "Got one chunk : failed" );
+ return( NULL );
+ }
+ p_info->i_idxposc++;
+ return( AVI_PESBuffer_Get( p_info ) );
+}
+
+static pes_packet_t *AVI_ReadStreamBytesInPES( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info,
+ int i_byte )
+{
+ pes_packet_t *p_pes;
+ data_packet_t *p_data;
+ int i_count = 0;
+ int i_read;
+
+
+ if( !( p_pes = input_NewPES( p_input->p_method_data ) ) )
+ {
+ return( NULL );
+ }
+ if( !( p_data = input_NewPacket( p_input->p_method_data, i_byte ) ) )
+ {
+ input_DeletePES( p_input->p_method_data, p_pes );
+ return( NULL );
+ }
+
+ p_pes->p_first =
+ p_pes->p_last = p_data;
+ p_pes->i_nb_data = 1;
+ p_pes->i_pes_size = i_byte;
+
+ while( i_byte > 0 )
+ {
+ if( !__AVI_GetChunk( p_input, p_info, 1) )
+ {
+ msg_Err( p_input, "Got one chunk : failed" );
+
+ input_DeletePES( p_input->p_method_data, p_pes );
+ return( NULL );
+ }
+
+ i_read = __MIN( p_info->p_pes_first->p_pes->i_pes_size -
+ ( p_info->i_idxposb - p_info->p_pes_first->i_posb ),
+ i_byte);
+ /* FIXME FIXME FIXME follow all data packet */
+ memcpy( p_data->p_payload_start + i_count,
+ p_info->p_pes_first->p_pes->p_first->p_payload_start +
+ p_info->i_idxposb - p_info->p_pes_first->i_posb,
+ i_read );
+
+ AVI_PESBuffer_Drop( p_input->p_method_data, p_info );
+ i_byte -= i_read;
+ i_count += i_read;
+
+ p_info->i_idxposb += i_read;
+ if( p_info->p_index[p_info->i_idxposc].i_length <= p_info->i_idxposb )
+ {
+ p_info->i_idxposb -= p_info->p_index[p_info->i_idxposc].i_length;
+ p_info->i_idxposc++;
+ }
+ }
+ return( p_pes );
+}
+
+
+
+/* try to realign after a seek */
+static int AVI_ReAlign( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info )
+{
+ int i;
+ off_t i_pos;
+ int b_after = 0;
+ demux_data_avi_file_t *p_avi_demux =
+ (demux_data_avi_file_t*)p_input->p_demux_data;
+
+
+ for( i = 0; i < p_avi_demux->i_streams; i++ )
+ {
+ AVI_PESBuffer_Flush( p_input->p_method_data, p_avi_demux->pp_info[i] );
+ }
+ /* Reinit clock
+ TODO use input_ClockInit instead but need to be exported
+ p_input->stream.p_selected_program->last_cr = 0;
+ p_input->stream.p_selected_program->last_syscr = 0;
+ p_input->stream.p_selected_program->cr_ref = 0;
+ p_input->stream.p_selected_program->sysdate_ref = 0;
+ p_input->stream.p_selected_program->delta_cr = 0;
+ p_input->stream.p_selected_program->c_average_count = 0; */
+
+ i_pos = AVI_TellAbsolute( p_input );
+
+ p_info->i_idxposc--; /* in fact p_info->i_idxposc is for ck to be read */
+
+
+ if( ( p_info->i_idxposc <= 0)
+ ||( i_pos <= p_info->p_index[0].i_pos ) )
+ {
+ /* before beginning of stream */
+ return( p_info->header.i_samplesize ?
+ AVI_SetStreamBytes( p_input, p_info, 0 ) :
+ AVI_SetStreamChunk( p_input, p_info, 0 ) );
+ }
+
+ b_after = ( i_pos >= p_info->p_index[p_info->i_idxposc].i_pos );
+ /* now find in what chunk we are */
+ while( ( i_pos < p_info->p_index[p_info->i_idxposc].i_pos )
+ &&( p_info->i_idxposc > 0 ) )
+ {
+ /* search before i_idxposc */
+
+ if( !AVI_SetStreamChunk( p_input, p_info, p_info->i_idxposc - 1 ) )
+ {
+ return( 0 );
+ }
+ }
+
+ while( i_pos >= p_info->p_index[p_info->i_idxposc].i_pos +
+ p_info->p_index[p_info->i_idxposc].i_length + 8 )
+ {
+ /* search after i_idxposc */
+
+ if( !AVI_SetStreamChunk( p_input, p_info, p_info->i_idxposc + 1 ) )
{
- /* do we need to check i_type ? */
- __AVI_AddEntryIndex( p_info_i, &index );
- if( (p_info_i == p_info)&&(!b_inc) )
- {
- p_info->i_idxpos++;
- b_inc = 1;
- }
+ return( 0 );
}
-#undef p_info_i
- if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+ }
+
+ /* search nearest key frame, only for video */
+ if( p_info->i_cat == VIDEO_ES )
+ {
+ if( b_after )
{
- if( b_inc )
+ while(!(p_info->p_index[p_info->i_idxposc].i_flags&AVIIF_KEYFRAME) )
{
- return( 0 );
+ if( !AVI_SetStreamChunk( p_input, p_info,
+ p_info->i_idxposc + 1 ) )
+ {
+ return( 0 );
+ }
}
- else
+ }
+ else
+ {
+ while( ( p_info->i_idxposc > 0 ) &&
+ (!(p_info->p_index[p_info->i_idxposc].i_flags&AVIIF_KEYFRAME)) )
{
- return( -1 );
+
+ if( !AVI_SetStreamChunk( p_input, p_info,
+ p_info->i_idxposc - 1 ) )
+ {
+
+ return( 0 );
+ }
}
}
}
- return( 0 );
+ return( 1 );
}
-static int __AVI_ReAlign( input_thread_t *p_input,
- AVIStreamInfo_t *p_info )
+/* make difference between audio and video pts as little as possible */
+static void AVI_SynchroReInit( input_thread_t *p_input )
{
- u32 u32_pos;
- off_t i_pos;
+ demux_data_avi_file_t *p_avi_demux =
+ (demux_data_avi_file_t*)p_input->p_demux_data;
- __RIFF_TellPos( p_input, &u32_pos );
- i_pos = (off_t)u32_pos - (off_t)p_info->i_idxoffset;
-
- /* TODO verifier si on est dans p_movi */
-
- if( p_info->p_index[p_info->i_idxnb-1].i_offset < i_pos )
+#define p_info_video p_avi_demux->p_info_video
+#define p_info_audio p_avi_demux->p_info_audio
+ if( ( !p_info_audio )||( !p_info_video ) )
{
- p_info->i_idxpos = p_info->i_idxnb-1;
- while( p_info->p_index[p_info->i_idxpos].i_offset < i_pos )
- {
- if( __AVI_NextIndexEntry( p_input, p_info ) !=0 )
- {
- return( -1 );
- }
- }
- return( 0 );
+ return;
}
-
- if( i_pos <= p_info->p_index[0].i_offset )
+ /* now resynch audio video video */
+ /*don't care of AVIF_KEYFRAME */
+ if( !p_info_audio->header.i_samplesize )
{
- p_info->i_idxpos = 0;
- return( 0 );
+ AVI_SetStreamChunk( p_input,
+ p_info_audio,
+ AVI_PTSToChunk( p_info_audio,
+ AVI_GetPTS( p_info_video ) ) );
}
- /* if we have seek in the current chunk then do nothing
- __AVI_SeekToChunk will correct */
- if( (p_info->p_index[p_info->i_idxpos].i_offset <= i_pos)
- && ( i_pos < p_info->p_index[p_info->i_idxpos].i_offset +
- p_info->p_index[p_info->i_idxpos].i_length + 8) )
+ else
{
- return( 0 );
+ AVI_SetStreamBytes( p_input,
+ p_info_audio,
+ AVI_PTSToByte( p_info_audio,
+ AVI_GetPTS( p_info_video ) ) );
+ }
+#undef p_info_video
+#undef p_info_audio
+}
+
+/*****************************************************************************
+ * AVI_GetFrameInPES : get dpts length(µs) in pes from stream
+ *****************************************************************************
+ * Handle multiple pes, and set pts to the good value
+ *****************************************************************************/
+static pes_packet_t *AVI_GetFrameInPES( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info,
+ mtime_t i_dpts)
+{
+ int i;
+ pes_packet_t *p_pes = NULL;
+ pes_packet_t *p_pes_tmp = NULL;
+ pes_packet_t *p_pes_first = NULL;
+ mtime_t i_pts;
+
+ if( i_dpts < 1000 )
+ {
+ return( NULL ) ;
}
- if( i_pos >= p_info->p_index[p_info->i_idxpos].i_offset )
+ if( !p_info->header.i_samplesize )
{
- /* search for a chunk after i_idxpos */
- while( (p_info->p_index[p_info->i_idxpos].i_offset < i_pos) )
-/* &&( p_info->i_idxpos < p_info->i_idxnb - 1 ) ) */
+ int i_chunk = __MAX( AVI_PTSToChunk( p_info, i_dpts), 1 );
+ p_pes_first = NULL;
+ for( i = 0; i < i_chunk; i++ )
{
-/*
- if( __AVI_NextIndexEntry( p_input, p_info ) != 0 )
+ /* get pts while is valid */
+ i_pts = AVI_GetPTS( p_info );
+
+ p_pes_tmp = AVI_ReadStreamChunkInPES( p_input, p_info );
+
+ if( !p_pes_tmp )
{
- return( -1 );
+ return( p_pes_first );
}
-*/
- p_info->i_idxpos++; /* we know that index is valid (first test )*/
- }
- while(((p_info->p_index[p_info->i_idxpos].i_flags&AVIIF_KEYFRAME) == 0))
-/* &&( p_info->i_idxpos < p_info->i_idxnb - 1 ) ) */
- {
- if( __AVI_NextIndexEntry( p_input, p_info ) != 0 )
+ p_pes_tmp->i_pts = i_pts;
+ if( !p_pes_first )
+ {
+ p_pes_first = p_pes_tmp;
+ }
+ else
{
- return( -1 );
+ p_pes->p_next = p_pes_tmp;
}
+ p_pes = p_pes_tmp;
}
+ return( p_pes_first );
}
else
{
- /* search for a chunk before i_idxpos */
- while( (p_info->p_index[p_info->i_idxpos].i_offset +
- p_info->p_index[p_info->i_idxpos].i_length + 8>= i_pos)
- &&( p_info->i_idxpos > 0 ) )
+ /* stream is byte based */
+ int i_byte = AVI_PTSToByte( p_info, i_dpts);
+ if( i_byte < 50 ) /* to avoid some problem with audio */
{
- p_info->i_idxpos--; /* backward, index is always valid */
+ return( NULL );
}
- while( ((p_info->p_index[p_info->i_idxpos].i_flags&AVIIF_KEYFRAME) == 0)
- &( p_info->i_idxpos > 0 ) )
+ i_pts = AVI_GetPTS( p_info ); /* ok even with broken index */
+ p_pes = AVI_ReadStreamBytesInPES( p_input, p_info, i_byte);
+
+ if( p_pes )
{
- p_info->i_idxpos--;
+ p_pes->i_pts = i_pts;
}
+ return( p_pes );
}
-
- return( 0 );
}
-static void __AVI_SynchroReInit( input_thread_t *p_input,
- AVIStreamInfo_t *p_info_master,
- AVIStreamInfo_t *p_info_slave )
+/*****************************************************************************
+ * AVI_DecodePES : send a pes to decoder
+ *****************************************************************************
+ * Handle multiple pes, and update pts to the good value
+ *****************************************************************************/
+static inline void AVI_DecodePES( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info,
+ pes_packet_t *p_pes )
{
- demux_data_avi_file_t *p_avi_demux;
+ pes_packet_t *p_pes_next;
+ /* input_decode want only one pes, but AVI_GetFrameInPES give
+ multiple pes so send one by one */
+ while( p_pes )
+ {
+ p_pes_next = p_pes->p_next;
+ p_pes->p_next = NULL;
+ p_pes->i_pts = input_ClockGetTS( p_input,
+ p_input->stream.p_selected_program,
+ p_pes->i_pts * 9/100);
+ input_DecodePES( p_info->p_es->p_decoder_fifo, p_pes );
+ p_pes = p_pes_next;
+ }
+
+}
- p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
-
- p_avi_demux->i_date = mdate() + DEFAULT_PTS_DELAY
- - __AVI_GetPTS( p_info_master );
+/*****************************************************************************
+ * AVIDemux_Seekable: reads and demuxes data packets for stream seekable
+ *****************************************************************************
+ * Called by AVIDemux, that make common work
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+static int AVIDemux_Seekable( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info_master,
+ AVIStreamInfo_t *p_info_slave )
+{
+ demux_data_avi_file_t *p_avi_demux =
+ (demux_data_avi_file_t*)p_input->p_demux_data;
- if( p_info_slave != NULL )
- {
- p_info_slave->i_idxpos = 0;
- while( __AVI_GetPTS( p_info_slave) < __AVI_GetPTS( p_info_master) )
+ pes_packet_t *p_pes_master;
+ pes_packet_t *p_pes_slave;
+
+ /* check for signal from interface */
+ if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
+ {
+ /* we can supposed that is a seek */
+ /* first wait for empty buffer, arbitrary time */
+ msleep( DEFAULT_PTS_DELAY );
+ /* then try to realign in stream */
+ if( !AVI_ReAlign( p_input, p_info_master ) )
{
- if( __AVI_NextIndexEntry( p_input, p_info_slave ) != 0 )
+ return( 0 ); /* assume EOF */
+ }
+ AVI_SynchroReInit( p_input );
+ }
+
+ /* take care of newly selected audio ES */
+ if( p_info_master->b_selected )
+ {
+ p_info_master->b_selected = 0;
+ AVI_SynchroReInit( p_input );
+ }
+ if( ( p_info_slave )&&( p_info_slave->b_selected ) )
+ {
+ p_info_slave->b_selected = 0;
+ AVI_SynchroReInit( p_input );
+ }
+
+ /* wait for the good time */
+ input_ClockManageRef( p_input,
+ p_input->stream.p_selected_program,
+ p_avi_demux->i_pcr /*- DEFAULT_PTS_DELAY / 2 */);
+ /* calculate pcr, time when we must read the next data */
+ /* 9/100 kludge ->need to convert to 1/1000000 clock unit to 1/90000 */
+ if( p_info_slave )
+ {
+ p_avi_demux->i_pcr = __MIN( AVI_GetPTS( p_info_master ),
+ AVI_GetPTS( p_info_slave ) ) * 9/100;
+ }
+ else
+ {
+ p_avi_demux->i_pcr = AVI_GetPTS( p_info_master ) * 9/100;
+ }
+
+ /* get video and audio frames */
+ p_pes_master = AVI_GetFrameInPES( p_input,
+ p_info_master,
+ 100000 ); /* 100 ms */
+ AVI_DecodePES( p_input,
+ p_info_master,
+ p_pes_master);
+
+
+ if( p_info_slave )
+ {
+ p_pes_slave = AVI_GetFrameInPES( p_input,
+ p_info_slave,
+ AVI_GetPTS( p_info_master ) -
+ AVI_GetPTS( p_info_slave) );
+ AVI_DecodePES( p_input,
+ p_info_slave,
+ p_pes_slave );
+ }
+
+
+ /* at the end ? */
+ return( p_pes_master ? 1 : 0 );
+
+}
+
+/*****************************************************************************
+ * AVIDemux_NotSeekable: reads and demuxes data packets for stream seekable
+ *****************************************************************************
+ * Called by AVIDemux, that makes common work
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+
+/* 0 if can be load/updated, 1 if skip, 2 if descend into, 3 if exit, 4 if error and need recover */
+static int __AVIDemux_ChunkAction( int i_streams_max,
+ riffchunk_t *p_ck )
+{
+ int i_stream;
+ int i_type;
+
+ AVI_ParseStreamHeader( p_ck->i_id, &i_stream, &i_type );
+ if( i_stream < i_streams_max )
+ {
+ return( 0 ); /* read and/or update stream info */
+ }
+
+ if( i_stream <= 99 )
+ {
+ /* should not happen but ... */
+ return( 1 );
+ }
+
+ /* now we know that it's not a stream */
+
+ switch( p_ck->i_id )
+ {
+ case( FOURCC_JUNK ):
+ return( 1 );
+ case( FOURCC_idx1 ):
+ return( 3 );
+ case( FOURCC_LIST ):
+ if( p_ck->i_type == FOURCC_rec )
+ {
+ return( 2 );
+ }
+ else
{
- return;
+ return( 1 );
}
+ default:
+ break;
+ }
+ /* test for ix?? */
+
+ if( ( p_ck->i_id & 0xFFFF ) == VLC_TWOCC( 'i','x' ) )
+ {
+ return( 1 );
+ }
+
+ return( 4 );
+}
+
+static int AVI_NotSeekableRecover( input_thread_t *p_input )
+{
+ byte_t *p_id;
+ u32 i_id;
+ int i_number, i_type;
+ data_packet_t *p_pack;
+
+ for( ; ; )
+ {
+ if( input_Peek( p_input, &p_id, 4 ) < 4 )
+ {
+ return( 0 ); /* Failed */
+ }
+ i_id = GetDWLE( p_id );
+ switch( i_id )
+ {
+ case( FOURCC_idx1 ):
+ case( FOURCC_JUNK ):
+ case( FOURCC_LIST ):
+ return( 1 );
+ default:
+ AVI_ParseStreamHeader( i_id, &i_number, &i_type );
+ if( i_number <= 99 )
+ {
+ switch( i_type )
+ {
+ case( TWOCC_wb ):
+ case( TWOCC_db ):
+ case( TWOCC_dc ):
+ case( TWOCC_pc ):
+ return( 1 );
+ }
+ }
+ else
+ {
+
+ }
}
- if( (__AVI_GetPTS( p_info_slave) > __AVI_GetPTS( p_info_master))
- &&(p_info_slave->i_idxpos>0) )
+ /* Read 1 byte VERY unoptimised */
+ if( input_SplitBuffer( p_input, &p_pack, 1) < 1 )
{
- p_info_slave->i_idxpos--;
+ return( 0 );
}
- p_info_slave->b_unselected = 0 ;
+ input_DeletePacket( p_input->p_method_data, p_pack);
}
- p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
-}
-/** -1 in case of error, 0 of EOF, 1 otherwise **/
-static int AVIDemux( input_thread_t *p_input )
+
+}
+
+static int AVIDemux_NotSeekable( input_thread_t *p_input,
+ AVIStreamInfo_t *p_info_master,
+ AVIStreamInfo_t *p_info_slave )
{
- riffchunk_t *p_chunk;
- int i;
+ demux_data_avi_file_t *p_avi_demux =
+ (demux_data_avi_file_t*)p_input->p_demux_data;
+ int i_loop;
+ int i_stream;
+ int i_type;
+
+ riffchunk_t *p_ck;
pes_packet_t *p_pes;
- demux_data_avi_file_t *p_avi_demux;
+
+/*
+ i_filepos = AVI_TellAbsolute( p_input );
+ p_input->pf_seek( p_input, i_filepos );
+ input_AccessReinit( p_input );
+*/
+
+#define p_info p_avi_demux->pp_info[i_stream]
- AVIStreamInfo_t *p_info_video;
- AVIStreamInfo_t *p_info_audio;
- AVIStreamInfo_t *p_info;
-/* try to use this to read data packet at the good time
- * input_ClockManageRef( p_input,
- p_input->stream.p_selected_program,
- (mtime_t)pcr ); ??? what suppose to do */
- p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
-
- /* search video and audio stream selected */
- p_info_video = NULL;
- p_info_audio = NULL;
+ /* The managment is very basic, we will read packets, caclulate pts
+ and send it to decoder, synchro made on video, and audio is very less
+ important */
- for( i = 0; i < p_avi_demux->i_streams; i++ )
+ /* wait the good time */
+ input_ClockManageRef( p_input,
+ p_input->stream.p_selected_program,
+ p_avi_demux->i_pcr /*- DEFAULT_PTS_DELAY / 2 */);
+ /* TODO be smart, seeing if we can wait for min( audio, video )
+ or there is a too big deep */
+ if( !p_info_slave )
{
- if( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo != NULL )
+ p_avi_demux->i_pcr = AVI_GetPTS( p_info_master ) * 9/100;
+ }
+ else
+ {
+ p_avi_demux->i_pcr = __MIN( AVI_GetPTS( p_info_master ),
+ AVI_GetPTS( p_info_slave ) ) * 9/100;
+ p_avi_demux->i_pcr = AVI_GetPTS( p_info_master ) * 9/100;
+ }
+
+ for( i_loop = 0; i_loop < 10; i_loop++ )
+ {
+ int b_load =0;
+
+ /* first find a ck for master or slave */
+ do
{
- switch( p_avi_demux->pp_info[i]->p_es->i_cat )
+
+ if( !(p_ck = RIFF_ReadChunk( p_input ) ) )
{
- case( VIDEO_ES ):
- p_info_video = p_avi_demux->pp_info[i];
+ msg_Err( p_input, "Badd" );
+ return( 0 ); /* assume EOF */
+ }
+ //msg_Err( p_input,"Looking ck: %4.4s %d",&p_ck->i_id, p_ck->i_size );
+
+ switch( __AVIDemux_ChunkAction( p_avi_demux->i_streams, p_ck ) )
+ {
+ case( 0 ): /* load it if possible */
+ b_load = 1;
+ break;
+ case( 1 ): /* skip it */
+ RIFF_DeleteChunk( p_input, p_ck );
+ if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+ {
+ return( 0 );
+ }
+ b_load = 0;
break;
- case( AUDIO_ES ):
- p_info_audio = p_avi_demux->pp_info[i];
+ case( 2 ): /* descend into */
+ RIFF_DeleteChunk( p_input, p_ck );
+ RIFF_DescendChunk( p_input );
+ b_load = 0;
+ break;
+ case( 3 ): /* exit */
+ RIFF_DeleteChunk( p_input, p_ck );
+ return( 0 );
+ case( 4 ): /* Error */
+ RIFF_DeleteChunk( p_input, p_ck );
+ msg_Warn( p_input, "unknown chunk id 0x%8.8x, trying to recover", p_ck->i_id );
+ if( !AVI_NotSeekableRecover( p_input ) )
+ {
+ msg_Err( p_input, "cannot recover, dying" );
+ return( -1 );
+ }
+ else
+ {
+ msg_Warn( p_input, "recovered sucessfully" );
+ }
+ b_load = 0;
break;
}
+
+ } while( !b_load );
+
+ AVI_ParseStreamHeader( p_ck->i_id, &i_stream, &i_type );
+ /* now check if we really have to load it */
+ if( ( p_info != p_info_master )&&( p_info != p_info_slave ) )
+ {
+ b_load = 0;
}
else
{
- p_avi_demux->pp_info[i]->b_unselected = 1;
- }
- }
- if( p_info_video == NULL )
- {
- intf_ErrMsg( "input error: no video ouput selected" );
- return( -1 );
- }
- if( (input_ClockManageControl( p_input, p_input->stream.p_selected_program,
- (mtime_t)0) == PAUSE_S) )
- {
- __AVI_SynchroReInit( p_input, p_info_video, p_info_audio );
- }
+ if( p_info == p_info_master )
+ {
+ b_load = 1;
+ }
+ else
+ {
+ mtime_t i_dpts;
+ i_dpts = AVI_GetPTS( p_info_slave ) -
+ AVI_GetPTS( p_info_master );
+ if( i_dpts < 0 ) {i_dpts = - i_dpts; }
+ if( i_dpts < 600000 )
+ {
+ b_load = 1;
+ }
+ else
+ {
+ b_load = 0;
+ }
+ }
- /* after updated p_avi_demux->pp_info[i]->b_unselected !! */
- if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
- {
- /*realign on video stream*/
- if( __AVI_ReAlign( p_input, p_info_video ) != 0 )
- {
- return( 0 ); /* assume EOF */
}
- __AVI_SynchroReInit( p_input, p_info_video, p_info_audio );
- }
- /* update i_date if previously unselected ES (ex: 2 channels audio ) */
- if( (p_info_audio != NULL)&&(p_info_audio->b_unselected ))
- {
- p_info_audio->b_unselected = 0 ;
- /* we have to go to the good pts */
- /* we will reach p_info_ok pts */
- while( __AVI_GetPTS( p_info_audio) < __AVI_GetPTS( p_info_video) )
+ /* now do we can load this chunk ? */
+ if( b_load )
{
- if( __AVI_NextIndexEntry( p_input, p_info_audio ) != 0 )
+
+ if( __AVI_GetDataInPES( p_input, &p_pes, p_ck->i_size + 8, 1) != p_ck->i_size + 8)
{
- p_info_audio = NULL; /* to force selection of video */
- break;
+ return( 0 );
}
+ p_pes->p_first->p_payload_start += 8;
+ p_pes->i_pes_size -= 8;
+ /* get PTS */
+ p_pes->i_pts = AVI_GetPTS( p_info );
+ AVI_DecodePES( p_input, p_info, p_pes );
}
- }
+ else
+ {
- /* what stream we should read in first */
- if( p_info_audio == NULL )
- {
- p_info = p_info_video;
- }
- else
- {
- if( __AVI_GetPTS( p_info_audio ) <=
- __AVI_GetPTS( p_info_video ) )
+ if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+ {
+ RIFF_DeleteChunk( p_input, p_ck );
+ return( 0 );
+ }
+ }
+
+ /* finaly update stream information */
+ if( p_info->header.i_samplesize )
{
- p_info = p_info_audio;
+ p_info->i_idxposb += p_ck->i_size;
}
else
{
- p_info = p_info_video;
+ p_info->i_idxposc++;
}
+
+ RIFF_DeleteChunk( p_input, p_ck );
}
- /* go to the good chunk to read */
+ return( 1 );
+#undef p_info
+}
+/*****************************************************************************
+ * AVIDemux: reads and demuxes data packets
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ * TODO add support for unstreable file, just read a chunk and send it
+ * to the right decoder, very easy
+ *****************************************************************************/
+
+static int AVIDemux( input_thread_t *p_input )
+{
+ int i;
+ AVIStreamInfo_t *p_info_master;
+ AVIStreamInfo_t *p_info_slave;
- __AVI_SeekToChunk( p_input, p_info );
-
- /* now we just need to read a chunk */
- if( (p_chunk = RIFF_ReadChunk( p_input )) == NULL )
- {
- intf_ErrMsg( "input demux: cannot read chunk" );
- return( -1 );
- }
+ demux_data_avi_file_t *p_avi_demux =
+ (demux_data_avi_file_t*)p_input->p_demux_data;
- if( (p_chunk->i_id&0xFFFF0000) !=
- (p_info->p_index[p_info->i_idxpos].i_id&0xFFFF0000) )
+ /* search new video and audio stream selected
+ if current have been unselected*/
+ if( ( !p_avi_demux->p_info_video )
+ || ( !p_avi_demux->p_info_video->p_es->p_decoder_fifo ) )
+ {
+ p_avi_demux->p_info_video = NULL;
+ for( i = 0; i < p_avi_demux->i_streams; i++ )
+ {
+ if( ( p_avi_demux->pp_info[i]->i_cat == VIDEO_ES )
+ &&( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo ) )
+ {
+ p_avi_demux->p_info_video = p_avi_demux->pp_info[i];
+ p_avi_demux->p_info_video->b_selected = 1;
+ break;
+ }
+ }
+ }
+ if( ( !p_avi_demux->p_info_audio )
+ ||( !p_avi_demux->p_info_audio->p_es->p_decoder_fifo ) )
{
- intf_WarnMsg( 2, "input demux: bad index entry" );
- if( __AVI_NextIndexEntry( p_input, p_info ) != 0 )
+ p_avi_demux->p_info_audio = NULL;
+ for( i = 0; i < p_avi_demux->i_streams; i++ )
{
- return( 0 );
+ if( ( p_avi_demux->pp_info[i]->i_cat == AUDIO_ES )
+ &&( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo ) )
+ {
+ p_avi_demux->p_info_audio = p_avi_demux->pp_info[i];
+ p_avi_demux->p_info_audio->b_selected = 1;
+ break;
+ }
}
- return( 1 );
}
-/*
- intf_WarnMsg( 6, "input demux: read %4.4s chunk %d bytes",
- (char*)&p_chunk->i_id,
- p_chunk->i_size);
-*/
- if( RIFF_LoadChunkDataInPES(p_input, p_chunk, &p_pes) != 0 )
+ /* by default video is master for resync audio (after a seek .. ) */
+ if( p_avi_demux->p_info_video )
{
- intf_ErrMsg( "input error: cannot read data" );
- return( -1 );
+ p_info_master = p_avi_demux->p_info_video;
+ p_info_slave = p_avi_demux->p_info_audio;
+ }
+ else
+ {
+ p_info_master = p_avi_demux->p_info_audio;
+ p_info_slave = NULL;
}
-/* i_rate is about how fast we read it (slow, fast ...) */
-/* TODO: handle i_rate */
- vlc_mutex_lock( &p_input->stream.stream_lock );
- p_pes->i_rate = p_input->stream.control.i_rate;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- p_pes->i_pts = p_avi_demux->i_date + __AVI_GetPTS( p_info );
- p_pes->i_dts = 0;
- /* send to decoder */
- vlc_mutex_lock( &p_info->p_es->p_decoder_fifo->data_lock );
- /* change MAX_PACKET and replace it to have same duration of audio
- and video in buffer, to avoid to much unsynchronization while seeking */
- if( p_info->p_es->p_decoder_fifo->i_depth >= MAX_PACKETS_IN_FIFO )
+ if( !p_info_master )
{
- /* Wait for the decoder. */
- vlc_cond_wait( &p_info->p_es->p_decoder_fifo->data_wait,
- &p_info->p_es->p_decoder_fifo->data_lock );
+ msg_Err( p_input, "no stream selected" );
+ return( -1 );
}
- vlc_mutex_unlock( &p_info->p_es->p_decoder_fifo->data_lock );
- input_DecodePES( p_info->p_es->p_decoder_fifo, p_pes );
- if( p_info == p_info_video )
+ /* manage rate, if not default: skeep audio */
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ if( p_input->stream.control.i_rate != p_avi_demux->i_rate )
{
- if( __AVI_NextIndexEntry( p_input, p_info ) != 0 )
+ if( p_avi_demux->p_info_audio)
{
- return( 0 );
+ p_avi_demux->p_info_audio->b_selected = 1;
}
+ p_avi_demux->i_rate = p_input->stream.control.i_rate;
+ }
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ p_avi_demux->i_rate = DEFAULT_RATE;
+ if( p_avi_demux->i_rate != DEFAULT_RATE )
+ {
+ p_info_slave = NULL;
+ }
+
+ if( p_avi_demux->b_seekable )
+ {
+ return( AVIDemux_Seekable( p_input,
+ p_info_master,
+ p_info_slave) );
}
else
{
- __AVI_NextIndexEntry( p_input, p_info );
+ return( AVIDemux_NotSeekable( p_input,
+ p_info_master,
+ p_info_slave ) );
}
-
- return( 1 );
}
+
+
+