Commit cdf8646f authored by Laurent Aimar's avatar Laurent Aimar

* all : rewrite demux part (simpler and cleaner). Please, tell me if you see

some regression.
parent 4a0ddd5b
SOURCES_avi = \
modules/demux/avi/avi.c \
modules/demux/avi/libioRIFF.c \
modules/demux/avi/libavi.c
noinst_HEADERS += \
modules/demux/avi/avi.h \
modules/demux/avi/libioRIFF.h \
modules/demux/avi/libavi.h
......@@ -2,7 +2,7 @@
* 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
......@@ -33,7 +33,6 @@
#include "video.h"
#include "libioRIFF.h"
#include "libavi.h"
#include "avi.h"
......@@ -61,14 +60,13 @@ vlc_module_begin();
"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 )
{
......@@ -96,6 +94,66 @@ static inline off_t __EVEN( off_t i )
#define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) )
/* read data in a pes */
static int input_ReadInPES( input_thread_t *p_input,
pes_packet_t **pp_pes,
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 )
{
......@@ -212,97 +270,6 @@ vlc_fourcc_t AVI_FourccGetCodec( int i_cat, vlc_fourcc_t i_codec )
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 )
{
......@@ -337,18 +304,6 @@ 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;
......@@ -396,14 +351,25 @@ static int AVI_PacketRead( input_thread_t *p_input,
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 );
}
......@@ -435,7 +401,7 @@ static int AVI_PacketSearch( input_thread_t *p_input )
}
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 )
......@@ -472,6 +438,19 @@ static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
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 )
......@@ -526,11 +505,11 @@ 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++ )
......@@ -591,8 +570,7 @@ static void AVI_IndexCreate( input_thread_t *p_input )
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
{
......@@ -659,8 +637,10 @@ static int AVI_StreamStart( input_thread_t *p_input,
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
......@@ -677,8 +657,6 @@ static void AVI_StreamStop( input_thread_t *p_input,
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 );
......@@ -747,8 +725,6 @@ static void __AVIEnd ( vlc_object_t * p_this )
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++ )
......@@ -758,8 +734,6 @@ static void __AVIEnd ( vlc_object_t * p_this )
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] );
}
......@@ -787,6 +761,8 @@ static int AVIInit( vlc_object_t * p_this )
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 ) )
{
......@@ -810,7 +786,6 @@ static int AVIInit( vlc_object_t * p_this )
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 *** */
......@@ -900,10 +875,10 @@ static int AVIInit( vlc_object_t * p_this )
/* 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++ )
{
......@@ -914,15 +889,16 @@ static int AVIInit( vlc_object_t * p_this )
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 ) )
......@@ -1045,15 +1021,9 @@ static int AVIInit( vlc_object_t * p_this )
}
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]
......@@ -1061,19 +1031,16 @@ static int AVIInit( vlc_object_t * p_this )
{
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:
......@@ -1082,16 +1049,16 @@ static int AVIInit( vlc_object_t * p_this )
#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 );
......@@ -1104,6 +1071,9 @@ static int AVIInit( vlc_object_t * p_this )
// 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 );
}
......@@ -1114,7 +1084,7 @@ static int AVIInit( vlc_object_t * p_this )
* 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 *
......@@ -1122,7 +1092,7 @@ static inline mtime_t AVI_PTSToChunk( AVIStreamInfo_t *p_info,
(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 *
......@@ -1132,7 +1102,28 @@ static inline mtime_t AVI_PTSToByte( AVIStreamInfo_t *p_info,
(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 )
......@@ -1175,712 +1166,175 @@ static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
}
}
/*****************************************************************************
* 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,
......@@ -1889,14 +1343,17 @@ static int AVI_StreamSeek( input_thread_t *p_input,
#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",
......@@ -1911,7 +1368,7 @@ static int AVI_StreamSeek( input_thread_t *p_input,
AVIIF_KEYFRAME ) )
{
if( !AVI_SetStreamChunk( p_input,
p_stream,
i_stream,
p_stream->i_idxposc - 1 ) )
{
return( 0 );
......@@ -1920,11 +1377,12 @@ static int AVI_StreamSeek( input_thread_t *p_input,
}
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 );
......@@ -1934,9 +1392,12 @@ static int AVI_StreamSeek( input_thread_t *p_input,
}
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
......@@ -1962,8 +1423,7 @@ static int AVISeek ( input_thread_t *p_input,
{
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 */
......@@ -1981,41 +1441,38 @@ static int AVISeek ( input_thread_t *p_input,
/* 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 );
......@@ -2076,16 +1533,26 @@ static int AVISeek ( input_thread_t *p_input,
* 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 */
......@@ -2108,43 +1575,13 @@ static int AVIDemux_Seekable( input_thread_t *p_input )
}
#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 *
......@@ -2152,48 +1589,284 @@ static int AVIDemux_Seekable( input_thread_t *p_input )
(mtime_t)p_input->stream.p_selected_area->i_size;
i_percent = 100 * AVI_TellAbsolute( p_input ) /
p_input->stream.p_selected_area->i_size;
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 );
}
}
}
......@@ -2206,7 +1879,7 @@ static int AVIDemux_Seekable( input_thread_t *p_input )
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;
......@@ -2308,8 +1981,11 @@ static int AVIDemux_UnSeekable( input_thread_t *p_input )
{
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
{
......
......@@ -2,7 +2,7 @@
* avi.h : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: avi.h,v 1.4 2002/10/15 00:55:07 fenrir Exp $
* $Id: avi.h,v 1.5 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
......@@ -20,7 +20,20 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#define MAX_PACKETS_IN_FIFO 2
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;
typedef struct AVIIndexEntry_s
{
......@@ -29,22 +42,14 @@ typedef struct AVIIndexEntry_s
u32 i_pos;
u32 i_length;
u32 i_lengthtotal;
} AVIIndexEntry_t;
typedef struct AVIESBuffer_s
typedef struct avi_stream_s
{
struct AVIESBuffer_s *p_next;
pes_packet_t *p_pes;
int i_posc;
int i_posb;
} AVIESBuffer_t;
int i_activated;
typedef struct AVIStreamInfo_s
{
int i_cat; /* AUDIO_ES, VIDEO_ES */
int i_activated;
vlc_fourcc_t i_fourcc;
vlc_fourcc_t i_codec;
......@@ -52,8 +57,8 @@ typedef struct AVIStreamInfo_s
int i_scale;
int i_samplesize;
es_descriptor_t *p_es;
int b_selected; /* newly selected */
es_descriptor_t *p_es;
AVIIndexEntry_t *p_index;
int i_idxnb;
int i_idxmax;
......@@ -61,32 +66,23 @@ typedef struct AVIStreamInfo_s
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;
} avi_stream_t;
struct demux_sys_t
{
mtime_t i_time;
mtime_t i_length;
mtime_t i_pcr;
int i_rate;
riffchunk_t *p_movi;
int b_seekable;
avi_chunk_t ck_root;
/* Info extrated from avih */
off_t i_movi_begin;
off_t i_movi_lastchunk_pos; /* XXX position of last valid chunk */
/* number of stream and informations*/
int i_streams;
AVIStreamInfo_t **pp_info;
avi_stream_t **pp_info;
/* current audio and video es */
AVIStreamInfo_t *p_info_video;
AVIStreamInfo_t *p_info_audio;
};
......@@ -2,7 +2,7 @@
* libavi.c :
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: libavi.c,v 1.2 2002/10/26 19:14:45 fenrir Exp $
* $Id: libavi.c,v 1.3 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
......@@ -109,14 +109,33 @@ int AVI_SeekAbsolute( input_thread_t *p_input,
}
else
{
int i_peek;
int i_skip = i_pos - i_filepos;
u8 *p_peek;
data_packet_t *p_data;
int i_skip = i_pos - i_filepos;
msg_Warn( p_input, "will skip %d bytes, slow", i_skip );
if( i_skip < 0 )
{
return( 0 ); // failed
}
while (i_skip > 0 )
{
int i_read;
i_read = input_SplitBuffer( p_input, &p_data,
__MIN( 4096, i_skip ) );
if( i_read < 0 )
{
return( 0 );
}
i_skip -= i_read;
input_DeletePacket( p_input->p_method_data, p_data );
if( i_read == 0 && i_skip > 0 )
{
return( 0 );
}
}
#if 0
while( i_skip > 0 )
{
i_peek = input_Peek( p_input, &p_peek, i_skip+1 );
......@@ -130,6 +149,7 @@ int AVI_SeekAbsolute( input_thread_t *p_input,
return( 0);
}
}
#endif
return( 1 );
}
}
......
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