Commit b2b07494 authored by Laurent Aimar's avatar Laurent Aimar

* all : I rewrite the way to read, in order to minimize seeking (

faster and in prevision of VOD by http, but not yet functionnal ). But
sound becomes horrible, I will try to fix it as soon as possible.
parent 62e73f50
......@@ -2,7 +2,7 @@
* avi.c : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: avi.c,v 1.22 2002/06/07 14:30:40 sam Exp $
* $Id: avi.c,v 1.23 2002/06/26 23:11:12 fenrir Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
......@@ -66,8 +66,7 @@ MODULE_DEACTIVATE_STOP
/*****************************************************************************
* Definition of structures and libraries for this plugins
*****************************************************************************/
#include "libLE.c"
#include "libioRIFF.c"
#include "libioRIFF.h"
#include "avi.h"
/*****************************************************************************
......@@ -84,7 +83,264 @@ static void input_getfunctions( function_list_t * p_function_list )
#undef input
}
/********************************************************************/
/*****************************************************************************
* Some usefull functions to manipulate memory
*****************************************************************************/
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 inline off_t __EVEN( off_t i )
{
return( (i & 1) ? i+1 : i );
}
/*****************************************************************************
* Functions for parsing the headers in an avi file
*****************************************************************************/
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 )
{
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 );
}
return( UNKNOWN_ES );
}
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 );
}
}
static int AVI_VideoGetType( u32 i_type )
{
switch( i_type )
{
case( FOURCC_DIV1 ): /* FIXME it is for msmpeg4v1 or old mpeg4 ?? */
case( FOURCC_div1 ):
case( FOURCC_MPG4 ):
case( FOURCC_mpg4 ):
return( MSMPEG4v1_VIDEO_ES );
case( FOURCC_DIV2 ):
case( FOURCC_div2 ):
case( FOURCC_MP42 ):
case( FOURCC_mp42 ):
return( MSMPEG4v2_VIDEO_ES );
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( MSMPEG4v3_VIDEO_ES );
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 ):
return( MPEG4_VIDEO_ES );
default:
return( 0 );
}
}
/*****************************************************************************
* Data and functions to manipulate pes buffer
*****************************************************************************/
#define BUFFER_MAXTOTALSIZE 512*1024 /* 1/2 Mo */
#define BUFFER_MAXSPESSIZE 1024*200
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 )
{
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;
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 )
{
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 );
}
}
static void AVI_PESBuffer_Flush( input_buffers_t *p_method_data,
AVIStreamInfo_t *p_info )
{
while( p_info->p_pes_first )
{
AVI_PESBuffer_Drop( p_method_data, p_info );
}
}
static void __AVIFreeDemuxData( input_thread_t *p_input )
......@@ -110,6 +366,7 @@ static void __AVIFreeDemuxData( input_thread_t *p_input )
if( p_avi_demux->pp_info[i]->p_index != NULL )
{
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] );
}
......@@ -118,85 +375,7 @@ static void __AVIFreeDemuxData( input_thread_t *p_input )
}
}
static void __AVI_Parse_avih( MainAVIHeader_t *p_avih, byte_t *p_buff )
{
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);
}
static void __AVI_Parse_Header( AVIStreamHeader_t *p_strh, byte_t *p_buff )
{
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);
}
int avi_ParseBitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
{
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 );
}
int avi_ParseWaveFormatEx( waveformatex_t *h, byte_t *p_data )
{
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 );
}
static inline int __AVIGetESTypeFromTwoCC( u16 i_type )
{
switch( i_type )
{
case( TWOCC_wb ):
return( AUDIO_ES );
case( TWOCC_dc ):
case( TWOCC_db ):
return( VIDEO_ES );
}
return( UNKNOWN_ES );
}
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;
......@@ -207,12 +386,42 @@ static int __AVI_ParseStreamHeader( u32 i_id, int *i_number, u16 *i_type )
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 = ( c4 << 8) + c3;
}
}
/* 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 )
{
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)
......@@ -232,7 +441,7 @@ static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
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;
......@@ -262,7 +471,7 @@ static void __AVI_GetIndex( input_thread_t *p_input )
int i_read;
int i;
int i_number;
u16 i_type;
int i_type;
int i_totalentry = 0;
demux_data_avi_file_t *p_avi_demux =
(demux_data_avi_file_t*)p_input->p_demux_data ;
......@@ -292,15 +501,15 @@ static void __AVI_GetIndex( input_thread_t *p_input )
{
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_pos = __GetDoubleWordLittleEndianFromBuff( p_peek+8);
index.i_length = __GetDoubleWordLittleEndianFromBuff(p_peek+12);
index.i_id = GetDWLE( p_peek );
index.i_flags = GetDWLE( p_peek+4);
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 )
&&(p_avi_demux->pp_info[i_number]->i_cat ==
__AVIGetESTypeFromTwoCC( i_type )))
if( ( i_number < p_avi_demux->i_streams )
&&(p_avi_demux->pp_info[i_number]->i_cat ==
__AVI_GetESTypeFromTwoCC( i_type )))
{
__AVI_AddEntryIndex( p_avi_demux->pp_info[i_number],
&index );
......@@ -310,20 +519,6 @@ static void __AVI_GetIndex( input_thread_t *p_input )
}
}
static int __AVI_SeekToChunk( input_thread_t *p_input, AVIStreamInfo_t *p_info )
{
if( (p_info->p_index )&&(p_info->i_idxposc < p_info->i_idxnb) )
{
p_input->pf_seek( p_input,
(off_t)p_info->p_index[p_info->i_idxposc].i_pos);
input_AccessReinit( p_input );
return( 0 );
}
/* no index can't arrive but ...*/
msg_Warn( p_input, "cannot seek");
return( -1 );
}
/* XXX call after get p_movi */
static void __AVI_UpdateIndexOffset( input_thread_t *p_input )
......@@ -363,72 +558,10 @@ static void __AVI_UpdateIndexOffset( input_thread_t *p_input )
#undef p_info
}
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 );
}
}
static int __AVI_VideoGetType( u32 i_type )
{
switch( i_type )
{
/* FIXME FIXME : what are the correct tag for msmpeg4 v1 */
case( FOURCC_MPG4 ):
case( FOURCC_mpg4 ):
case( FOURCC_DIV2 ):
case( FOURCC_div2 ):
case( FOURCC_MP42 ):
case( FOURCC_mp42 ):
return( MSMPEG4v2_VIDEO_ES );
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( MSMPEG4v3_VIDEO_ES );
case( FOURCC_DIVX ):
case( FOURCC_divx ):
case( FOURCC_DIV1 ):
case( FOURCC_div1 ):
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 ):
return( MPEG4_VIDEO_ES );
default:
return( 0 );
}
}
#if 0
FILE *DumpAudio;
#endif
/*****************************************************************************
* AVIInit: check file and initializes AVI structures
......@@ -443,22 +576,17 @@ static int AVIInit( input_thread_t *p_input )
int i;
/* we need to seek to be able to readcorrectly */
if( !p_input->stream.b_seekable )
{
msg_Warn( p_input, "RIFF-AVI module discarded (not seekable)" );
return( -1 );
}
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) ) ) )
{
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;
/* FIXME I don't know what it's do, copied from ESInit */
p_avi_demux->b_seekable = ( ( p_input->stream.b_seekable )
&&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
/* Initialize access plug-in structures. */
if( p_input->i_mtu == 0 )
{
......@@ -504,7 +632,7 @@ static int AVIInit( input_thread_t *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 )
......@@ -567,7 +695,7 @@ static int AVIInit( input_thread_t *p_input )
msg_Err( p_input, "cannot find \"strh\"" );
return( -1 );
}
__AVI_Parse_Header( &p_info->header,
AVI_Parse_Header( &p_info->header,
p_strh->p_data->p_payload_start);
RIFF_DeleteChunk( p_input, p_strh );
......@@ -602,12 +730,12 @@ static int AVIInit( input_thread_t *p_input )
{
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 )
AVI_AudioGetType( p_info->audio_format.i_formattag );
if( !p_es->i_type )
{
msg_Err( p_input, "stream(%d,0x%x) not supported", i,
p_info->audio_format.i_formattag );
......@@ -617,12 +745,12 @@ static int AVIInit( input_thread_t *p_input )
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 )
AVI_VideoGetType( p_info->video_format.i_compression );
if( !p_es->i_type )
{
msg_Err( p_input, "stream(%d,%4.4s) not supported", i,
(char*)&p_info->video_format.i_compression);
......@@ -665,94 +793,35 @@ static int AVIInit( input_thread_t *p_input )
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 )
&&( p_avi_demux->avih.i_flags&AVIF_HASINDEX ) )
{
/* get index */
__AVI_GetIndex( p_input );
/* try to get i_idxoffset for each stream */
__AVI_UpdateIndexOffset( p_input );
/* 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 );
msg_Err( p_input, "cannot go in (\"movi\")" );
return( -1 );
}
}
else
{
msg_Warn( p_input, "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 )
{
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 ):
if( RIFF_FindChunk( p_input,
VLC_FOURCC('0'+i/10, '0'+i%10,'w','b' ),
p_movi ) == 0)
{
p_chunk = RIFF_ReadChunk( p_input );
}
break;
case( VIDEO_ES ):
if( (RIFF_FindChunk( p_input,
VLC_FOURCC('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,
VLC_FOURCC('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_pos = p_chunk->i_pos;
index.i_length = p_chunk->i_size;
__AVI_AddEntryIndex( p_info, &index );
msg_Dbg( p_input, "add index entry (%4.4s) (%d)",
(char*)&p_chunk->i_id, i );
}
}
#undef p_info
}
/* 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 );
msg_Err( p_input, "cannot go in (\"movi\")" );
return( -1 );
}
/* print informations on streams */
msg_Dbg( p_input, "AVIH: %d stream, flags %s%s%s%s%s%s ",
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":"",
p_avi_demux->avih.i_flags&AVIF_WASCAPTUREFILE?" CAPTUREFILE":"",
p_avi_demux->avih.i_flags&AVIF_COPYRIGHTED?" COPYRIGHTED":"" );
p_avi_demux->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
for( i = 0; i < p_avi_demux->i_streams; i++ )
{
......@@ -760,64 +829,62 @@ static int AVIInit( input_thread_t *p_input )
switch( p_info->p_es->i_cat )
{
case( VIDEO_ES ):
msg_Dbg( p_input, "video(%4.4s) %dx%d %dbpp %ffps (size %d)",
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,
p_info->header.i_samplesize );
(float)p_info->header.i_scale );
if( (p_avi_demux->p_info_video == NULL) )
{
p_avi_demux->p_info_video = p_info;
/* TODO add test to see if a decoder has been foud */
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 ):
msg_Dbg( p_input, "audio(0x%x) %d channels %dHz %dbits %ffps (size %d)",
msg_Dbg( p_input, "audio(0x%x) %d channels %dHz %dbits %d bytes",
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_avi_demux->p_info_audio == NULL) )
{
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;
case( UNKNOWN_ES ):
msg_Warn( p_input, "unhandled stream %d", i );
break;
}
#undef p_info
}
/* we select the first audio and video ES */
vlc_mutex_lock( &p_input->stream.stream_lock );
if( p_avi_demux->p_info_video != NULL )
{
input_SelectES( p_input, p_avi_demux->p_info_video->p_es );
/* it seems that it's useless to select es because there are selected
* by the interface but i'm not sure of that */
}
else
if( !p_avi_demux->p_info_video )
{
msg_Err( p_input, "no video stream found" );
msg_Warn( p_input, "no video stream found" );
}
if( p_avi_demux->p_info_audio != NULL )
{
input_SelectES( p_input, p_avi_demux->p_info_audio->p_es );
}
else
if( !p_avi_demux->p_info_audio )
{
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 );
#if 0
DumpAudio = fopen( "tmp.mp3", "w+" );
#endif
return( 0 );
}
......@@ -827,11 +894,37 @@ static int AVIInit( input_thread_t *p_input )
*****************************************************************************/
static void AVIEnd( input_thread_t *p_input )
{
#if 0
fclose( DumpAudio );
#endif
__AVIFreeDemuxData( p_input );
return;
}
/*****************************************************************************
* Function to convert pts to chunk or byte
*****************************************************************************/
static inline mtime_t AVI_PTSToChunk( AVIStreamInfo_t *p_info,
mtime_t i_pts )
{
return( (mtime_t)((double)i_pts *
(double)p_info->header.i_rate /
(double)p_info->header.i_scale /
(double)1000000.0 ) );
}
static inline mtime_t AVI_PTSToByte( AVIStreamInfo_t *p_info,
mtime_t i_pts )
{
return( (mtime_t)((double)i_pts *
(double)p_info->header.i_samplesize *
(double)p_info->header.i_rate /
(double)p_info->header.i_scale /
(double)1000000.0 ) );
}
static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
{
/* p_info->p_index[p_info->i_idxposc] need to be valid !! */
......@@ -855,440 +948,552 @@ static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
}
/*****************************************************************************
* 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
*****************************************************************************/
static int __AVI_NextIndexEntry( input_thread_t *p_input,
AVIStreamInfo_t *p_info )
{
AVIIndexEntry_t index;
riffchunk_t *p_chunk;
AVIStreamInfo_t *p_info_tmp;
int i;
int i_idxposc;
int b_inc = 0;
demux_data_avi_file_t *p_avi_demux =
(demux_data_avi_file_t*)p_input->p_demux_data;
p_info->i_idxposc++;
/* 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 )
{
if( p_info->i_idxposc < p_info->i_idxnb )
int i_read;
data_packet_t *p_data;
if( !(*pp_pes = input_NewPES( p_input->p_method_data ) ) )
{
return( 0 );
}
if( p_info->i_idxposc > p_info->i_idxnb )
if( ( i_size&1 )&&( b_pad ) )
{
return( -1 );
b_pad = 1;
i_size++;
}
p_info->i_idxposc--;
/* create entry on the fly */
/* search for the more advance stream and parse from it for all streams*/
p_info_tmp = p_info;
for( i = 0; i < p_avi_demux->i_streams; i++ )
else
{
#define p_info_i p_avi_demux->pp_info[i]
if( ( p_info_i->p_index )
&& ( p_info_i->p_index[p_info_i->i_idxnb - 1].i_pos >
p_info_tmp->p_index[p_info_tmp->i_idxnb - 1].i_pos ) )
{
p_info_tmp = p_info_i;
}
#undef p_info_i
b_pad = 0;
}
/* go to last defined entry */
i_idxposc = p_info_tmp->i_idxposc; /* save p_info_tmp->i_idxposc */
p_info_tmp->i_idxposc = p_info_tmp->i_idxnb - 1;
__AVI_SeekToChunk( p_input, p_info_tmp );
p_info_tmp->i_idxposc = i_idxposc;
if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
if( !i_size )
{
p_info->i_idxposc++;
return( -1 );
(*pp_pes)->p_first = (*pp_pes)->p_last = NULL;
(*pp_pes)->i_nb_data = 0;
(*pp_pes)->i_pes_size = 0;
return( 0 );
}
/* save idxpos of p_info */
/* now parse for all stream and stop when reach next chunk for p_info */
for( i = 0; (i < 15)||(!b_inc); i++)
do
{
int i_number;
u16 i_type;
if( (p_chunk = RIFF_ReadChunk( p_input )) == NULL )
i_read = input_SplitBuffer(p_input, &p_data, i_size -
(*pp_pes)->i_pes_size );
if( i_read < 0 )
{
p_info->i_idxposc++;
return( b_inc == 1 ? 0 : -1 );
return( (*pp_pes)->i_pes_size );
}
index.i_id = p_chunk->i_id;
index.i_flags = AVIIF_KEYFRAME;
index.i_pos = 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->p_index[p_info_i->i_idxnb - 1].i_pos +
p_info_i->p_index[p_info_i->i_idxnb - 1].i_length + 8<=
index.i_pos )
&&( __AVIGetESTypeFromTwoCC( i_type ) == p_info_i->i_cat ) )
if( !(*pp_pes)->p_first )
{
__AVI_AddEntryIndex( p_info_i, &index );
if( (p_info_i == p_info)&&(!b_inc) )
{
b_inc = 1;
}
(*pp_pes)->p_first =
(*pp_pes)->p_last = p_data;
(*pp_pes)->i_nb_data = 1;
(*pp_pes)->i_pes_size = i_read;
}
#undef p_info_i
if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
else
{
p_info->i_idxposc++;
return( b_inc == 1 ? 0 : -1 );
(*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--;
}
p_info->i_idxposc++;
return( 0 );
return( i_size );
}
/*****************************************************************************
* Functions to acces streams data
* Uses it, because i plane to read unseekable stream
* Don't work for the moment for unseekable stream
*****************************************************************************/
/* __AVI_ReadStreamChunkInPES; load an entire chunk
__AVI_ReadStreamBytesInPES; load bytes
__AVI_GoToStreamChunk; go to chunk
__AVI_GoToStreamBytes; go to bytes in the all stream
not seekable file is not yet supported
*/
static int __AVI_GoToStreamChunk( input_thread_t *p_input,
AVIStreamInfo_t *p_info,
int i_chunk )
/* XXX FIXME up to now, we assume that all chunk are one after one */
/* XXX Don't use this function directly ! XXX */
static int __AVI_GetChunk( input_thread_t *p_input,
AVIStreamInfo_t *p_info,
int b_load )
{
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;
AVIStreamInfo_t *p_other;
int i_other_ck; /* dernier ck lu pour p_other */
int b_parse;
if( !p_input->stream.b_seekable )
#define p_video p_avi_demux->p_info_video
#define p_audio p_avi_demux->p_info_audio
#define p_info_i p_avi_demux->pp_info[i]
while( p_info->p_pes_first )
{
msg_Err( p_input, "need the ability to seek in stream" );
return( -1 );
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->i_idxposb < p_info->p_pes_first->i_posb + p_info->p_pes_first->p_pes->i_pes_size ) )
{
return( 1 );
}
else
{
AVI_PESBuffer_Drop( p_input->p_method_data, p_info );
}
}
if( p_info->p_index != NULL )
/* up to now we handle only one audio and one video stream at the same time */
p_other = (p_info == p_video ) ? p_audio : p_video ;
if( p_other )
{
i_other_ck = p_other->p_pes_last ? p_other->p_pes_last->i_posc : p_other->i_idxposc - 1;
}
else
{
i_other_ck = -1;
}
/* XXX -1 --> aucun lu */
if( p_info->i_idxposc >= p_info->i_idxnb )
{
/* invalid index for p_info -> read one after one, load all ck
for p_other until the one for p_info */
b_parse = 1;
}
else
if( p_info->i_idxposb )
{
b_parse = 0;
}
else
if( !p_other )
{
b_parse = 0;
}
else
if( ( i_other_ck +1 >= p_other->i_idxnb )||( i_other_ck == -1 )||( p_info->i_idxposc == 0) )
/* XXX see if i_other_ck +1 >= p_other->i_idxnb if it is necessary */
{
if( i_chunk >= p_info->i_idxnb )
b_parse = 1;
}
else
{
/* Avoid : * read an already read ck
* create a discontinuity */
if( p_info->p_index[p_info->i_idxposc].i_pos < p_other->p_index[i_other_ck].i_pos )
{
p_info->i_idxposc = p_info->i_idxnb-1;
while( p_info->i_idxposc < i_chunk )
{
if( __AVI_NextIndexEntry( p_input, p_info ) != 0)
{
return( -1 );
}
}
b_parse = 0;
}
else
{
p_info->i_idxposc = i_chunk;
if( p_info->p_index[p_info->i_idxposc-1].i_pos > p_other->p_index[i_other_ck + 1].i_pos )
{
b_parse = 0;
}
else
{
b_parse = 1;
}
}
/* now do we have valid index for the chunk */
__RIFF_TellPos( p_input, &u32_pos );
}
/* XXX XXX just for test */
// b_parse = 0;
/* XXX XXX */
if( !b_parse )
{
pes_packet_t *p_pes;
int i_length;
// msg_Warn( p_input, "parsing 0" );
i_length = __MIN( p_info->p_index[p_info->i_idxposc].i_length - p_info->i_idxposb,
BUFFER_MAXSPESSIZE );
i_pos = (off_t)p_info->p_index[i_chunk].i_pos;
if( i_pos != u32_pos )
AVI_SeekAbsolute( p_input,
(off_t)p_info->p_index[p_info->i_idxposc].i_pos +
p_info->i_idxposb + 8);
/* FIXME lit align donc risque de lire un car de trop si position non align */
if( !b_load )
{
p_input->pf_seek( p_input, i_pos );
input_AccessReinit( p_input );
return( 1 );
}
p_info->i_idxposb = 0;
return( 0 );
if( __AVI_GetDataInPES( p_input,
&p_pes,
i_length ,
0) != i_length )
{
msg_Err( p_input, "%d ERROR", p_info->i_cat );
return( 0 );
}
AVI_PESBuffer_Add( p_input->p_method_data,
p_info,
p_pes,
p_info->i_idxposc,
p_info->i_idxposb );
return( 1 );
}
else
{
return( -1 );
}
}
int i;
off_t i_posmax;
static int __AVI_GoToStreamBytes( input_thread_t *p_input,
AVIStreamInfo_t *p_info,
int i_byte )
{
u32 u32_pos;
off_t i_pos;
if( !p_input->stream.b_seekable )
{
msg_Err( p_input, "need the ability to seek in stream" );
return( -1 );
}
// msg_Warn( p_input, "parsing 1" );
if( p_info->i_idxposc - 1 >= 0 )
{
i_posmax = p_info->p_index[p_info->i_idxposc - 1].i_pos +
__EVEN( p_info->p_index[p_info->i_idxposc - 1].i_length ) + 8;
}
else
{
i_posmax = p_avi_demux->p_movi->i_pos + 12;
}
if( i_other_ck >= 0 )
{
i_posmax = __MAX( i_posmax,
p_other->p_index[i_other_ck].i_pos +
__EVEN( p_other->p_index[i_other_ck].i_length ) + 8 );
}
AVI_SeekAbsolute( p_input, i_posmax );
/* now do we have valid index for the chunk */
if( p_info->p_index != NULL )
{
if( p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal +
p_info->p_index[p_info->i_idxnb - 1].i_length <= i_byte)
for( ;; )
{
p_info->i_idxposc = p_info->i_idxnb - 1;
while( p_info->p_index[p_info->i_idxposc].i_lengthtotal +
p_info->p_index[p_info->i_idxposc].i_length <= i_byte)
riffchunk_t *p_ck;
int i_ck;
int i_type;
if( !(p_ck = RIFF_ReadChunk( p_input )) )
{
if( __AVI_NextIndexEntry( p_input, p_info ) != 0)
return( 0 );
}
if( p_ck->i_id == FOURCC_LIST )
{
if( p_ck->i_type == FOURCC_rec )
{
return( -1 );
RIFF_DescendChunk( p_input );
continue;
}
}
}
else
{
/* uses dichototmie to be fast enougth */
int i_idxposc = p_info->i_idxposc;
int i_idxmax = p_info->i_idxnb;
int i_idxmin = 0;
for( ;; )
AVI_ParseStreamHeader( p_ck->i_id, &i, &i_type );
// msg_Dbg( p_input, "ck: %4.4s", &p_ck->i_id );
if( ( i >= p_avi_demux->i_streams )
||(__AVI_GetESTypeFromTwoCC( i_type ) != p_info_i->i_cat ) )
{
if( p_info->p_index[i_idxposc].i_lengthtotal > i_byte )
if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
{
i_idxmax = i_idxposc ;
i_idxposc = ( i_idxmin + i_idxposc ) / 2 ;
return( 0 );
}
}
else
{
if( ( !p_info_i->i_idxnb )
||( p_info_i->p_index[p_info_i->i_idxnb-1].i_pos +
__EVEN( p_info_i->p_index[p_info_i->i_idxnb-1].i_length ) + 8 <=
p_ck->i_pos ) )
{
/* add a new entry */
AVIIndexEntry_t index;
index.i_id = p_ck->i_id;
index.i_flags = AVIIF_KEYFRAME;
index.i_pos = p_ck->i_pos;
index.i_length = p_ck->i_size;
__AVI_AddEntryIndex( p_info_i, &index );
}
RIFF_DeleteChunk( p_input, p_ck );
/* load the packet */
if( p_info_i == p_info )
{
/* special case with broken index */
i_ck = p_info->i_idxposc > p_info->i_idxnb - 1 ? p_info->i_idxnb - 1 : p_info->i_idxposc;
}
else
{
if( p_info->p_index[i_idxposc].i_lengthtotal +
p_info->p_index[i_idxposc].i_length <= i_byte)
i_ck = p_info_i->p_pes_last ? p_info_i->p_pes_last->i_posc + 1 : p_info_i->i_idxposc;
}
/* TODO check if buffer overflow and if so seek to get the good ck if possible */
/* check if last ck was troncated */
if( ( b_load )
&&( ( p_info_i == p_audio )||( p_info_i == p_video ) )
&&( ( !p_info_i->p_pes_last )
||( p_info_i->p_pes_last->p_pes->i_pes_size != BUFFER_MAXSPESSIZE ) ) )
{
pes_packet_t *p_pes;
int i_offset = ( ( p_info_i == p_info )&&( i_ck == p_info->i_idxposc ) ) ?
p_info->i_idxposb : 0;
int i_length = __MIN( p_info_i->p_index[i_ck].i_length - i_offset,
BUFFER_MAXSPESSIZE );
AVI_SeekAbsolute( p_input,
(off_t)p_info_i->p_index[i_ck].i_pos +
i_offset + 8);
if( __AVI_GetDataInPES( p_input, &p_pes, i_length,1 ) != i_length)
{
i_idxmin = i_idxposc ;
i_idxposc = (i_idxmax + i_idxposc ) / 2 ;
return( 0 );
}
else
AVI_PESBuffer_Add( p_input->p_method_data,
p_info_i,
p_pes,
i_ck,
i_offset );
if( ( p_info_i == p_info )
&&( p_info->i_idxposc == i_ck ) )
{
p_info->i_idxposc = i_idxposc;
break;
}
return( 1 );
}
}
else
{
RIFF_NextChunk( p_input, p_avi_demux->p_movi );
if( ( p_info_i == p_info )
&&( p_info->i_idxposc == i_ck ) )
{
return( 1 );
}
}
}
}
}
p_info->i_idxposb = i_byte -
p_info->p_index[p_info->i_idxposc].i_lengthtotal;
i_pos = (off_t)p_info->p_index[p_info->i_idxposc].i_pos +
p_info->i_idxposb + 8;
__RIFF_TellPos( p_input, &u32_pos );
if( u32_pos != i_pos )
#undef p_video
#undef p_audio
#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
{
return( __AVI_GetChunk( p_input, p_info, 0) );
}
}
/* 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( ;; )
{
p_input->pf_seek( p_input, i_pos );
input_AccessReinit( p_input );
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 );
}
}
}
return( 0 );
}
else
{
return( -1 );
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 )
static pes_packet_t *AVI_ReadStreamChunkInPES( input_thread_t *p_input,
AVIStreamInfo_t *p_info )
{
pes_packet_t *p_pes;
if( p_info->i_idxposc >= p_info->i_idxnb )
if( p_info->i_idxposc > p_info->i_idxnb )
{
return( NULL );
}
/*- XXX avio is sh*t sometime chunk size is broken, and
we must choose index sie */
if( ( __AVI_GoToStreamChunk( p_input, p_info, p_info->i_idxposc ) != 0 )
||( RIFF_LoadChunkDataInPES( p_input,
&p_pes,
p_info->p_index[p_info->i_idxposc].i_length ) != 0 ) )
/* 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 );
}
else
{
__AVI_NextIndexEntry( p_input, p_info);
p_info->i_idxposb = 0;
return( p_pes );
}
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 )
static pes_packet_t *AVI_ReadStreamBytesInPES( input_thread_t *p_input,
AVIStreamInfo_t *p_info,
int i_byte )
{
pes_packet_t *p_pes = NULL;
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 ) ) == NULL )
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( p_info->i_idxposc >= p_info->i_idxnb )
{
input_DeletePES( p_input->p_method_data, p_pes );
return( NULL );
}
if( __AVI_GoToStreamBytes( p_input, p_info,
p_info->p_index[p_info->i_idxposc].i_lengthtotal +
p_info->i_idxposb ) != 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 = input_SplitBuffer(p_input, &p_data,
__MIN( i_byte,
p_info->p_index[p_info->i_idxposc].i_length
- p_info->i_idxposb ) );
if( i_read <= 0 )
{
input_DeletePES( p_input->p_method_data, p_pes );
return( NULL );
}
p_pes->i_nb_data++;
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_pes_size += i_read;
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 );
i_byte -= i_read;
p_info->i_idxposb += i_read;
AVI_PESBuffer_Drop( p_input->p_method_data, p_info );
i_byte -= i_read;
i_count += i_read;
if( p_info->i_idxposb >= p_info->p_index[p_info->i_idxposc].i_length )
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 = 0;
if( __AVI_NextIndexEntry( p_input, p_info) != 0 )
{
input_DeletePES( p_input->p_method_data, p_pes );
return( NULL );
}
p_info->i_idxposb -= p_info->p_index[p_info->i_idxposc].i_length;
p_info->i_idxposc++;
}
};
}
#if 0
fwrite( p_data->p_payload_start, 1, i_count, DumpAudio );
#endif
return( p_pes );
}
/*****************************************************************************
* Function to convert pts to chunk or byte
*****************************************************************************/
static inline mtime_t __AVI_PTSToChunk( AVIStreamInfo_t *p_info,
mtime_t i_pts )
{
return( (mtime_t)((double)i_pts *
(double)p_info->header.i_rate /
(double)p_info->header.i_scale /
(double)1000000.0 ) );
}
static inline mtime_t __AVI_PTSToByte( AVIStreamInfo_t *p_info,
mtime_t i_pts )
{
return( (mtime_t)((double)i_pts *
(double)p_info->header.i_samplesize *
(double)p_info->header.i_rate /
(double)p_info->header.i_scale /
(double)1000000.0 ) );
}
/* try to realign after a seek */
static int AVI_ReAlign( input_thread_t *p_input )
static int AVI_ReAlign( input_thread_t *p_input,
AVIStreamInfo_t *p_info )
{
u32 u32_pos;
int i;
off_t i_pos;
int b_after = 0;
AVIStreamInfo_t *p_info;
demux_data_avi_file_t *p_avi_demux =
(demux_data_avi_file_t*)p_input->p_demux_data;
p_info = (p_avi_demux->p_info_video != NULL ) ?
p_avi_demux->p_info_video :
p_avi_demux->p_info_audio;
__RIFF_TellPos( p_input, &u32_pos );
i_pos = (off_t)u32_pos;
if( i_pos <= p_info->p_index[0].i_pos )
{
/* before beginning of stream */
if( !p_info->header.i_samplesize )
{
__AVI_GoToStreamChunk( p_input,
p_info,
0 );
}
else
{
__AVI_GoToStreamBytes( p_input,
p_info,
0);
}
return( 0 );
}
if( (p_info->p_index[p_info->i_idxposc].i_pos <= i_pos)
&& ( i_pos < p_info->p_index[p_info->i_idxposc].i_pos +
p_info->p_index[p_info->i_idxposc].i_length ) )
{
/* FIXME if master == audio and samplesize != 0 */
/* don't work with big chunk */
/* don't do anything we are in the current chunk */
return( 0 );
}
if( i_pos < p_info->p_index[p_info->i_idxposc].i_pos )
for( i = 0; i < p_avi_demux->i_streams; i++ )
{
b_after = 0;
AVI_PESBuffer_Flush( p_input->p_method_data, p_avi_demux->pp_info[i] );
}
else
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 ) )
{
b_after = 1;
/* 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 */
p_info->i_idxposc--;
AVI_SetStreamChunk( p_input, p_info, p_info->i_idxposc - 1 );
}
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_NextIndexEntry( p_input, p_info ) != 0 )
{
return( -1 );
}
AVI_SetStreamChunk( p_input, p_info, p_info->i_idxposc + 1 );
}
/* search nearest key frame */
if( ( !p_info->header.i_samplesize ) && ( p_info->i_cat == VIDEO_ES ) )
/* search nearest key frame, only for video */
if( p_info->i_cat == VIDEO_ES )
{
/* only for chunk stream */
if( b_after )
{
while(!(p_info->p_index[p_info->i_idxposc].i_flags&AVIIF_KEYFRAME) )
{
if( __AVI_NextIndexEntry( p_input, p_info ) != 0 )
{
break;
}
AVI_SetStreamChunk( p_input, p_info, p_info->i_idxposc + 1 );
}
}
else
......@@ -1296,13 +1501,11 @@ static int AVI_ReAlign( input_thread_t *p_input )
while( ( p_info->i_idxposc > 0 ) &&
(!(p_info->p_index[p_info->i_idxposc].i_flags&AVIIF_KEYFRAME)) )
{
p_info->i_idxposc--;
AVI_SetStreamChunk( p_input, p_info, p_info->i_idxposc - 1 );
}
}
}
__AVI_GoToStreamChunk( p_input, p_info, p_info->i_idxposc );
return( 0 );
return( 1 );
}
/* make difference between audio and video pts as little as possible */
......@@ -1310,6 +1513,7 @@ static void AVI_SynchroReInit( input_thread_t *p_input )
{
demux_data_avi_file_t *p_avi_demux =
(demux_data_avi_file_t*)p_input->p_demux_data;
#define p_info_video p_avi_demux->p_info_video
#define p_info_audio p_avi_demux->p_info_audio
if( ( p_info_video )&&( p_info_audio ) )
......@@ -1318,19 +1522,20 @@ static void AVI_SynchroReInit( input_thread_t *p_input )
/*don't care of AVIF_KEYFRAME */
if( !p_info_audio->header.i_samplesize )
{
int i_chunk = __AVI_PTSToChunk( p_info_audio,
int i_chunk = AVI_PTSToChunk( p_info_audio,
AVI_GetPTS( p_info_video ));
__AVI_GoToStreamChunk( p_input,
p_info_audio,
i_chunk );
AVI_SetStreamChunk( p_input,
p_info_audio,
i_chunk );
}
else
{
int i_byte = __AVI_PTSToByte( p_info_audio,
int i_byte = AVI_PTSToByte( p_info_audio,
AVI_GetPTS( p_info_video ) ) ;
__AVI_GoToStreamBytes( p_input,
p_info_audio,
i_byte );
AVI_SetStreamBytes( p_input,
p_info_audio,
i_byte );
}
}
#undef p_info_video
......@@ -1352,7 +1557,6 @@ static pes_packet_t *AVI_GetFrameInPES( input_thread_t *p_input,
pes_packet_t *p_pes_first = NULL;
mtime_t i_pts;
/* we now that p_info != NULL */
if( i_dpts < 1000 )
{
return( NULL ) ;
......@@ -1360,16 +1564,14 @@ static pes_packet_t *AVI_GetFrameInPES( input_thread_t *p_input,
if( !p_info->header.i_samplesize )
{
/* stream is chunk based , easy */
int i_chunk = __MAX( __AVI_PTSToChunk( p_info, i_dpts), 1 );
/* at least one frame */
/* read them */
int i_chunk = __MAX( AVI_PTSToChunk( p_info, i_dpts), 1 );
p_pes_first = NULL;
for( i = 0; i < i_chunk; i++ )
{
/* get pts while is valid */
i_pts = AVI_GetPTS( p_info );
p_pes_tmp = __AVI_ReadStreamChunkInPES( p_input, p_info );
i_pts = AVI_GetPTS( p_info ); /* FIXME will segfault with bad index */
p_pes_tmp = AVI_ReadStreamChunkInPES( p_input, p_info );
if( !p_pes_tmp )
{
......@@ -1391,18 +1593,15 @@ static pes_packet_t *AVI_GetFrameInPES( input_thread_t *p_input,
else
{
/* stream is byte based */
int i_byte = __AVI_PTSToByte( p_info, i_dpts);
if( !i_byte )
int i_byte = AVI_PTSToByte( p_info, i_dpts);
if( i_byte < 50 ) /* to avoid some problem with audio */
{
return( NULL );
}
/* at least one Kbyte */
/*i_byte = __MIN( 1024*1000, i_byte ); *//* but no more than 1000ko */
i_pts = AVI_GetPTS( p_info );
i_pts = AVI_GetPTS( p_info ); /* FIXME will segfault with bad index */
p_pes = AVI_ReadStreamBytesInPES( p_input, p_info, i_byte);
p_pes = __AVI_ReadStreamBytesInPES( p_input, p_info, i_byte);
if( p_pes != NULL )
if( p_pes )
{
p_pes->i_pts = i_pts;
}
......@@ -1431,7 +1630,7 @@ static inline void AVI_DecodePES( input_thread_t *p_input,
p_pes->i_pts * 9/100);
input_DecodePES( p_info->p_es->p_decoder_fifo, p_pes );
p_pes = p_pes_next;
};
}
}
......@@ -1493,7 +1692,7 @@ static int AVIDemux( input_thread_t *p_input )
p_info_master = p_avi_demux->p_info_audio;
p_info_slave = NULL;
}
if( !p_info_master )
{
msg_Err( p_input, "no stream selected" );
......@@ -1507,7 +1706,7 @@ static int AVIDemux( input_thread_t *p_input )
/* first wait for empty buffer, arbitrary time */
msleep( DEFAULT_PTS_DELAY );
/* then try to realign in stream */
if( AVI_ReAlign( p_input ) != 0 )
if( !AVI_ReAlign( p_input, p_info_master ) )
{
return( 0 ); /* assume EOF */
}
......@@ -1562,20 +1761,26 @@ static int AVIDemux( input_thread_t *p_input )
p_info_master,
100000 ); /* 100 ms */
AVI_DecodePES( p_input,
p_info_master,
p_pes);
if( p_info_slave )
{
p_pes = AVI_GetFrameInPES( p_input,
p_info_slave,
AVI_GetPTS( p_info_master ) -
AVI_GetPTS( p_info_slave));
pes_packet_t *p_pes_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 );
p_pes_slave );
}
AVI_DecodePES( p_input,
p_info_master,
p_pes);
/* at the end ? */
return( p_info_master->i_idxposc >= p_info_master->i_idxnb ? 0 : 1 );
return( p_pes ? 1 : 0 );
/* return( p_info_master->i_idxposc > p_info_master->i_idxnb ? 0 : 1 );*/
}
......@@ -2,7 +2,7 @@
* avi.h : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: avi.h,v 1.6 2002/05/13 21:55:30 fenrir Exp $
* $Id: avi.h,v 1.7 2002/06/26 23:11:12 fenrir Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
......@@ -116,6 +116,16 @@ typedef struct AVIIndexEntry_s
u32 i_lengthtotal;
} AVIIndexEntry_t;
typedef struct AVIESBuffer_s
{
struct AVIESBuffer_s *p_next;
pes_packet_t *p_pes;
int i_posc;
int i_posb;
} AVIESBuffer_t;
typedef struct AVIStreamInfo_s
{
......@@ -134,8 +144,15 @@ typedef struct AVIStreamInfo_s
AVIIndexEntry_t *p_index;
int i_idxnb;
int i_idxmax;
int i_idxposc; /* numero of chunk */
int i_idxposb; /* byte in the current chunk */
/* add some buffering */
AVIESBuffer_t *p_pes_first;
AVIESBuffer_t *p_pes_last;
int i_pes_count;
int i_pes_totalsize;
} AVIStreamInfo_t;
typedef struct demux_data_avi_file_s
......@@ -147,6 +164,8 @@ typedef struct demux_data_avi_file_s
riffchunk_t *p_movi;
riffchunk_t *p_idx1;
int b_seekable;
/* Info extrated from avih */
MainAVIHeader_t avih;
......
/*****************************************************************************
* libioRIFF.h : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: libioRIFF.h,v 1.1 2002/06/26 23:11:12 fenrir Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
typedef struct riffchunk_s
{
u32 i_id;
u32 i_size;
u32 i_type;
u32 i_pos;
data_packet_t *p_data;
} riffchunk_t;
int __RIFF_TellPos( input_thread_t *p_input, u32 *pos );
int __RIFF_SkipBytes(input_thread_t * p_input,int nb);
void RIFF_DeleteChunk( input_thread_t *p_input, riffchunk_t *p_chunk );
riffchunk_t *RIFF_ReadChunk(input_thread_t * p_input);
int RIFF_NextChunk( input_thread_t * p_input,riffchunk_t *p_rifffather);
int RIFF_DescendChunk(input_thread_t * p_input);
int RIFF_AscendChunk(input_thread_t * p_input ,riffchunk_t *p_riff);
int RIFF_FindChunk(input_thread_t * p_input,
u32 i_id,riffchunk_t *p_rifffather);
int RIFF_GoToChunkData(input_thread_t * p_input);
int RIFF_LoadChunkData(input_thread_t * p_input,
riffchunk_t *p_riff );
int RIFF_LoadChunkDataInPES(input_thread_t * p_input,
pes_packet_t **pp_pes,
int i_size_index);
int RIFF_GoToChunk(input_thread_t * p_input,
riffchunk_t *p_riff);
int RIFF_TestFileHeader( input_thread_t * p_input,
riffchunk_t ** pp_riff,
u32 i_type );
int RIFF_FindAndLoadChunk( input_thread_t * p_input,
riffchunk_t *p_riff,
riffchunk_t **pp_fmt,
u32 i_type );
int RIFF_FindAndGotoDataChunk( input_thread_t * p_input,
riffchunk_t *p_riff,
riffchunk_t **pp_data,
u32 i_type );
int RIFF_FindListChunk( input_thread_t *p_input,
riffchunk_t **pp_riff,
riffchunk_t *p_rifffather,
u32 i_type );
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment