* avi.c : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: avi.c,v 1.6 2002/10/15 00:55:07 fenrir Exp $
+ * $Id: avi.c,v 1.7 2002/10/27 15:37:16 fenrir Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
#include "video.h"
-#include "libioRIFF.h"
#include "libavi.h"
#include "avi.h"
"force index creation" );
set_description( "avi demuxer" );
- set_capability( "demux", 160 );
+ set_capability( "demux", 212 );
set_callbacks( AVIInit, __AVIEnd );
vlc_module_end();
/*****************************************************************************
* Some usefull functions to manipulate memory
*****************************************************************************/
-static int __AVI_GetDataInPES( input_thread_t *, pes_packet_t **, int, int );
static u16 GetWLE( byte_t *p_buff )
{
#define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) )
+/* read data in a pes */
+static int input_ReadInPES( input_thread_t *p_input,
+ pes_packet_t **pp_pes,
+ int i_size )
+{
+ pes_packet_t *p_pes;
+ data_packet_t *p_data;
+
+
+ if( !(p_pes = input_NewPES( p_input->p_method_data ) ) )
+ {
+ pp_pes = NULL;
+ return( -1 );
+ }
+
+ *pp_pes = p_pes;
+
+ if( !i_size )
+ {
+ p_pes->p_first =
+ p_pes->p_last =
+ input_NewPacket( p_input->p_method_data, 0 );
+ p_pes->i_nb_data = 1;
+ p_pes->i_pes_size = 0;
+ return( 0 );
+ }
+
+ p_pes->i_nb_data = 0;
+ p_pes->i_pes_size = 0;
+
+ while( p_pes->i_pes_size < i_size )
+ {
+ int i_read;
+
+ i_read = input_SplitBuffer(p_input,
+ &p_data,
+ __MIN( i_size -
+ p_pes->i_pes_size, 1024 ) );
+ if( i_read <= 0 )
+ {
+ return( p_pes->i_pes_size );
+ }
+
+ if( !p_pes->p_first )
+ {
+ p_pes->p_first = p_data;
+ }
+ else
+ {
+ p_pes->p_last->p_next = p_data;
+ }
+ p_pes->p_last = p_data;
+ p_pes->i_nb_data++;
+ p_pes->i_pes_size += i_read;
+ }
+
+
+ return( p_pes->i_pes_size );
+}
+
/* Test if it seems that it's a key frame */
static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, u8 *p_byte )
{
return( VLC_FOURCC( 'u', 'n', 'd', 'f' ) );
}
}
-/*****************************************************************************
- * Data and functions to manipulate pes buffer
- *****************************************************************************/
-#define BUFFER_MAXTOTALSIZE 500*1024 /* 1/2 Mo */
-#define BUFFER_MAXSPESSIZE 200*1024
-static int AVI_PESBuffer_IsFull( AVIStreamInfo_t *p_info )
-{
- return( p_info->i_pes_totalsize > BUFFER_MAXTOTALSIZE ? 1 : 0);
-}
-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 AVI_ParseStreamHeader( u32 i_id, int *pi_number, int *pi_type )
{
#undef SET_PTR
}
-typedef struct avi_packet_s
-{
- u32 i_fourcc;
- off_t i_pos;
- u32 i_size;
- u32 i_type; // only for AVIFOURCC_LIST
- u8 i_peek[8]; //first 8 bytes
-
- int i_stream;
- int i_cat;
-} avi_packet_t;
-
static int AVI_PacketGetHeader( input_thread_t *p_input, avi_packet_t *p_pk )
{
u8 *p_peek;
avi_packet_t *p_pk,
pes_packet_t **pp_pes )
{
+ int i_size;
+ int b_pad;
- if( __AVI_GetDataInPES( p_input, pp_pes, p_pk->i_size + 8, 1)
- != p_pk->i_size + 8)
+ i_size = __EVEN( p_pk->i_size + 8 );
+ b_pad = ( i_size != p_pk->i_size + 8 );
+
+ if( input_ReadInPES( p_input, pp_pes, i_size ) != i_size )
{
return( 0 );
}
(*pp_pes)->p_first->p_payload_start += 8;
(*pp_pes)->i_pes_size -= 8;
+
+ if( b_pad )
+ {
+ (*pp_pes)->p_last->p_payload_end--;
+ (*pp_pes)->i_pes_size--;
+ }
+
return( 1 );
}
}
-static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
+static void __AVI_AddEntryIndex( avi_stream_t *p_info,
AVIIndexEntry_t *p_index)
{
if( p_info->p_index == NULL )
p_info->p_index[p_info->i_idxnb] = *p_index;
p_info->i_idxnb++;
+
+}
+
+static void AVI_IndexAddEntry( demux_sys_t *p_avi,
+ int i_stream,
+ AVIIndexEntry_t *p_index)
+{
+ __AVI_AddEntryIndex( p_avi->pp_info[i_stream],
+ p_index );
+ if( p_avi->i_movi_lastchunk_pos < p_index->i_pos )
+ {
+ p_avi->i_movi_lastchunk_pos = p_index->i_pos;
+ }
}
static void AVI_IndexLoad( input_thread_t *p_input )
{
AVIIndexEntry_t index;
index.i_id = p_idx1->entry[i_index].i_fourcc;
- index.i_flags = p_idx1->entry[i_index].i_flags&(~AVIIF_FIXKEYFRAME);
+ index.i_flags =
+ p_idx1->entry[i_index].i_flags&(~AVIIF_FIXKEYFRAME);
index.i_pos = p_idx1->entry[i_index].i_pos + i_offset;
index.i_length = p_idx1->entry[i_index].i_length;
- __AVI_AddEntryIndex( p_avi->pp_info[i_stream],
- &index );
+ AVI_IndexAddEntry( p_avi, i_stream, &index );
}
}
for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
AVI_GetKeyFlag(p_avi->pp_info[pk.i_stream]->i_codec, pk.i_peek);
index.i_pos = pk.i_pos;
index.i_length = pk.i_size;
- __AVI_AddEntryIndex( p_avi->pp_info[pk.i_stream],
- &index );
+ AVI_IndexAddEntry( p_avi, pk.i_stream, &index );
}
else
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
p_stream->i_activated = p_stream->p_es->p_decoder_fifo ? 1 : 0;
-
- AVI_StreamSeek( p_input, p_avi, i_stream, p_avi->i_time );
+ if( p_stream->i_activated )
+ {
+ AVI_StreamSeek( p_input, p_avi, i_stream, p_avi->i_time );
+ }
return( p_stream->i_activated );
#undef p_stream
return;
}
-// AVI_PESBuffer_Flush( p_input->p_method_data, p_stream );
-
if( p_stream->p_es->p_decoder_fifo )
{
vlc_mutex_lock( &p_input->stream.stream_lock );
int i;
demux_sys_t *p_avi = p_input->p_demux_data ;
- if( p_avi->p_movi )
- RIFF_DeleteChunk( p_input, p_avi->p_movi );
if( p_avi->pp_info )
{
for( i = 0; i < p_avi->i_streams; i++ )
if( p_avi->pp_info[i]->p_index )
{
free( p_avi->pp_info[i]->p_index );
- AVI_PESBuffer_Flush( p_input->p_method_data,
- p_avi->pp_info[i] );
}
free( p_avi->pp_info[i] );
}
es_descriptor_t *p_es = NULL; /* avoid warning */
int i;
+ int b_stream_audio, b_stream_video;
+
p_input->pf_demux = AVIDemux_Seekable;
if( !AVI_TestFile( p_input ) )
{
memset( p_avi, 0, sizeof( demux_sys_t ) );
p_avi->i_time = 0;
p_avi->i_pcr = 0;
- p_avi->i_rate = DEFAULT_RATE;
p_avi->b_seekable = ( ( p_input->stream.b_seekable )
&&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
/* *** for unseekable stream, automaticaly use AVIDemux_interleaved *** */
/* now read info on each stream and create ES */
p_avi->pp_info = calloc( p_avi->i_streams,
- sizeof( AVIStreamInfo_t* ) );
+ sizeof( avi_stream_t* ) );
memset( p_avi->pp_info,
0,
- sizeof( AVIStreamInfo_t* ) * p_avi->i_streams );
+ sizeof( avi_stream_t* ) * p_avi->i_streams );
for( i = 0 ; i < p_avi->i_streams; i++ )
{
int i_init_size;
void *p_init_data;
#define p_info p_avi->pp_info[i]
- p_info = malloc( sizeof(AVIStreamInfo_t ) );
- memset( p_info, 0, sizeof( AVIStreamInfo_t ) );
+ p_info = malloc( sizeof(avi_stream_t ) );
+ memset( p_info, 0, sizeof( avi_stream_t ) );
p_avi_strl = (avi_chunk_list_t*)AVI_ChunkFind( p_hdrl,
AVIFOURCC_strl, i );
p_avi_strh = (avi_chunk_strh_t*)AVI_ChunkFind( p_avi_strl,
AVIFOURCC_strh, 0 );
- p_avi_strf_auds =
- p_avi_strf_vids = AVI_ChunkFind( p_avi_strl, AVIFOURCC_strf, 0 );
+ p_avi_strf_auds = (avi_chunk_strf_auds_t*)
+ p_avi_strf_vids = (avi_chunk_strf_vids_t*)
+ AVI_ChunkFind( p_avi_strl, AVIFOURCC_strf, 0 );
if( !p_avi_strl || !p_avi_strh ||
( !p_avi_strf_auds && !p_avi_strf_vids ) )
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
- /* create a pseudo p_movi */
- p_avi->p_movi = malloc( sizeof( riffchunk_t ) );
- p_avi->p_movi->i_id = AVIFOURCC_LIST;
- p_avi->p_movi->i_type = AVIFOURCC_movi;
- p_avi->p_movi->i_size = p_movi->i_chunk_size;
- p_avi->p_movi->i_pos = p_movi->i_chunk_pos;
- p_avi->p_movi->p_data = NULL;
-
-
+ b_stream_audio = 0;
+ b_stream_video = 0;
+
for( i = 0; i < p_avi->i_streams; i++ )
{
#define p_info p_avi->pp_info[i]
{
case( VIDEO_ES ):
- if( (p_avi->p_info_video == NULL) )
+ if( !b_stream_video )
{
- p_avi->p_info_video = p_info;
- /* TODO add test to see if a decoder has been found */
- AVI_StreamStart( p_input, p_avi, i );
+ b_stream_video = AVI_StreamStart( p_input, p_avi, i );
}
break;
case( AUDIO_ES ):
- if( (p_avi->p_info_audio == NULL) )
+ if( !b_stream_audio )
{
- p_avi->p_info_audio = p_info;
- AVI_StreamStart( p_input, p_avi, i );
+ b_stream_audio = AVI_StreamStart( p_input, p_avi, i );
}
break;
default:
#undef p_info
}
- /* we select the first audio and video ES */
- vlc_mutex_lock( &p_input->stream.stream_lock );
- if( !p_avi->p_info_video )
+ if( !b_stream_video )
{
msg_Warn( p_input, "no video stream found" );
}
- if( !p_avi->p_info_audio )
+ if( !b_stream_audio )
{
msg_Warn( p_input, "no audio stream found!" );
}
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_program->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
// already at begining of p_movi
}
AVI_SkipBytes( p_input, 12 ); // enter in p_movi
+
+ p_avi->i_movi_begin = p_movi->i_chunk_pos;
+ p_avi->i_movi_lastchunk_pos = 0;
return( 0 );
}
* Function to convert pts to chunk or byte
*****************************************************************************/
-static inline mtime_t AVI_PTSToChunk( AVIStreamInfo_t *p_info,
+static inline mtime_t AVI_PTSToChunk( avi_stream_t *p_info,
mtime_t i_pts )
{
return( (mtime_t)((s64)i_pts *
(s64)p_info->i_scale /
(s64)1000000 ) );
}
-static inline mtime_t AVI_PTSToByte( AVIStreamInfo_t *p_info,
+static inline mtime_t AVI_PTSToByte( avi_stream_t *p_info,
mtime_t i_pts )
{
return( (mtime_t)((s64)i_pts *
(s64)1000000 ) );
}
-static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
+
+static mtime_t AVI_GetDPTS( avi_stream_t *p_stream, int i_count )
+{
+ if( p_stream->i_samplesize )
+ {
+ return( (mtime_t)( (s64)1000000 *
+ (s64)i_count *
+ (s64)p_stream->i_scale /
+ (s64)p_stream->i_rate /
+ (s64)p_stream->i_samplesize ) );
+ }
+ else
+ {
+ return( (mtime_t)( (s64)1000000 *
+ (s64)i_count *
+ (s64)p_stream->i_scale /
+ (s64)p_stream->i_rate) );
+ }
+
+}
+
+static mtime_t AVI_GetPTS( avi_stream_t *p_info )
{
if( p_info->i_samplesize )
}
}
-
-/*****************************************************************************
- * Functions to acces streams data
- * Uses it, because i plane to read 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 )
+static int AVI_StreamChunkFind( input_thread_t *p_input,
+ int i_stream )
{
+ demux_sys_t *p_avi = p_input->p_demux_data;
+ avi_packet_t avi_pk;
- int i_read;
- data_packet_t *p_data;
-
-
- if( !(*pp_pes = input_NewPES( p_input->p_method_data ) ) )
- {
- return( 0 );
- }
+ /* find first chunk of i_stream that isn't in index */
-
- 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 );
- }
-
- if( ( i_size&1 )&&( b_pad ) )
+ if( p_avi->i_movi_lastchunk_pos >= p_avi->i_movi_begin )
{
- b_pad = 1;
- i_size++;
+ AVI_SeekAbsolute( p_input, p_avi->i_movi_lastchunk_pos );
+ if( !AVI_PacketNext( p_input ) )
+ {
+ return( 0 );
+ }
}
else
{
- b_pad = 0;
+ AVI_SeekAbsolute( p_input, p_avi->i_movi_begin );
}
- do
+ for( ;; )
{
- i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size -
- (*pp_pes)->i_pes_size, 1024 ) );
- if( i_read < 0 )
+
+ if( !AVI_PacketGetHeader( p_input, &avi_pk ) )
{
- return( (*pp_pes)->i_pes_size );
+ msg_Err( p_input, "cannot get packet header" );
+ return( 0 );
}
- if( !(*pp_pes)->p_first )
+ if( avi_pk.i_stream >= p_avi->i_streams ||
+ ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
{
- (*pp_pes)->p_first =
- (*pp_pes)->p_last = p_data;
- (*pp_pes)->i_nb_data = 1;
- (*pp_pes)->i_pes_size = i_read;
+ switch( avi_pk.i_fourcc )
+ {
+ case AVIFOURCC_LIST:
+ AVI_SkipBytes( p_input, 12 );
+ break;
+ default:
+ if( !AVI_PacketNext( p_input ) )
+ {
+ return( 0 );
+ }
+ break;
+ }
}
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;
+ /* add this chunk to the index */
+ AVIIndexEntry_t index;
+
+ index.i_id = avi_pk.i_fourcc;
+ index.i_flags =
+ AVI_GetKeyFlag(p_avi->pp_info[avi_pk.i_stream]->i_codec,
+ avi_pk.i_peek);
+ index.i_pos = avi_pk.i_pos;
+ index.i_length = avi_pk.i_size;
+ AVI_IndexAddEntry( p_avi, avi_pk.i_stream, &index );
+
+ if( avi_pk.i_stream == i_stream )
+ {
+ return( 1 );
+ }
+
+ if( !AVI_PacketNext( p_input ) )
+ {
+ return( 0 );
+ }
}
- } 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 )
+/* be sure that i_ck will be a valid index entry */
+static int AVI_SetStreamChunk( input_thread_t *p_input,
+ int i_stream,
+ int i_ck )
{
- int i_info_pos;
- int i_other_pos;
+ demux_sys_t *p_avi = p_input->p_demux_data;
+ avi_stream_t *p_stream = p_avi->pp_info[i_stream];
- int i_info_pos_last;
- int i_other_pos_last;
+ p_stream->i_idxposc = i_ck;
+ p_stream->i_idxposb = 0;
- /*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 )
+ if( i_ck < p_stream->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 ) ) )
+ else
{
- return( 0 );
- }
-
- /* KNOW for the 2 streams, the ck we want are after the last read
- or it's the first */
+ p_stream->i_idxposc = p_stream->i_idxnb - 1;
+ do
+ {
+ p_stream->i_idxposc++;
+ if( !AVI_StreamChunkFind( p_input, i_stream ) )
+ {
+ return( 0 );
+ }
- /* 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 );
-}
+ } while( p_stream->i_idxposc < i_ck );
-
-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( 1 );
}
- 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 )
+/* XXX FIXME up to now, we assume that all chunk are one after one */
+static int AVI_SetStreamBytes( input_thread_t *p_input,
+ int i_stream,
+ off_t i_byte )
{
demux_sys_t *p_avi = p_input->p_demux_data;
- AVIStreamInfo_t *p_other;
- int i_method;
- off_t i_posmax;
- int i;
-
-#define p_info_i p_avi->pp_info[i]
- 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
- {
- AVI_PESBuffer_Drop( p_input->p_method_data, p_info );
- }
- }
- /* up to now we handle only one audio and video streams at the same time */
- p_other = (p_info == p_avi->p_info_video ) ?
- p_avi->p_info_audio : p_avi->p_info_video ;
+ avi_stream_t *p_stream = p_avi->pp_info[i_stream];
- i_method = __AVI_GetChunkMethod( p_input, p_info, p_other );
-
- if( !i_method )
- {
- /* get directly the good chunk */
- return( b_load ? __AVI_SeekAndGetChunk( p_input, p_info ) : 1 );
- }
- /* 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 )
+ if( ( p_stream->i_idxnb > 0 )
+ &&( i_byte < p_stream->p_index[p_stream->i_idxnb - 1].i_lengthtotal +
+ p_stream->p_index[p_stream->i_idxnb - 1].i_length ) )
{
- /* 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->i_streams; i++ )
+ /* index is valid to find the ck */
+ /* uses dichototmie to be fast enougth */
+ int i_idxposc = __MIN( p_stream->i_idxposc, p_stream->i_idxnb - 1 );
+ int i_idxmax = p_stream->i_idxnb;
+ int i_idxmin = 0;
+ for( ;; )
{
- if( p_info_i->i_idxnb )
+ if( p_stream->p_index[i_idxposc].i_lengthtotal > i_byte )
+ {
+ i_idxmax = i_idxposc ;
+ i_idxposc = ( i_idxmin + i_idxposc ) / 2 ;
+ }
+ else
{
- if( p_info_max->i_idxnb )
+ if( p_stream->p_index[i_idxposc].i_lengthtotal +
+ p_stream->p_index[i_idxposc].i_length <= i_byte)
{
- 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;
- }
+ i_idxmin = i_idxposc ;
+ i_idxposc = (i_idxmax + i_idxposc ) / 2 ;
}
else
{
- p_info_max = p_info_i;
+ p_stream->i_idxposc = i_idxposc;
+ p_stream->i_idxposb = i_byte -
+ p_stream->p_index[i_idxposc].i_lengthtotal;
+ return( 1 );
}
}
}
- if( p_info_max->i_idxnb )
+
+ }
+ else
+ {
+ p_stream->i_idxposc = p_stream->i_idxnb - 1;
+ p_stream->i_idxposb = 0;
+ do
{
- /* 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->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 == AVIFOURCC_LIST )&&( p_ck->i_type == AVIFOURCC_rec ) )
- {
- AVI_SkipBytes( p_input, 12 );
-// 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->i_streams )
- {
- RIFF_DeleteChunk( p_input, p_ck );
- if( RIFF_NextChunk( p_input, p_avi->p_movi ) != 0 )
+ p_stream->i_idxposc++;
+ if( !AVI_StreamChunkFind( p_input, i_stream ) )
{
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->i_codec,
- (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->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 ) )
- {
- /* 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->p_movi ) != 0 )
- {
- return( 0 );
- }
- }
- }
-
-
- }
-
-#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 );
+ } while( p_stream->p_index[p_stream->i_idxposc].i_lengthtotal +
+ p_stream->p_index[p_stream->i_idxposc].i_length <= i_byte );
+ p_stream->i_idxposb = i_byte -
+ p_stream->p_index[p_stream->i_idxposc].i_lengthtotal;
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 );
-}
-
-/*****************************************************************************
- * 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( !p_info->i_samplesize )
- {
- 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 );
-
- if( !p_pes_tmp )
- {
- return( p_pes_first );
- }
- p_pes_tmp->i_pts = i_pts;
- if( !p_pes_first )
- {
- p_pes_first = p_pes_tmp;
- }
- else
- {
- p_pes->p_next = p_pes_tmp;
- }
- p_pes = p_pes_tmp;
- }
- return( p_pes_first );
- }
- else
- {
- /* stream is byte based */
- int i_byte = AVI_PTSToByte( p_info, i_dpts);
- if( i_byte < 50 ) /* to avoid some problem with audio */
- {
- return( NULL );
- }
- 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_pes->i_pts = i_pts;
- }
- return( p_pes );
- }
-}
-/*****************************************************************************
- * 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 )
-{
- 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;
- }
-
-}
-
static int AVI_StreamSeek( input_thread_t *p_input,
demux_sys_t *p_avi,
int i_stream,
#define p_stream p_avi->pp_info[i_stream]
mtime_t i_oldpts;
- AVI_PESBuffer_Flush( p_input->p_method_data, p_stream );
i_oldpts = AVI_GetPTS( p_stream );
if( !p_stream->i_samplesize )
{
- AVI_SetStreamChunk( p_input,
- p_stream,
- AVI_PTSToChunk( p_stream, i_date ) );
+ if( !AVI_SetStreamChunk( p_input,
+ i_stream,
+ AVI_PTSToChunk( p_stream, i_date ) ) )
+ {
+ return( 0 );
+ }
+
/* search key frame */
msg_Dbg( p_input,
"old:%lld %s new %lld",
AVIIF_KEYFRAME ) )
{
if( !AVI_SetStreamChunk( p_input,
- p_stream,
+ i_stream,
p_stream->i_idxposc - 1 ) )
{
return( 0 );
}
else
{
- while( !( p_stream->p_index[p_stream->i_idxposc].i_flags &
+ while( p_stream->i_idxposc < p_stream->i_idxnb &&
+ !( p_stream->p_index[p_stream->i_idxposc].i_flags &
AVIIF_KEYFRAME ) )
{
if( !AVI_SetStreamChunk( p_input,
- p_stream,
+ i_stream,
p_stream->i_idxposc + 1 ) )
{
return( 0 );
}
else
{
- AVI_SetStreamBytes( p_input,
- p_stream,
- AVI_PTSToByte( p_stream, i_date ) );
+ if( !AVI_SetStreamBytes( p_input,
+ i_stream,
+ AVI_PTSToByte( p_stream, i_date ) ) )
+ {
+ return( 0 );
+ }
}
return( 1 );
#undef p_stream
{
if( !p_avi->i_length )
{
- int i_index;
- AVIStreamInfo_t *p_stream;
+ avi_stream_t *p_stream;
u64 i_pos;
/* use i_percent to create a true i_date */
/* try to find chunk that is at i_percent or the file */
i_pos = __MAX( i_percent *
p_input->stream.p_selected_area->i_size / 100,
- p_avi->p_movi->i_pos );
+ p_avi->i_movi_begin );
/* search first selected stream */
- for( i_index = 0,p_stream = NULL;
- i_index < p_avi->i_streams; i_stream++ )
+ for( i_stream = 0, p_stream = NULL;
+ i_stream < p_avi->i_streams; i_stream++ )
{
- p_stream = p_avi->pp_info[i_index];
+ p_stream = p_avi->pp_info[i_stream];
if( p_stream->i_activated )
{
break;
}
}
- if( !p_stream || !p_stream->p_index )
+ if( !p_stream || !p_stream->i_activated )
{
msg_Err( p_input, "cannot find any selected stream" );
return( -1 );
}
- /* search chunk */
- p_stream->i_idxposc = __MAX( p_stream->i_idxposc - 1, 0 );
- while( ( i_pos < p_stream->p_index[p_stream->i_idxposc].i_pos )
- &&( p_stream->i_idxposc > 0 ) )
+
+ /* be sure that the index exit */
+ if( !AVI_SetStreamChunk( p_input,
+ i_stream,
+ 0 ) )
{
- /* search before i_idxposc */
- if( !AVI_SetStreamChunk( p_input,
- p_stream, p_stream->i_idxposc - 1 ) )
- {
- msg_Err( p_input, "cannot seek" );
- return( -1 );
- }
+ msg_Err( p_input, "cannot seek" );
+ return( -1 );
}
+
while( i_pos >= p_stream->p_index[p_stream->i_idxposc].i_pos +
p_stream->p_index[p_stream->i_idxposc].i_length + 8 )
{
/* search after i_idxposc */
if( !AVI_SetStreamChunk( p_input,
- p_stream, p_stream->i_idxposc + 1 ) )
+ i_stream, p_stream->i_idxposc + 1 ) )
{
msg_Err( p_input, "cannot seek" );
return( -1 );
* 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
*****************************************************************************/
+typedef struct avi_stream_toread_s
+{
+ int i_ok;
+
+ int i_toread;
+
+ off_t i_posf; // where we will read :
+ // if i_idxposb == 0 : begining of chunk (+8 to acces data)
+ // else : point on data directly
+} avi_stream_toread_t;
static int AVIDemux_Seekable( input_thread_t *p_input )
{
- int i;
int i_stream;
int b_stream;
+ // cannot be more than 100 stream (dcXX or wbXX)
+ avi_stream_toread_t toread[100];
+
demux_sys_t *p_avi = p_input->p_demux_data;
/* detect new selected/unselected streams */
}
#undef p_stream
}
- /* search new video and audio stream selected
- if current have been unselected*/
- if( ( !p_avi->p_info_video )
- || ( !p_avi->p_info_video->p_es->p_decoder_fifo ) )
- {
- p_avi->p_info_video = NULL;
- for( i = 0; i < p_avi->i_streams; i++ )
- {
- if( ( p_avi->pp_info[i]->i_cat == VIDEO_ES )
- &&( p_avi->pp_info[i]->p_es->p_decoder_fifo ) )
- {
- p_avi->p_info_video = p_avi->pp_info[i];
- break;
- }
- }
- }
- if( ( !p_avi->p_info_audio )
- ||( !p_avi->p_info_audio->p_es->p_decoder_fifo ) )
- {
- p_avi->p_info_audio = NULL;
- for( i = 0; i < p_avi->i_streams; i++ )
- {
- if( ( p_avi->pp_info[i]->i_cat == AUDIO_ES )
- &&( p_avi->pp_info[i]->p_es->p_decoder_fifo ) )
- {
- p_avi->p_info_audio = p_avi->pp_info[i];
- break;
- }
- }
- }
if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
{
mtime_t i_date;
int i_percent;
/* first wait for empty buffer, arbitrary time FIXME */
- msleep( DEFAULT_PTS_DELAY );
+// msleep( DEFAULT_PTS_DELAY );
i_date = (mtime_t)1000000 *
(mtime_t)p_avi->i_length *
(mtime_t)p_input->stream.p_selected_area->i_size;
i_percent = 100 * AVI_TellAbsolute( p_input ) /
p_input->stream.p_selected_area->i_size;
- AVISeek( p_input, i_date, i_percent);
+
// input_ClockInit( p_input->stream.p_selected_program );
+ AVISeek( p_input, i_date, i_percent);
}
+
+
/* wait for the good time */
+
+ p_avi->i_pcr = p_avi->i_time * 9 / 100;
+
input_ClockManageRef( p_input,
p_input->stream.p_selected_program,
p_avi->i_pcr );
- p_avi->i_pcr = p_avi->i_time * 9 / 100;
+
p_avi->i_time += 100*1000; /* read 100ms */
+
+ /* init toread */
+ for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
+ {
+#define p_stream p_avi->pp_info[i_stream]
+ mtime_t i_dpts;
+
+ toread[i_stream].i_ok = p_stream->i_activated;
+
+ if( p_stream->i_idxposc < p_stream->i_idxnb )
+ {
+ toread[i_stream].i_posf =
+ p_stream->p_index[p_stream->i_idxposc].i_pos;
+ if( p_stream->i_idxposb > 0 )
+ {
+ toread[i_stream].i_posf += 8 + p_stream->i_idxposb;
+ }
+ }
+ else
+ {
+ toread[i_stream].i_posf = -1;
+ }
+
+ i_dpts = p_avi->i_time - AVI_GetPTS( p_stream );
+
+ if( p_stream->i_samplesize )
+ {
+ toread[i_stream].i_toread = AVI_PTSToByte( p_stream,
+ __ABS( i_dpts ) );
+ }
+ else
+ {
+ toread[i_stream].i_toread = AVI_PTSToChunk( p_stream,
+ __ABS( i_dpts ) );
+ }
+
+ if( i_dpts < 0 )
+ {
+ toread[i_stream].i_toread *= -1;
+ }
+#undef p_stream
+ }
+
+ b_stream = 0;
- for( i_stream = 0, b_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
+ for( ;; )
{
#define p_stream p_avi->pp_info[i_stream]
+ int b_done;
pes_packet_t *p_pes;
+ off_t i_pos;
+ int i;
+ int i_size;
+
+ /* search for first chunk to be read */
+ for( i = 0, b_done = 1, i_pos = -1; i < p_avi->i_streams; i++ )
+ {
+ if( !toread[i].i_ok ||
+ AVI_GetDPTS( p_avi->pp_info[i],
+ toread[i].i_toread ) <= -25 * 1000 )
+ {
+ continue;
+ }
+
+ if( toread[i].i_toread > 0 )
+ {
+ b_done = 0; // not yet finished
+ }
+
+ if( toread[i].i_posf > 0 )
+ {
+ i_stream = i;
+ if( i_pos == -1 )
+ {
+ i_pos = toread[i_stream].i_posf;
+ }
+ else
+ {
+ i_pos = __MIN( i_pos, toread[i_stream].i_posf );
+ }
+ }
+ }
- if( !p_stream->p_es ||
- !p_stream->p_es->p_decoder_fifo )
+ if( b_done )
{
+ return( b_stream ? 1 : 0 );
+ }
+
+ if( i_pos == -1 )
+ {
+ /* no valid index, we will parse directly the stream */
+ if( p_avi->i_movi_lastchunk_pos >= p_avi->i_movi_begin )
+ {
+ AVI_SeekAbsolute( p_input, p_avi->i_movi_lastchunk_pos );
+ if( !AVI_PacketNext( p_input ) )
+ {
+ return( 0 );
+ }
+ }
+ else
+ {
+ AVI_SeekAbsolute( p_input, p_avi->i_movi_begin );
+ }
- continue;
+ for( ;; )
+ {
+ avi_packet_t avi_pk;
+
+ if( !AVI_PacketGetHeader( p_input, &avi_pk ) )
+ {
+ msg_Err( p_input, "cannot get packet header" );
+ return( 0 );
+ }
+ if( avi_pk.i_stream >= p_avi->i_streams ||
+ ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
+ {
+ switch( avi_pk.i_fourcc )
+ {
+ case AVIFOURCC_LIST:
+ AVI_SkipBytes( p_input, 12 );
+ break;
+ default:
+ if( !AVI_PacketNext( p_input ) )
+ {
+ msg_Err( p_input, "cannot skip packet" );
+ return( 0 );
+ }
+ break;
+ }
+ continue;
+ }
+ else
+ {
+ /* add this chunk to the index */
+ AVIIndexEntry_t index;
+
+ index.i_id = avi_pk.i_fourcc;
+ index.i_flags =
+ AVI_GetKeyFlag(p_avi->pp_info[avi_pk.i_stream]->i_codec,
+ avi_pk.i_peek);
+ index.i_pos = avi_pk.i_pos;
+ index.i_length = avi_pk.i_size;
+ AVI_IndexAddEntry( p_avi, avi_pk.i_stream, &index );
+
+ i_stream = avi_pk.i_stream;
+ /* do we will read this data ? */
+ if( AVI_GetDPTS( p_stream,
+ toread[i_stream].i_toread ) > -25 * 1000 )
+ {
+ break;
+ }
+ else
+ {
+ if( !AVI_PacketNext( p_input ) )
+ {
+ msg_Err( p_input, "cannot skip packet" );
+ return( 0 );
+ }
+ }
+ }
+ }
+
}
- if( p_avi->i_time <= AVI_GetPTS( p_stream ) )
+ else
{
- msg_Warn( p_input, "skeeping stream %d", i_stream );
- b_stream = 1;
+ AVI_SeekAbsolute( p_input, i_pos );
+ }
+
+ /* read thoses data */
+ if( p_stream->i_samplesize )
+ {
+ i_size = __MIN( p_stream->p_index[p_stream->i_idxposc].i_length -
+ p_stream->i_idxposb,
+ 100 * 1024 ); // 10Ko max
+// toread[i_stream].i_toread );
+ }
+ else
+ {
+ i_size = p_stream->p_index[p_stream->i_idxposc].i_length;
+ }
+
+ if( p_stream->i_idxposb == 0 )
+ {
+ i_size += 8; // need to read and skip header
+ }
+
+ if( input_ReadInPES( p_input, &p_pes, __EVEN( i_size ) ) < 0 )
+ {
+ msg_Err( p_input, "failled reading data" );
+ toread[i_stream].i_ok = 0;
continue;
}
- p_pes = AVI_GetFrameInPES( p_input,
- p_stream,
- p_avi->i_time - AVI_GetPTS( p_stream ) );
- if( p_pes )
+
+ if( i_size % 2 ) // read was padded on word boundary
{
- AVI_DecodePES( p_input, p_stream, p_pes );
- b_stream = 1;
+ p_pes->p_last->p_payload_end--;
+ p_pes->i_pes_size--;
+ }
+ // skip header
+ if( p_stream->i_idxposb == 0 )
+ {
+ p_pes->p_first->p_payload_start += 8;
+ p_pes->i_pes_size -= 8;
}
-#undef p_stream
- }
- /* at the end ? */
- return( b_stream ? 1 : 0 );
+ p_pes->i_pts = AVI_GetPTS( p_stream );
+
+ /* read data */
+ if( p_stream->i_samplesize )
+ {
+ if( p_stream->i_idxposb == 0 )
+ {
+ i_size -= 8;
+ }
+ toread[i_stream].i_toread -= i_size;
+ p_stream->i_idxposb += i_size;
+ if( p_stream->i_idxposb >=
+ p_stream->p_index[p_stream->i_idxposc].i_length )
+ {
+ p_stream->i_idxposb = 0;
+ p_stream->i_idxposc++;
+ }
+ }
+ else
+ {
+ toread[i_stream].i_toread--;
+ p_stream->i_idxposc++;
+ }
+
+ if( p_stream->i_idxposc < p_stream->i_idxnb)
+ {
+ toread[i_stream].i_posf =
+ p_stream->p_index[p_stream->i_idxposc].i_pos;
+ if( p_stream->i_idxposb > 0 )
+ {
+ toread[i_stream].i_posf += 8 + p_stream->i_idxposb;
+ }
+
+ }
+ else
+ {
+ toread[i_stream].i_posf = -1;
+ }
+ b_stream = 1; // at least one read succeed
+
+ if( p_stream->p_es && p_stream->p_es->p_decoder_fifo )
+ {
+ p_pes->i_dts =
+ p_pes->i_pts =
+ input_ClockGetTS( p_input,
+ p_input->stream.p_selected_program,
+ p_pes->i_pts * 9/100);
+
+ input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes );
+ }
+ else
+ {
+ input_DeletePES( p_input->p_method_data, p_pes );
+ }
+ }
+
}
static int AVIDemux_UnSeekable( input_thread_t *p_input )
{
demux_sys_t *p_avi = p_input->p_demux_data;
- AVIStreamInfo_t *p_stream_master;
+ avi_stream_t *p_stream_master;
int i_stream;
int b_audio;
int i_packet;
{
return( -1 );
}
- p_pes->i_pts = AVI_GetPTS( p_stream );
- AVI_DecodePES( p_input, p_stream, p_pes );
+ p_pes->i_pts =
+ input_ClockGetTS( p_input,
+ p_input->stream.p_selected_program,
+ AVI_GetPTS( p_stream ) * 9/100);
+ input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes );
}
else
{