Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

avi.c

00001 /*****************************************************************************
00002  * avi.c : AVI file Stream input module for vlc
00003  *****************************************************************************
00004  * Copyright (C) 2001-2004 the VideoLAN team
00005  * $Id: avi.c 12821 2005-10-11 17:16:13Z zorglub $
00006  * Authors: Laurent Aimar <[email protected]>
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00021  *****************************************************************************/
00022 
00023 /*****************************************************************************
00024  * Preamble
00025  *****************************************************************************/
00026 #include <stdlib.h>                                      /* malloc(), free() */
00027 
00028 #include <vlc/vlc.h>
00029 #include <vlc/input.h>
00030 
00031 #include "vlc_meta.h"
00032 #include "codecs.h"
00033 
00034 #include "libavi.h"
00035 
00036 /*****************************************************************************
00037  * Module descriptor
00038  *****************************************************************************/
00039 
00040 #define INTERLEAVE_TEXT N_("Force interleaved method" )
00041 #define INTERLEAVE_LONGTEXT N_( "Force interleaved method" )
00042 
00043 #define INDEX_TEXT N_("Force index creation")
00044 #define INDEX_LONGTEXT N_( \
00045     "Recreate a index for the AVI file. Use this if your AVI file is damaged "\
00046     "or incomplete (not seekable)" )
00047 
00048 static int  Open ( vlc_object_t * );
00049 static void Close( vlc_object_t * );
00050 
00051 vlc_module_begin();
00052     set_shortname( "AVI" );
00053     set_description( _("AVI demuxer") );
00054     set_capability( "demux2", 212 );
00055     set_category( CAT_INPUT );
00056     set_subcategory( SUBCAT_INPUT_DEMUX );
00057 
00058     add_bool( "avi-interleaved", 0, NULL,
00059               INTERLEAVE_TEXT, INTERLEAVE_LONGTEXT, VLC_TRUE );
00060     add_bool( "avi-index", 0, NULL,
00061               INDEX_TEXT, INDEX_LONGTEXT, VLC_FALSE );
00062 
00063     set_callbacks( Open, Close );
00064 vlc_module_end();
00065 
00066 /*****************************************************************************
00067  * Local prototypes
00068  *****************************************************************************/
00069 static int Control         ( demux_t *, int, va_list );
00070 static int Seek            ( demux_t *, mtime_t, int );
00071 static int Demux_Seekable  ( demux_t * );
00072 static int Demux_UnSeekable( demux_t * );
00073 
00074 #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
00075 #define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) )
00076 
00077 typedef struct
00078 {
00079     vlc_fourcc_t i_fourcc;
00080     off_t        i_pos;
00081     uint32_t     i_size;
00082     vlc_fourcc_t i_type;     /* only for AVIFOURCC_LIST */
00083 
00084     uint8_t      i_peek[8];  /* first 8 bytes */
00085 
00086     unsigned int i_stream;
00087     unsigned int i_cat;
00088 } avi_packet_t;
00089 
00090 
00091 typedef struct
00092 {
00093     vlc_fourcc_t i_id;
00094     uint32_t     i_flags;
00095     off_t        i_pos;
00096     uint32_t     i_length;
00097     uint32_t     i_lengthtotal;
00098 
00099 } avi_entry_t;
00100 
00101 typedef struct
00102 {
00103     vlc_bool_t      b_activated;
00104 
00105     unsigned int    i_cat; /* AUDIO_ES, VIDEO_ES */
00106     vlc_fourcc_t    i_codec;
00107 
00108     int             i_rate;
00109     int             i_scale;
00110     int             i_samplesize;
00111 
00112     es_out_id_t     *p_es;
00113 
00114     avi_entry_t     *p_index;
00115     unsigned int        i_idxnb;
00116     unsigned int        i_idxmax;
00117 
00118     unsigned int        i_idxposc;  /* numero of chunk */
00119     unsigned int        i_idxposb;  /* byte in the current chunk */
00120 
00121     /* For VBR audio only */
00122     unsigned int        i_blockno;
00123     unsigned int        i_blocksize;
00124 } avi_track_t;
00125 
00126 struct demux_sys_t
00127 {
00128     mtime_t i_time;
00129     mtime_t i_length;
00130 
00131     vlc_bool_t  b_seekable;
00132     avi_chunk_t ck_root;
00133 
00134     vlc_bool_t  b_odml;
00135 
00136     off_t   i_movi_begin;
00137     off_t   i_movi_lastchunk_pos;   /* XXX position of last valid chunk */
00138 
00139     /* number of streams and information */
00140     unsigned int i_track;
00141     avi_track_t  **track;
00142 
00143     /* meta */
00144     vlc_meta_t  *meta;
00145 };
00146 
00147 static inline off_t __EVEN( off_t i )
00148 {
00149     return (i & 1) ? i + 1 : i;
00150 }
00151 
00152 static mtime_t AVI_PTSToChunk( avi_track_t *, mtime_t i_pts );
00153 static mtime_t AVI_PTSToByte ( avi_track_t *, mtime_t i_pts );
00154 static mtime_t AVI_GetDPTS   ( avi_track_t *, int64_t i_count );
00155 static mtime_t AVI_GetPTS    ( avi_track_t * );
00156 
00157 
00158 static int AVI_StreamChunkFind( demux_t *, unsigned int i_stream );
00159 static int AVI_StreamChunkSet ( demux_t *,
00160                                 unsigned int i_stream, unsigned int i_ck );
00161 static int AVI_StreamBytesSet ( demux_t *,
00162                                 unsigned int i_stream, off_t   i_byte );
00163 
00164 vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t );
00165 static int   AVI_GetKeyFlag    ( vlc_fourcc_t , uint8_t * );
00166 
00167 static int AVI_PacketGetHeader( demux_t *, avi_packet_t *p_pk );
00168 static int AVI_PacketNext     ( demux_t * );
00169 static int AVI_PacketRead     ( demux_t *, avi_packet_t *, block_t **);
00170 static int AVI_PacketSearch   ( demux_t * );
00171 
00172 static void AVI_IndexLoad    ( demux_t * );
00173 static void AVI_IndexCreate  ( demux_t * );
00174 static void AVI_IndexAddEntry( demux_sys_t *, int, avi_entry_t * );
00175 
00176 static mtime_t  AVI_MovieGetLength( demux_t * );
00177 
00178 /*****************************************************************************
00179  * Stream management
00180  *****************************************************************************/
00181 static int        AVI_TrackSeek  ( demux_t *, int, mtime_t );
00182 static int        AVI_TrackStopFinishedStreams( demux_t *);
00183 
00184 /* Remarks:
00185  - For VBR mp3 stream:
00186     count blocks by rounded-up chunksizes instead of chunks
00187     we need full emulation of dshow avi demuxer bugs :(
00188     fixes silly nandub-style a-v delaying in avi with vbr mp3...
00189     (from mplayer 2002/08/02)
00190  - to complete....
00191  */
00192 
00193 /*****************************************************************************
00194  * Open: check file and initializes AVI structures
00195  *****************************************************************************/
00196 static int Open( vlc_object_t * p_this )
00197 {
00198     demux_t  *p_demux = (demux_t *)p_this;
00199     demux_sys_t     *p_sys;
00200 
00201     avi_chunk_t         ck_riff;
00202     avi_chunk_list_t    *p_riff = (avi_chunk_list_t*)&ck_riff;
00203     avi_chunk_list_t    *p_hdrl, *p_movi;
00204     avi_chunk_avih_t    *p_avih;
00205 
00206     unsigned int i_track;
00207     unsigned int i, i_peeker;
00208 
00209     uint8_t  *p_peek;
00210 
00211     /* Is it an avi file ? */
00212     if( stream_Peek( p_demux->s, &p_peek, 200 ) < 200 ) return VLC_EGENERIC;
00213 
00214     for( i_peeker = 0; i_peeker < 188; i_peeker++ )
00215     {
00216         if( !strncmp( (char *)&p_peek[0], "RIFF", 4 ) &&
00217             !strncmp( (char *)&p_peek[8], "AVI ", 4 ) ) break;
00218         p_peek++;
00219     }
00220     if( i_peeker == 188 )
00221     {
00222         return VLC_EGENERIC;
00223     }
00224 
00225     /* Initialize input  structures. */
00226     p_sys = p_demux->p_sys = malloc( sizeof(demux_sys_t) );
00227     memset( p_sys, 0, sizeof( demux_sys_t ) );
00228     p_sys->i_time   = 0;
00229     p_sys->i_length = 0;
00230     p_sys->i_movi_lastchunk_pos = 0;
00231     p_sys->b_odml   = VLC_FALSE;
00232     p_sys->i_track  = 0;
00233     p_sys->track    = NULL;
00234     p_sys->meta     = NULL;
00235 
00236     stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &p_sys->b_seekable );
00237 
00238     p_demux->pf_control = Control;
00239     p_demux->pf_demux = Demux_Seekable;
00240 
00241     /* For unseekable stream, automaticaly use Demux_UnSeekable */
00242     if( !p_sys->b_seekable || config_GetInt( p_demux, "avi-interleaved" ) )
00243     {
00244         p_demux->pf_demux = Demux_UnSeekable;
00245     }
00246 
00247     if( i_peeker > 0 )
00248     {
00249         stream_Read( p_demux->s, NULL, i_peeker );
00250     }
00251 
00252     if( AVI_ChunkReadRoot( p_demux->s, &p_sys->ck_root ) )
00253     {
00254         msg_Err( p_demux, "avi module discarded (invalid file)" );
00255         return VLC_EGENERIC;
00256     }
00257 
00258     if( AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF ) > 1 )
00259     {
00260         unsigned int i_count =
00261             AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF );
00262 
00263         msg_Warn( p_demux, "multiple riff -> OpenDML ?" );
00264         for( i = 1; i < i_count; i++ )
00265         {
00266             avi_chunk_list_t *p_sysx;
00267 
00268             p_sysx = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, i );
00269             if( p_sysx->i_type == AVIFOURCC_AVIX )
00270             {
00271                 msg_Warn( p_demux, "detected OpenDML file" );
00272                 p_sys->b_odml = VLC_TRUE;
00273                 break;
00274             }
00275         }
00276     }
00277 
00278     p_riff  = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0 );
00279     p_hdrl  = AVI_ChunkFind( p_riff, AVIFOURCC_hdrl, 0 );
00280     p_movi  = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0 );
00281 
00282     if( !p_hdrl || !p_movi )
00283     {
00284         msg_Err( p_demux, "avi module discarded (invalid file)" );
00285         goto error;
00286     }
00287 
00288     if( !( p_avih = AVI_ChunkFind( p_hdrl, AVIFOURCC_avih, 0 ) ) )
00289     {
00290         msg_Err( p_demux, "cannot find avih chunk" );
00291         goto error;
00292     }
00293     i_track = AVI_ChunkCount( p_hdrl, AVIFOURCC_strl );
00294     if( p_avih->i_streams != i_track )
00295     {
00296         msg_Warn( p_demux,
00297                   "found %d stream but %d are declared",
00298                   i_track, p_avih->i_streams );
00299     }
00300     if( i_track == 0 )
00301     {
00302         msg_Err( p_demux, "no stream defined!" );
00303         goto error;
00304     }
00305 
00306     /* print information on streams */
00307     msg_Dbg( p_demux, "AVIH: %d stream, flags %s%s%s%s ",
00308              i_track,
00309              p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
00310              p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
00311              p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
00312              p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
00313     if( ( p_sys->meta = vlc_meta_New() ) )
00314     {
00315         char buffer[200];
00316         sprintf( buffer, "%s%s%s%s",
00317                  p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
00318                  p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
00319                  p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
00320                  p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
00321         vlc_meta_Add( p_sys->meta, VLC_META_SETTING, buffer );
00322     }
00323 
00324     /* now read info on each stream and create ES */
00325     for( i = 0 ; i < i_track; i++ )
00326     {
00327         avi_track_t      *tk = malloc( sizeof( avi_track_t ) );
00328         avi_chunk_list_t *p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i );
00329         avi_chunk_strh_t *p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 );
00330         avi_chunk_STRING_t *p_strn = AVI_ChunkFind( p_strl, AVIFOURCC_strn, 0 );
00331         avi_chunk_strf_auds_t *p_auds;
00332         avi_chunk_strf_vids_t *p_vids;
00333         es_format_t fmt;
00334 
00335         tk->b_activated = VLC_FALSE;
00336         tk->p_index     = 0;
00337         tk->i_idxnb     = 0;
00338         tk->i_idxmax    = 0;
00339         tk->i_idxposc   = 0;
00340         tk->i_idxposb   = 0;
00341 
00342         tk->i_blockno   = 0;
00343         tk->i_blocksize = 0;
00344 
00345         p_vids = (avi_chunk_strf_vids_t*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 );
00346         p_auds = (avi_chunk_strf_auds_t*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 );
00347 
00348         if( p_strl == NULL || p_strh == NULL || p_auds == NULL || p_vids == NULL )
00349         {
00350             msg_Warn( p_demux, "stream[%d] incomplete", i );
00351             continue;
00352         }
00353 
00354         tk->i_rate  = p_strh->i_rate;
00355         tk->i_scale = p_strh->i_scale;
00356         tk->i_samplesize = p_strh->i_samplesize;
00357         msg_Dbg( p_demux, "stream[%d] rate:%d scale:%d samplesize:%d",
00358                  i, tk->i_rate, tk->i_scale, tk->i_samplesize );
00359 
00360         switch( p_strh->i_type )
00361         {
00362             case( AVIFOURCC_auds ):
00363                 tk->i_cat   = AUDIO_ES;
00364                 tk->i_codec = AVI_FourccGetCodec( AUDIO_ES,
00365                                                   p_auds->p_wf->wFormatTag );
00366                 if( ( tk->i_blocksize = p_auds->p_wf->nBlockAlign ) == 0 )
00367                 {
00368                     if( p_auds->p_wf->wFormatTag == 1 )
00369                     {
00370                         tk->i_blocksize = p_auds->p_wf->nChannels * (p_auds->p_wf->wBitsPerSample/8);
00371                     }
00372                     else
00373                     {
00374                         tk->i_blocksize = 1;
00375                     }
00376                 }
00377                 es_format_Init( &fmt, AUDIO_ES, tk->i_codec );
00378 
00379                 fmt.audio.i_channels        = p_auds->p_wf->nChannels;
00380                 fmt.audio.i_rate            = p_auds->p_wf->nSamplesPerSec;
00381                 fmt.i_bitrate               = p_auds->p_wf->nAvgBytesPerSec*8;
00382                 fmt.audio.i_blockalign      = p_auds->p_wf->nBlockAlign;
00383                 fmt.audio.i_bitspersample   = p_auds->p_wf->wBitsPerSample;
00384                 fmt.i_extra = __MIN( p_auds->p_wf->cbSize,
00385                     p_auds->i_chunk_size - sizeof(WAVEFORMATEX) );
00386                 fmt.p_extra = &p_auds->p_wf[1];
00387                 msg_Dbg( p_demux, "stream[%d] audio(0x%x) %d channels %dHz %dbits",
00388                          i, p_auds->p_wf->wFormatTag, p_auds->p_wf->nChannels,
00389                          p_auds->p_wf->nSamplesPerSec, p_auds->p_wf->wBitsPerSample);
00390                 break;
00391 
00392             case( AVIFOURCC_vids ):
00393                 tk->i_cat   = VIDEO_ES;
00394                 tk->i_codec = AVI_FourccGetCodec( VIDEO_ES,
00395                                                   p_vids->p_bih->biCompression );
00396                 if( p_vids->p_bih->biCompression == 0x00 )
00397                 {
00398                     switch( p_vids->p_bih->biBitCount )
00399                     {
00400                         case 32:
00401                             tk->i_codec = VLC_FOURCC('R','V','3','2');
00402                             break;
00403                         case 24:
00404                             tk->i_codec = VLC_FOURCC('R','V','2','4');
00405                             break;
00406                         case 16:
00407                             /* tk->i_codec = VLC_FOURCC('R','V','1','6');*/
00408                             /* break;*/
00409                         case 15:
00410                             tk->i_codec = VLC_FOURCC('R','V','1','5');
00411                             break;
00412                         case 9:
00413                             tk->i_codec = VLC_FOURCC( 'Y', 'V', 'U', '9' ); /* <- TODO check that */
00414                             break;
00415                     }
00416                     es_format_Init( &fmt, VIDEO_ES, tk->i_codec );
00417 
00418                     if( p_vids->p_bih->biBitCount == 24 )
00419                     {
00420                         /* This is in BGR format */
00421                         fmt.video.i_bmask = 0x00ff0000;
00422                         fmt.video.i_gmask = 0x0000ff00;
00423                         fmt.video.i_rmask = 0x000000ff;
00424                     }
00425                 }
00426                 else
00427                 {
00428                     es_format_Init( &fmt, VIDEO_ES, p_vids->p_bih->biCompression );
00429                     if( tk->i_codec == FOURCC_mp4v &&
00430                         !strncasecmp( (char*)&p_strh->i_handler, "XVID", 4 ) )
00431                     {
00432                         fmt.i_codec = VLC_FOURCC( 'X', 'V', 'I', 'D' );
00433                     }
00434                 }
00435                 tk->i_samplesize = 0;
00436                 fmt.video.i_width  = p_vids->p_bih->biWidth;
00437                 fmt.video.i_height = p_vids->p_bih->biHeight;
00438                 fmt.video.i_bits_per_pixel = p_vids->p_bih->biBitCount;
00439                 fmt.video.i_frame_rate = tk->i_rate;
00440                 fmt.video.i_frame_rate_base = tk->i_scale;
00441                 fmt.i_extra =
00442                     __MIN( p_vids->p_bih->biSize - sizeof( BITMAPINFOHEADER ),
00443                            p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER) );
00444                 fmt.p_extra = &p_vids->p_bih[1];
00445                 msg_Dbg( p_demux, "stream[%d] video(%4.4s) %dx%d %dbpp %ffps",
00446                          i, (char*)&p_vids->p_bih->biCompression,
00447                          p_vids->p_bih->biWidth,
00448                          p_vids->p_bih->biHeight,
00449                          p_vids->p_bih->biBitCount,
00450                          (float)tk->i_rate/(float)tk->i_scale );
00451 
00452                 if( p_vids->p_bih->biCompression == 0x00 )
00453                 {
00454                     /* RGB DIB are coded from bottom to top */
00455                     fmt.video.i_height =
00456                         (unsigned int)(-(int)p_vids->p_bih->biHeight);
00457                 }
00458 
00459                 /* Extract palette from extradata if bpp <= 8
00460                  * (assumes that extradata contains only palette but appears
00461                  *  to be true for all palettized codecs we support) */
00462                 if( fmt.i_extra && fmt.video.i_bits_per_pixel <= 8 &&
00463                     fmt.video.i_bits_per_pixel > 0 )
00464                 {
00465                     int i;
00466 
00467                     fmt.video.p_palette = calloc( sizeof(video_palette_t), 1 );
00468                     fmt.video.p_palette->i_entries = 1;
00469 
00470                     /* Apparently this is necessary. But why ? */
00471                     fmt.i_extra =
00472                         p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER);
00473                     for( i = 0; i < __MIN(fmt.i_extra/4, 256); i++ )
00474                     {
00475                         ((uint32_t *)&fmt.video.p_palette->palette[0][0])[i] =
00476                             GetDWLE((uint32_t*)fmt.p_extra + i);
00477                     }
00478                 }
00479                 break;
00480 
00481             case( AVIFOURCC_txts):
00482                 tk->i_cat   = SPU_ES;
00483                 tk->i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
00484                 msg_Dbg( p_demux, "stream[%d] subtitles", i );
00485                 es_format_Init( &fmt, SPU_ES, tk->i_codec );
00486                 break;
00487 
00488             case( AVIFOURCC_mids):
00489                 msg_Dbg( p_demux, "stream[%d] midi is UNSUPPORTED", i );
00490 
00491             default:
00492                 msg_Warn( p_demux, "stream[%d] unknown type", i );
00493                 free( tk );
00494                 continue;
00495         }
00496         if( p_strn )
00497         {
00498             fmt.psz_description = strdup( p_strn->p_str );
00499         }
00500         tk->p_es = es_out_Add( p_demux->out, &fmt );
00501         TAB_APPEND( p_sys->i_track, p_sys->track, tk );
00502     }
00503 
00504     if( p_sys->i_track <= 0 )
00505     {
00506         msg_Err( p_demux, "no valid track" );
00507         goto error;
00508     }
00509 
00510     if( config_GetInt( p_demux, "avi-index" ) )
00511     {
00512         if( p_sys->b_seekable )
00513         {
00514             AVI_IndexCreate( p_demux );
00515         }
00516         else
00517         {
00518             msg_Warn( p_demux, "cannot create index (unseekable stream)" );
00519             AVI_IndexLoad( p_demux );
00520         }
00521     }
00522     else
00523     {
00524         AVI_IndexLoad( p_demux );
00525     }
00526 
00527     /* *** movie length in sec *** */
00528     p_sys->i_length = AVI_MovieGetLength( p_demux );
00529     if( p_sys->i_length < (mtime_t)p_avih->i_totalframes *
00530                           (mtime_t)p_avih->i_microsecperframe /
00531                           (mtime_t)1000000 )
00532     {
00533         msg_Warn( p_demux, "broken or missing index, 'seek' will be axproximative or will have strange behavour" );
00534     }
00535     /* fix some BeOS MediaKit generated file */
00536     for( i = 0 ; i < p_sys->i_track; i++ )
00537     {
00538         avi_track_t         *tk = p_sys->track[i];
00539         avi_chunk_list_t    *p_strl;
00540         avi_chunk_strh_t    *p_strh;
00541         avi_chunk_strf_auds_t    *p_auds;
00542 
00543         if( tk->i_cat != AUDIO_ES )
00544         {
00545             continue;
00546         }
00547         if( tk->i_idxnb < 1 ||
00548             tk->i_scale != 1 ||
00549             tk->i_samplesize != 0 )
00550         {
00551             continue;
00552         }
00553         p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i );
00554         p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 );
00555         p_auds = AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 );
00556 
00557         if( p_auds->p_wf->wFormatTag != WAVE_FORMAT_PCM &&
00558             (unsigned int)tk->i_rate == p_auds->p_wf->nSamplesPerSec )
00559         {
00560             int64_t i_track_length =
00561                 tk->p_index[tk->i_idxnb-1].i_length +
00562                 tk->p_index[tk->i_idxnb-1].i_lengthtotal;
00563             mtime_t i_length = (mtime_t)p_avih->i_totalframes *
00564                                (mtime_t)p_avih->i_microsecperframe;
00565 
00566             if( i_length == 0 )
00567             {
00568                 msg_Warn( p_demux, "track[%d] cannot be fixed (BeOS MediaKit generated)", i );
00569                 continue;
00570             }
00571             tk->i_samplesize = 1;
00572             tk->i_rate       = i_track_length  * (int64_t)1000000/ i_length;
00573             msg_Warn( p_demux, "track[%d] fixed with rate=%d scale=%d (BeOS MediaKit generated)", i, tk->i_rate, tk->i_scale );
00574         }
00575     }
00576 
00577     if( p_sys->b_seekable )
00578     {
00579         /* we have read all chunk so go back to movi */
00580         stream_Seek( p_demux->s, p_movi->i_chunk_pos );
00581     }
00582     /* Skip movi header */
00583     stream_Read( p_demux->s, NULL, 12 );
00584 
00585     p_sys->i_movi_begin = p_movi->i_chunk_pos;
00586     return VLC_SUCCESS;
00587 
00588 error:
00589     if( p_sys->meta )
00590     {
00591         vlc_meta_Delete( p_sys->meta );
00592     }
00593     AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root );
00594     free( p_sys );
00595     return VLC_EGENERIC;
00596 }
00597 
00598 /*****************************************************************************
00599  * Close: frees unused data
00600  *****************************************************************************/
00601 static void Close ( vlc_object_t * p_this )
00602 {
00603     demux_t *    p_demux = (demux_t *)p_this;
00604     unsigned int i;
00605     demux_sys_t *p_sys = p_demux->p_sys  ;
00606 
00607     for( i = 0; i < p_sys->i_track; i++ )
00608     {
00609         if( p_sys->track[i] )
00610         {
00611             FREE( p_sys->track[i]->p_index );
00612             free( p_sys->track[i] );
00613         }
00614     }
00615     FREE( p_sys->track );
00616     AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root );
00617     vlc_meta_Delete( p_sys->meta );
00618 
00619     free( p_sys );
00620 }
00621 
00622 /*****************************************************************************
00623  * Demux_Seekable: reads and demuxes data packets for stream seekable
00624  *****************************************************************************
00625  * AVIDemux: reads and demuxes data packets
00626  *****************************************************************************
00627  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
00628  *****************************************************************************/
00629 typedef struct
00630 {
00631     vlc_bool_t b_ok;
00632 
00633     int i_toread;
00634 
00635     off_t i_posf; /* where we will read :
00636                    if i_idxposb == 0 : begining of chunk (+8 to acces data)
00637                    else : point on data directly */
00638 } avi_track_toread_t;
00639 
00640 static int Demux_Seekable( demux_t *p_demux )
00641 {
00642     demux_sys_t *p_sys = p_demux->p_sys;
00643 
00644     unsigned int i_track_count = 0;
00645     unsigned int i_track;
00646     vlc_bool_t b_stream;
00647     /* cannot be more than 100 stream (dcXX or wbXX) */
00648     avi_track_toread_t toread[100];
00649 
00650 
00651     /* detect new selected/unselected streams */
00652     for( i_track = 0; i_track < p_sys->i_track; i_track++ )
00653     {
00654         avi_track_t *tk = p_sys->track[i_track];
00655         vlc_bool_t  b;
00656 
00657         es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
00658         if( b && !tk->b_activated )
00659         {
00660             if( p_sys->b_seekable)
00661             {
00662                 AVI_TrackSeek( p_demux, i_track, p_sys->i_time );
00663             }
00664             tk->b_activated = VLC_TRUE;
00665         }
00666         else if( !b && tk->b_activated )
00667         {
00668             tk->b_activated = VLC_FALSE;
00669         }
00670         if( b )
00671         {
00672             i_track_count++;
00673         }
00674     }
00675 
00676     if( i_track_count <= 0 )
00677     {
00678         int64_t i_length = p_sys->i_length * (mtime_t)1000000;
00679 
00680         p_sys->i_time += 25*1000;  /* read 25ms */
00681         if( i_length > 0 )
00682         {
00683             if( p_sys->i_time >= i_length )
00684                 return 0;
00685             return 1;
00686         }
00687         msg_Warn( p_demux, "no track selected, exiting..." );
00688         return 0;
00689     }
00690 
00691     /* wait for the good time */
00692     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time + 1 );
00693     p_sys->i_time += 25*1000;  /* read 25ms */
00694 
00695     /* init toread */
00696     for( i_track = 0; i_track < p_sys->i_track; i_track++ )
00697     {
00698         avi_track_t *tk = p_sys->track[i_track];
00699         mtime_t i_dpts;
00700 
00701         toread[i_track].b_ok = tk->b_activated;
00702         if( tk->i_idxposc < tk->i_idxnb )
00703         {
00704             toread[i_track].i_posf = tk->p_index[tk->i_idxposc].i_pos;
00705            if( tk->i_idxposb > 0 )
00706            {
00707                 toread[i_track].i_posf += 8 + tk->i_idxposb;
00708            }
00709         }
00710         else
00711         {
00712             toread[i_track].i_posf = -1;
00713         }
00714 
00715         i_dpts = p_sys->i_time - AVI_GetPTS( tk  );
00716 
00717         if( tk->i_samplesize )
00718         {
00719             toread[i_track].i_toread = AVI_PTSToByte( tk, __ABS( i_dpts ) );
00720         }
00721         else
00722         {
00723             toread[i_track].i_toread = AVI_PTSToChunk( tk, __ABS( i_dpts ) );
00724         }
00725 
00726         if( i_dpts < 0 )
00727         {
00728             toread[i_track].i_toread *= -1;
00729         }
00730     }
00731 
00732     b_stream = VLC_FALSE;
00733 
00734     for( ;; )
00735     {
00736         avi_track_t     *tk;
00737         vlc_bool_t       b_done;
00738         block_t         *p_frame;
00739         off_t i_pos;
00740         unsigned int i;
00741         size_t i_size;
00742 
00743         /* search for first chunk to be read */
00744         for( i = 0, b_done = VLC_TRUE, i_pos = -1; i < p_sys->i_track; i++ )
00745         {
00746             if( !toread[i].b_ok ||
00747                 AVI_GetDPTS( p_sys->track[i],
00748                              toread[i].i_toread ) <= -25 * 1000 )
00749             {
00750                 continue;
00751             }
00752 
00753             if( toread[i].i_toread > 0 )
00754             {
00755                 b_done = VLC_FALSE; /* not yet finished */
00756             }
00757             if( toread[i].i_posf > 0 )
00758             {
00759                 if( i_pos == -1 || i_pos > toread[i_track].i_posf )
00760                 {
00761                     i_track = i;
00762                     i_pos = toread[i].i_posf;
00763                 }
00764             }
00765         }
00766 
00767         if( b_done )
00768         {
00769             return( 1 );
00770         }
00771 
00772         if( i_pos == -1 )
00773         {
00774             int i_loop_count = 0;
00775 
00776             /* no valid index, we will parse directly the stream
00777              * in case we fail we will disable all finished stream */
00778             if( p_sys->i_movi_lastchunk_pos >= p_sys->i_movi_begin + 12 )
00779             {
00780                 stream_Seek( p_demux->s, p_sys->i_movi_lastchunk_pos );
00781                 if( AVI_PacketNext( p_demux ) )
00782                 {
00783                     return( AVI_TrackStopFinishedStreams( p_demux ) ? 0 : 1 );
00784                 }
00785             }
00786             else
00787             {
00788                 stream_Seek( p_demux->s, p_sys->i_movi_begin + 12 );
00789             }
00790 
00791             for( ;; )
00792             {
00793                 avi_packet_t avi_pk;
00794 
00795                 if( AVI_PacketGetHeader( p_demux, &avi_pk ) )
00796                 {
00797                     msg_Warn( p_demux,
00798                              "cannot get packet header, track disabled" );
00799                     return( AVI_TrackStopFinishedStreams( p_demux ) ? 0 : 1 );
00800                 }
00801                 if( avi_pk.i_stream >= p_sys->i_track ||
00802                     ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
00803                 {
00804                     if( AVI_PacketNext( p_demux ) )
00805                     {
00806                         msg_Warn( p_demux,
00807                                   "cannot skip packet, track disabled" );
00808                         return( AVI_TrackStopFinishedStreams( p_demux ) ? 0 : 1 );
00809                     }
00810 
00811                     /* Prevents from eating all the CPU with broken files.
00812                      * This value should be low enough so that it doesn't
00813                      * affect the reading speed too much. */
00814                     if( !(++i_loop_count % 1024) )
00815                     {
00816                         if( p_demux->b_die ) return -1;
00817                         msleep( 10000 );
00818 
00819                         if( !(i_loop_count % (1024 * 10)) )
00820                             msg_Warn( p_demux,
00821                                       "don't seem to find any data..." );
00822                     }
00823                     continue;
00824                 }
00825                 else
00826                 {
00827                     /* add this chunk to the index */
00828                     avi_entry_t index;
00829 
00830                     index.i_id = avi_pk.i_fourcc;
00831                     index.i_flags =
00832                        AVI_GetKeyFlag(p_sys->track[avi_pk.i_stream]->i_codec,
00833                                       avi_pk.i_peek);
00834                     index.i_pos = avi_pk.i_pos;
00835                     index.i_length = avi_pk.i_size;
00836                     AVI_IndexAddEntry( p_sys, avi_pk.i_stream, &index );
00837 
00838                     i_track = avi_pk.i_stream;
00839                     tk = p_sys->track[i_track];
00840                     /* do we will read this data ? */
00841                     if( AVI_GetDPTS( tk, toread[i_track].i_toread ) > -25*1000 )
00842                     {
00843                         break;
00844                     }
00845                     else
00846                     {
00847                         if( AVI_PacketNext( p_demux ) )
00848                         {
00849                             msg_Warn( p_demux,
00850                                       "cannot skip packet, track disabled" );
00851                             return( AVI_TrackStopFinishedStreams( p_demux ) ? 0 : 1 );
00852                         }
00853                     }
00854                 }
00855             }
00856 
00857         }
00858         else
00859         {
00860             stream_Seek( p_demux->s, i_pos );
00861         }
00862 
00863         /* Set the track to use */
00864         tk = p_sys->track[i_track];
00865 
00866         /* read thoses data */
00867         if( tk->i_samplesize )
00868         {
00869             unsigned int i_toread;
00870 
00871             if( ( i_toread = toread[i_track].i_toread ) <= 0 )
00872             {
00873                 if( tk->i_samplesize > 1 )
00874                 {
00875                     i_toread = tk->i_samplesize;
00876                 }
00877                 else
00878                 {
00879                     i_toread = AVI_PTSToByte( tk, 20 * 1000 );
00880                     i_toread = __MAX( i_toread, 100 );
00881                 }
00882             }
00883             i_size = __MIN( tk->p_index[tk->i_idxposc].i_length -
00884                                 tk->i_idxposb,
00885                             i_toread );
00886         }
00887         else
00888         {
00889             i_size = tk->p_index[tk->i_idxposc].i_length;
00890         }
00891 
00892         if( tk->i_idxposb == 0 )
00893         {
00894             i_size += 8; /* need to read and skip header */
00895         }
00896 
00897         if( ( p_frame = stream_Block( p_demux->s, __EVEN( i_size ) ) )==NULL )
00898         {
00899             msg_Warn( p_demux, "failed reading data" );
00900             tk->b_activated = VLC_FALSE;
00901             toread[i_track].b_ok = VLC_FALSE;
00902             continue;
00903         }
00904         if( i_size % 2 )    /* read was padded on word boundary */
00905         {
00906             p_frame->i_buffer--;
00907         }
00908         /* skip header */
00909         if( tk->i_idxposb == 0 )
00910         {
00911             p_frame->p_buffer += 8;
00912             p_frame->i_buffer -= 8;
00913         }
00914         p_frame->i_pts = AVI_GetPTS( tk ) + 1;
00915         if( tk->p_index[tk->i_idxposc].i_flags&AVIIF_KEYFRAME )
00916         {
00917             p_frame->i_flags = BLOCK_FLAG_TYPE_I;
00918         }
00919         else
00920         {
00921             p_frame->i_flags = BLOCK_FLAG_TYPE_PB;
00922         }
00923 
00924         /* read data */
00925         if( tk->i_samplesize )
00926         {
00927             if( tk->i_idxposb == 0 )
00928             {
00929                 i_size -= 8;
00930             }
00931             toread[i_track].i_toread -= i_size;
00932             tk->i_idxposb += i_size;
00933             if( tk->i_idxposb >=
00934                     tk->p_index[tk->i_idxposc].i_length )
00935             {
00936                 tk->i_idxposb = 0;
00937                 tk->i_idxposc++;
00938             }
00939         }
00940         else
00941         {
00942             int i_length = tk->p_index[tk->i_idxposc].i_length;
00943 
00944             tk->i_idxposc++;
00945             if( tk->i_cat == AUDIO_ES )
00946             {
00947                 tk->i_blockno += tk->i_blocksize > 0 ? ( i_length + tk->i_blocksize - 1 ) / tk->i_blocksize : 1;
00948             }
00949             toread[i_track].i_toread--;
00950         }
00951 
00952         if( tk->i_idxposc < tk->i_idxnb)
00953         {
00954             toread[i_track].i_posf =
00955                 tk->p_index[tk->i_idxposc].i_pos;
00956             if( tk->i_idxposb > 0 )
00957             {
00958                 toread[i_track].i_posf += 8 + tk->i_idxposb;
00959             }
00960 
00961         }
00962         else
00963         {
00964             toread[i_track].i_posf = -1;
00965         }
00966 
00967         b_stream = VLC_TRUE; /* at least one read succeed */
00968 
00969         if( tk->i_cat != VIDEO_ES )
00970             p_frame->i_dts = p_frame->i_pts;
00971         else
00972         {
00973             p_frame->i_dts = p_frame->i_pts;
00974             p_frame->i_pts = 0;
00975         }
00976 
00977         //p_pes->i_rate = p_demux->stream.control.i_rate;
00978         es_out_Send( p_demux->out, tk->p_es, p_frame );
00979     }
00980 }
00981 
00982 
00983 /*****************************************************************************
00984  * Demux_UnSeekable: reads and demuxes data packets for unseekable file
00985  *****************************************************************************
00986  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
00987  *****************************************************************************/
00988 static int Demux_UnSeekable( demux_t *p_demux )
00989 {
00990     demux_sys_t     *p_sys = p_demux->p_sys;
00991     avi_track_t *p_stream_master = NULL;
00992     unsigned int i_stream;
00993     unsigned int i_packet;
00994 
00995     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time + 1 );
00996 
00997     /* *** find master stream for data packet skipping algo *** */
00998     /* *** -> first video, if any, or first audio ES *** */
00999     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
01000     {
01001         avi_track_t *tk = p_sys->track[i_stream];
01002         vlc_bool_t  b;
01003 
01004         es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
01005 
01006         if( b && tk->i_cat == VIDEO_ES )
01007         {
01008             p_stream_master = tk;
01009         }
01010         else if( b )
01011         {
01012             p_stream_master = tk;
01013         }
01014     }
01015 
01016     if( !p_stream_master )
01017     {
01018         msg_Warn( p_demux, "no more stream selected" );
01019         return( 0 );
01020     }
01021 
01022     p_sys->i_time = AVI_GetPTS( p_stream_master );
01023 
01024     for( i_packet = 0; i_packet < 10; i_packet++)
01025     {
01026 #define p_stream    p_sys->track[avi_pk.i_stream]
01027 
01028         avi_packet_t    avi_pk;
01029 
01030         if( AVI_PacketGetHeader( p_demux, &avi_pk ) )
01031         {
01032             return( 0 );
01033         }
01034 
01035         if( avi_pk.i_stream >= p_sys->i_track ||
01036             ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
01037         {
01038             /* we haven't found an audio or video packet:
01039              *  - we have seek, found first next packet
01040              *  - others packets could be found, skip them
01041              */
01042             switch( avi_pk.i_fourcc )
01043             {
01044                 case AVIFOURCC_JUNK:
01045                 case AVIFOURCC_LIST:
01046                 case AVIFOURCC_RIFF:
01047                     return( !AVI_PacketNext( p_demux ) ? 1 : 0 );
01048                 case AVIFOURCC_idx1:
01049                     if( p_sys->b_odml )
01050                     {
01051                         return( !AVI_PacketNext( p_demux ) ? 1 : 0 );
01052                     }
01053                     return( 0 );    /* eof */
01054                 default:
01055                     msg_Warn( p_demux,
01056                               "seems to have lost position, resync" );
01057                     if( AVI_PacketSearch( p_demux ) )
01058                     {
01059                         msg_Err( p_demux, "resync failed" );
01060                         return( -1 );
01061                     }
01062             }
01063         }
01064         else
01065         {
01066             /* check for time */
01067             if( __ABS( AVI_GetPTS( p_stream ) -
01068                         AVI_GetPTS( p_stream_master ) )< 600*1000 )
01069             {
01070                 /* load it and send to decoder */
01071                 block_t *p_frame;
01072                 if( AVI_PacketRead( p_demux, &avi_pk, &p_frame ) || p_frame == NULL )
01073                 {
01074                     return( -1 );
01075                 }
01076                 p_frame->i_pts = AVI_GetPTS( p_stream ) + 1;
01077 
01078                 if( avi_pk.i_cat != VIDEO_ES )
01079                     p_frame->i_dts = p_frame->i_pts;
01080                 else
01081                 {
01082                     p_frame->i_dts = p_frame->i_pts;
01083                     p_frame->i_pts = 0;
01084                 }
01085 
01086                 //p_pes->i_rate = p_demux->stream.control.i_rate;
01087                 es_out_Send( p_demux->out, p_stream->p_es, p_frame );
01088             }
01089             else
01090             {
01091                 if( AVI_PacketNext( p_demux ) )
01092                 {
01093                     return( 0 );
01094                 }
01095             }
01096 
01097             /* *** update stream time position *** */
01098             if( p_stream->i_samplesize )
01099             {
01100                 p_stream->i_idxposb += avi_pk.i_size;
01101             }
01102             else
01103             {
01104                 if( p_stream->i_cat == AUDIO_ES )
01105                 {
01106                     p_stream->i_blockno += p_stream->i_blocksize > 0 ? ( avi_pk.i_size + p_stream->i_blocksize - 1 ) / p_stream->i_blocksize : 1;
01107                 }
01108                 p_stream->i_idxposc++;
01109             }
01110 
01111         }
01112 #undef p_stream
01113     }
01114 
01115     return( 1 );
01116 }
01117 
01118 /*****************************************************************************
01119  * Seek: goto to i_date or i_percent
01120  *****************************************************************************/
01121 static int Seek( demux_t *p_demux, mtime_t i_date, int i_percent )
01122 {
01123 
01124     demux_sys_t *p_sys = p_demux->p_sys;
01125     unsigned int i_stream;
01126     msg_Dbg( p_demux, "seek requested: "I64Fd" secondes %d%%",
01127              i_date / 1000000, i_percent );
01128 
01129     if( p_sys->b_seekable )
01130     {
01131         if( !p_sys->i_length )
01132         {
01133             avi_track_t *p_stream;
01134             int64_t i_pos;
01135 
01136             /* use i_percent to create a true i_date */
01137             msg_Warn( p_demux, "mmh, seeking without index at %d%%"
01138                       " work only for interleaved file", i_percent );
01139             if( i_percent >= 100 )
01140             {
01141                 msg_Warn( p_demux, "cannot seek so far !" );
01142                 return VLC_EGENERIC;
01143             }
01144             i_percent = __MAX( i_percent, 0 );
01145 
01146             /* try to find chunk that is at i_percent or the file */
01147             i_pos = __MAX( i_percent * stream_Size( p_demux->s ) / 100,
01148                            p_sys->i_movi_begin );
01149             /* search first selected stream */
01150             for( i_stream = 0, p_stream = NULL;
01151                         i_stream < p_sys->i_track; i_stream++ )
01152             {
01153                 p_stream = p_sys->track[i_stream];
01154                 if( p_stream->b_activated )
01155                 {
01156                     break;
01157                 }
01158             }
01159             if( !p_stream || !p_stream->b_activated )
01160             {
01161                 msg_Warn( p_demux, "cannot find any selected stream" );
01162                 return VLC_EGENERIC;
01163             }
01164 
01165             /* be sure that the index exist */
01166             if( AVI_StreamChunkSet( p_demux, i_stream, 0 ) )
01167             {
01168                 msg_Warn( p_demux, "cannot seek" );
01169                 return VLC_EGENERIC;
01170             }
01171 
01172             while( i_pos >= p_stream->p_index[p_stream->i_idxposc].i_pos +
01173                p_stream->p_index[p_stream->i_idxposc].i_length + 8 )
01174             {
01175                 /* search after i_idxposc */
01176                 if( AVI_StreamChunkSet( p_demux,
01177                                         i_stream, p_stream->i_idxposc + 1 ) )
01178                 {
01179                     msg_Warn( p_demux, "cannot seek" );
01180                     return VLC_EGENERIC;
01181                 }
01182             }
01183 
01184             i_date = AVI_GetPTS( p_stream );
01185             /* TODO better support for i_samplesize != 0 */
01186             msg_Dbg( p_demux, "estimate date "I64Fd, i_date );
01187         }
01188 
01189 #define p_stream    p_sys->track[i_stream]
01190         p_sys->i_time = 0;
01191         /* seek for chunk based streams */
01192         for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
01193         {
01194             if( p_stream->b_activated && !p_stream->i_samplesize )
01195 /*            if( p_stream->b_activated ) */
01196             {
01197                 AVI_TrackSeek( p_demux, i_stream, i_date );
01198                 p_sys->i_time = __MAX( AVI_GetPTS( p_stream ),
01199                                         p_sys->i_time );
01200             }
01201         }
01202 #if 1
01203         if( p_sys->i_time )
01204         {
01205             i_date = p_sys->i_time;
01206         }
01207         /* seek for bytes based streams */
01208         for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
01209         {
01210             if( p_stream->b_activated && p_stream->i_samplesize )
01211             {
01212                 AVI_TrackSeek( p_demux, i_stream, i_date );
01213 /*                p_sys->i_time = __MAX( AVI_GetPTS( p_stream ), p_sys->i_time );*/
01214             }
01215         }
01216         msg_Dbg( p_demux, "seek: "I64Fd" seconds", p_sys->i_time /1000000 );
01217         /* set true movie time */
01218 #endif
01219         if( !p_sys->i_time )
01220         {
01221             p_sys->i_time = i_date;
01222         }
01223 #undef p_stream
01224         return VLC_SUCCESS;
01225     }
01226     else
01227     {
01228         msg_Err( p_demux, "shouldn't yet be executed" );
01229         return VLC_EGENERIC;
01230     }
01231 }
01232 
01233 /*****************************************************************************
01234  * Control:
01235  *****************************************************************************
01236  *
01237  *****************************************************************************/
01238 static double ControlGetPosition( demux_t *p_demux )
01239 {
01240     demux_sys_t *p_sys = p_demux->p_sys;
01241 
01242     if( p_sys->i_length > 0 )
01243     {
01244         return (double)p_sys->i_time / (double)( p_sys->i_length * (mtime_t)1000000 );
01245     }
01246     else if( stream_Size( p_demux->s ) > 0 )
01247     {
01248         unsigned int i;
01249         int64_t i_tmp;
01250         int64_t i64 = 0;
01251 
01252         /* search the more advanced selected es */
01253         for( i = 0; i < p_sys->i_track; i++ )
01254         {
01255             avi_track_t *tk = p_sys->track[i];
01256             if( tk->b_activated && tk->i_idxposc < tk->i_idxnb )
01257             {
01258                 i_tmp = tk->p_index[tk->i_idxposc].i_pos +
01259                         tk->p_index[tk->i_idxposc].i_length + 8;
01260                 if( i_tmp > i64 )
01261                 {
01262                     i64 = i_tmp;
01263                 }
01264             }
01265         }
01266         return (double)i64 / (double)stream_Size( p_demux->s );
01267     }
01268     return 0.0;
01269 }
01270 
01271 static int    Control( demux_t *p_demux, int i_query, va_list args )
01272 {
01273     demux_sys_t *p_sys = p_demux->p_sys;
01274     int i;
01275     double   f, *pf;
01276     int64_t i64, *pi64;
01277     vlc_meta_t **pp_meta;
01278 
01279     switch( i_query )
01280     {
01281         case DEMUX_GET_POSITION:
01282             pf = (double*)va_arg( args, double * );
01283             *pf = ControlGetPosition( p_demux );
01284             return VLC_SUCCESS;
01285         case DEMUX_SET_POSITION:
01286             f = (double)va_arg( args, double );
01287             if( p_sys->b_seekable )
01288             {
01289                 i64 = (mtime_t)(1000000.0 * p_sys->i_length * f );
01290                 return Seek( p_demux, i64, (int)(f * 100) );
01291             }
01292             else
01293             {
01294                 int64_t i_pos = stream_Size( p_demux->s ) * f;
01295                 return stream_Seek( p_demux->s, i_pos );
01296             }
01297 
01298         case DEMUX_GET_TIME:
01299             pi64 = (int64_t*)va_arg( args, int64_t * );
01300             *pi64 = p_sys->i_time;
01301             return VLC_SUCCESS;
01302 
01303         case DEMUX_SET_TIME:
01304         {
01305             int i_percent = 0;
01306 
01307             i64 = (int64_t)va_arg( args, int64_t );
01308             if( p_sys->i_length > 0 )
01309             {
01310                 i_percent = 100 * i64 / (p_sys->i_length*1000000);
01311             }
01312             else if( p_sys->i_time > 0 )
01313             {
01314                 i_percent = (int)( 100.0 * ControlGetPosition( p_demux ) *
01315                                    (double)i64 / (double)p_sys->i_time );
01316             }
01317             return Seek( p_demux, i64, i_percent );
01318         }
01319         case DEMUX_GET_LENGTH:
01320             pi64 = (int64_t*)va_arg( args, int64_t * );
01321             *pi64 = p_sys->i_length * (mtime_t)1000000;
01322             return VLC_SUCCESS;
01323 
01324         case DEMUX_GET_FPS:
01325             pf = (double*)va_arg( args, double * );
01326             *pf = 0.0;
01327             for( i = 0; i < (int)p_sys->i_track; i++ )
01328             {
01329                 avi_track_t *tk = p_sys->track[i];
01330                 if( tk->i_cat == VIDEO_ES && tk->i_scale > 0)
01331                 {
01332                     *pf = (float)tk->i_rate / (float)tk->i_scale;
01333                     break;
01334                 }
01335             }
01336             return VLC_SUCCESS;
01337         case DEMUX_GET_META:
01338             pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
01339             *pp_meta = vlc_meta_Duplicate( p_sys->meta );
01340             return VLC_SUCCESS;
01341 
01342         default:
01343             return VLC_EGENERIC;
01344     }
01345 }
01346 
01347 /*****************************************************************************
01348  * Function to convert pts to chunk or byte
01349  *****************************************************************************/
01350 
01351 static mtime_t AVI_PTSToChunk( avi_track_t *tk, mtime_t i_pts )
01352 {
01353     if( !tk->i_scale )
01354         return (mtime_t)0;
01355 
01356     return (mtime_t)((int64_t)i_pts *
01357                      (int64_t)tk->i_rate /
01358                      (int64_t)tk->i_scale /
01359                      (int64_t)1000000 );
01360 }
01361 static mtime_t AVI_PTSToByte( avi_track_t *tk, mtime_t i_pts )
01362 {
01363     if( !tk->i_scale || !tk->i_samplesize )
01364         return (mtime_t)0;
01365 
01366     return (mtime_t)((int64_t)i_pts *
01367                      (int64_t)tk->i_rate /
01368                      (int64_t)tk->i_scale /
01369                      (int64_t)1000000 *
01370                      (int64_t)tk->i_samplesize );
01371 }
01372 
01373 static mtime_t AVI_GetDPTS( avi_track_t *tk, int64_t i_count )
01374 {
01375     mtime_t i_dpts = 0;
01376 
01377     if( !tk->i_rate )
01378         return i_dpts;
01379 
01380     i_dpts = (mtime_t)( (int64_t)1000000 *
01381                         (int64_t)i_count *
01382                         (int64_t)tk->i_scale /
01383                         (int64_t)tk->i_rate );
01384 
01385     if( tk->i_samplesize )
01386     {
01387         return i_dpts / tk->i_samplesize;
01388     }
01389     return i_dpts;
01390 }
01391 
01392 static mtime_t AVI_GetPTS( avi_track_t *tk )
01393 {
01394     if( tk->i_samplesize )
01395     {
01396         int64_t i_count = 0;
01397 
01398         /* we need a valid entry we will emulate one */
01399         if( tk->i_idxposc == tk->i_idxnb )
01400         {
01401             if( tk->i_idxposc )
01402             {
01403                 /* use the last entry */
01404                 i_count = tk->p_index[tk->i_idxnb - 1].i_lengthtotal
01405                             + tk->p_index[tk->i_idxnb - 1].i_length;
01406             }
01407         }
01408         else
01409         {
01410             i_count = tk->p_index[tk->i_idxposc].i_lengthtotal;
01411         }
01412         return AVI_GetDPTS( tk, i_count + tk->i_idxposb );
01413     }
01414     else
01415     {
01416         if( tk->i_cat == AUDIO_ES )
01417         {
01418             return AVI_GetDPTS( tk, tk->i_blockno );
01419         }
01420         else
01421         {
01422             return AVI_GetDPTS( tk, tk->i_idxposc );
01423         }
01424     }
01425 }
01426 
01427 static int AVI_StreamChunkFind( demux_t *p_demux, unsigned int i_stream )
01428 {
01429     demux_sys_t *p_sys = p_demux->p_sys;
01430     avi_packet_t avi_pk;
01431     int i_loop_count = 0;
01432 
01433     /* find first chunk of i_stream that isn't in index */
01434 
01435     if( p_sys->i_movi_lastchunk_pos >= p_sys->i_movi_begin + 12 )
01436     {
01437         stream_Seek( p_demux->s, p_sys->i_movi_lastchunk_pos );
01438         if( AVI_PacketNext( p_demux ) )
01439         {
01440             return VLC_EGENERIC;
01441         }
01442     }
01443     else
01444     {
01445         stream_Seek( p_demux->s, p_sys->i_movi_begin + 12 );
01446     }
01447 
01448     for( ;; )
01449     {
01450         if( p_demux->b_die ) return VLC_EGENERIC;
01451 
01452         if( AVI_PacketGetHeader( p_demux, &avi_pk ) )
01453         {
01454             msg_Warn( p_demux, "cannot get packet header" );
01455             return VLC_EGENERIC;
01456         }
01457         if( avi_pk.i_stream >= p_sys->i_track ||
01458             ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
01459         {
01460             if( AVI_PacketNext( p_demux ) )
01461             {
01462                 return VLC_EGENERIC;
01463             }
01464 
01465             /* Prevents from eating all the CPU with broken files.
01466              * This value should be low enough so that it doesn't
01467              * affect the reading speed too much. */
01468             if( !(++i_loop_count % 1024) )
01469             {
01470                 if( p_demux->b_die ) return VLC_EGENERIC;
01471                 msleep( 10000 );
01472 
01473                 if( !(i_loop_count % (1024 * 10)) )
01474                     msg_Warn( p_demux, "don't seem to find any data..." );
01475             }
01476         }
01477         else
01478         {
01479             /* add this chunk to the index */
01480             avi_entry_t index;
01481 
01482             index.i_id = avi_pk.i_fourcc;
01483             index.i_flags =
01484                AVI_GetKeyFlag(p_sys->track[avi_pk.i_stream]->i_codec,
01485                               avi_pk.i_peek);
01486             index.i_pos = avi_pk.i_pos;
01487             index.i_length = avi_pk.i_size;
01488             AVI_IndexAddEntry( p_sys, avi_pk.i_stream, &index );
01489 
01490             if( avi_pk.i_stream == i_stream  )
01491             {
01492                 return VLC_SUCCESS;
01493             }
01494 
01495             if( AVI_PacketNext( p_demux ) )
01496             {
01497                 return VLC_EGENERIC;
01498             }
01499         }
01500     }
01501 }
01502 
01503 /* be sure that i_ck will be a valid index entry */
01504 static int AVI_StreamChunkSet( demux_t *p_demux, unsigned int i_stream,
01505                                unsigned int i_ck )
01506 {
01507     demux_sys_t *p_sys = p_demux->p_sys;
01508     avi_track_t *p_stream = p_sys->track[i_stream];
01509 
01510     p_stream->i_idxposc = i_ck;
01511     p_stream->i_idxposb = 0;
01512 
01513     if(  i_ck >= p_stream->i_idxnb )
01514     {
01515         p_stream->i_idxposc = p_stream->i_idxnb - 1;
01516         do
01517         {
01518             p_stream->i_idxposc++;
01519             if( AVI_StreamChunkFind( p_demux, i_stream ) )
01520             {
01521                 return VLC_EGENERIC;
01522             }
01523 
01524         } while( p_stream->i_idxposc < i_ck );
01525     }
01526 
01527     return VLC_SUCCESS;
01528 }
01529 
01530 /* XXX FIXME up to now, we assume that all chunk are one after one */
01531 static int AVI_StreamBytesSet( demux_t    *p_demux,
01532                                unsigned int i_stream,
01533                                off_t   i_byte )
01534 {
01535     demux_sys_t *p_sys = p_demux->p_sys;
01536     avi_track_t *p_stream = p_sys->track[i_stream];
01537 
01538     if( ( p_stream->i_idxnb > 0 )
01539         &&( i_byte < p_stream->p_index[p_stream->i_idxnb - 1].i_lengthtotal +
01540                 p_stream->p_index[p_stream->i_idxnb - 1].i_length ) )
01541     {
01542         /* index is valid to find the ck */
01543         /* uses dichototmie to be fast enougth */
01544         int i_idxposc = __MIN( p_stream->i_idxposc, p_stream->i_idxnb - 1 );
01545         int i_idxmax  = p_stream->i_idxnb;
01546         int i_idxmin  = 0;
01547         for( ;; )
01548         {
01549             if( p_stream->p_index[i_idxposc].i_lengthtotal > i_byte )
01550             {
01551                 i_idxmax  = i_idxposc ;
01552                 i_idxposc = ( i_idxmin + i_idxposc ) / 2 ;
01553             }
01554             else
01555             {
01556                 if( p_stream->p_index[i_idxposc].i_lengthtotal +
01557                         p_stream->p_index[i_idxposc].i_length <= i_byte)
01558                 {
01559                     i_idxmin  = i_idxposc ;
01560                     i_idxposc = (i_idxmax + i_idxposc ) / 2 ;
01561                 }
01562                 else
01563                 {
01564                     p_stream->i_idxposc = i_idxposc;
01565                     p_stream->i_idxposb = i_byte -
01566                             p_stream->p_index[i_idxposc].i_lengthtotal;
01567                     return VLC_SUCCESS;
01568                 }
01569             }
01570         }
01571 
01572     }
01573     else
01574     {
01575         p_stream->i_idxposc = p_stream->i_idxnb - 1;
01576         p_stream->i_idxposb = 0;
01577         do
01578         {
01579             p_stream->i_idxposc++;
01580             if( AVI_StreamChunkFind( p_demux, i_stream ) )
01581             {
01582                 return VLC_EGENERIC;
01583             }
01584 
01585         } while( p_stream->p_index[p_stream->i_idxposc].i_lengthtotal +
01586                     p_stream->p_index[p_stream->i_idxposc].i_length <= i_byte );
01587 
01588         p_stream->i_idxposb = i_byte -
01589                        p_stream->p_index[p_stream->i_idxposc].i_lengthtotal;
01590         return VLC_SUCCESS;
01591     }
01592 }
01593 
01594 static int AVI_TrackSeek( demux_t *p_demux,
01595                            int i_stream,
01596                            mtime_t i_date )
01597 {
01598     demux_sys_t  *p_sys = p_demux->p_sys;
01599     avi_track_t  *tk = p_sys->track[i_stream];
01600 
01601 #define p_stream    p_sys->track[i_stream]
01602     mtime_t i_oldpts;
01603 
01604     i_oldpts = AVI_GetPTS( p_stream );
01605 
01606     if( !p_stream->i_samplesize )
01607     {
01608         if( AVI_StreamChunkSet( p_demux,
01609                                 i_stream,
01610                                 AVI_PTSToChunk( p_stream, i_date ) ) )
01611         {
01612             return VLC_EGENERIC;
01613         }
01614 
01615         if( p_stream->i_cat == AUDIO_ES )
01616         {
01617             unsigned int i;
01618             tk->i_blockno = 0;
01619             for( i = 0; i < tk->i_idxposc; i++ )
01620             {
01621                 if( tk->i_blocksize > 0 )
01622                 {
01623                     tk->i_blockno += ( tk->p_index[i].i_length + tk->i_blocksize - 1 ) / tk->i_blocksize;
01624                 }
01625                 else
01626                 {
01627                     tk->i_blockno++;
01628                 }
01629             }
01630         }
01631 
01632         msg_Dbg( p_demux,
01633                  "old:"I64Fd" %s new "I64Fd,
01634                  i_oldpts,
01635                  i_oldpts > i_date ? ">" : "<",
01636                  i_date );
01637 
01638         if( p_stream->i_cat == VIDEO_ES )
01639         {
01640             /* search key frame */
01641             if( i_date < i_oldpts )
01642             {
01643                 while( p_stream->i_idxposc > 0 &&
01644                    !( p_stream->p_index[p_stream->i_idxposc].i_flags &
01645                                                                 AVIIF_KEYFRAME ) )
01646                 {
01647                     if( AVI_StreamChunkSet( p_demux,
01648                                             i_stream,
01649                                             p_stream->i_idxposc - 1 ) )
01650                     {
01651                         return VLC_EGENERIC;
01652                     }
01653                 }
01654             }
01655             else
01656             {
01657                 while( p_stream->i_idxposc < p_stream->i_idxnb &&
01658                         !( p_stream->p_index[p_stream->i_idxposc].i_flags &
01659                                                                 AVIIF_KEYFRAME ) )
01660                 {
01661                     if( AVI_StreamChunkSet( p_demux,
01662                                             i_stream,
01663                                             p_stream->i_idxposc + 1 ) )
01664                     {
01665                         return VLC_EGENERIC;
01666                     }
01667                 }
01668             }
01669         }
01670     }
01671     else
01672     {
01673         if( AVI_StreamBytesSet( p_demux,
01674                                 i_stream,
01675                                 AVI_PTSToByte( p_stream, i_date ) ) )
01676         {
01677             return VLC_EGENERIC;
01678         }
01679     }
01680     return VLC_SUCCESS;
01681 #undef p_stream
01682 }
01683 
01684 /****************************************************************************
01685  * Return VLC_TRUE if it's a key frame
01686  ****************************************************************************/
01687 static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, uint8_t *p_byte )
01688 {
01689     switch( i_fourcc )
01690     {
01691         case FOURCC_DIV1:
01692             /* we have:
01693              *  startcode:      0x00000100   32bits
01694              *  framenumber     ?             5bits
01695              *  piture type     0(I),1(P)     2bits
01696              */
01697             if( GetDWBE( p_byte ) != 0x00000100 )
01698             {
01699                 /* it's not an msmpegv1 stream, strange...*/
01700                 return AVIIF_KEYFRAME;
01701             }
01702             return p_byte[4] & 0x06 ? 0 : AVIIF_KEYFRAME;
01703 
01704         case FOURCC_DIV2:
01705         case FOURCC_DIV3:   /* wmv1 also */
01706             /* we have
01707              *  picture type    0(I),1(P)     2bits
01708              */
01709             return p_byte[0] & 0xC0 ? 0 : AVIIF_KEYFRAME;
01710         case FOURCC_mp4v:
01711             /* we should find first occurrence of 0x000001b6 (32bits)
01712              *  startcode:      0x000001b6   32bits
01713              *  piture type     0(I),1(P)     2bits
01714              */
01715             if( GetDWBE( p_byte ) != 0x000001b6 )
01716             {
01717                 /* not true , need to find the first VOP header */
01718                 return AVIIF_KEYFRAME;
01719             }
01720             return p_byte[4] & 0xC0 ? 0 : AVIIF_KEYFRAME;
01721 
01722         default:
01723             /* I can't do it, so say yes */
01724             return AVIIF_KEYFRAME;
01725     }
01726 }
01727 
01728 vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t i_codec )
01729 {
01730     switch( i_cat )
01731     {
01732         case AUDIO_ES:
01733             wf_tag_to_fourcc( i_codec, &i_codec, NULL );
01734             return i_codec;
01735 
01736         case VIDEO_ES:
01737             /* XXX DIV1 <- msmpeg4v1, DIV2 <- msmpeg4v2, DIV3 <- msmpeg4v3, mp4v for mpeg4 */
01738             switch( i_codec )
01739             {
01740                 case FOURCC_1:
01741                     return VLC_FOURCC('m','r','l','e');
01742                 case FOURCC_DIV1:
01743                 case FOURCC_div1:
01744                 case FOURCC_MPG4:
01745                 case FOURCC_mpg4:
01746                     return FOURCC_DIV1;
01747                 case FOURCC_DIV2:
01748                 case FOURCC_div2:
01749                 case FOURCC_MP42:
01750                 case FOURCC_mp42:
01751                 case FOURCC_MPG3:
01752                 case FOURCC_mpg3:
01753                     return FOURCC_DIV2;
01754                 case FOURCC_div3:
01755                 case FOURCC_MP43:
01756                 case FOURCC_mp43:
01757                 case FOURCC_DIV3:
01758                 case FOURCC_DIV4:
01759                 case FOURCC_div4:
01760                 case FOURCC_DIV5:
01761                 case FOURCC_div5:
01762                 case FOURCC_DIV6:
01763                 case FOURCC_div6:
01764                 case FOURCC_AP41:
01765                 case FOURCC_3IV1:
01766                 case FOURCC_3iv1:
01767                 case FOURCC_3IVD:
01768                 case FOURCC_3ivd:
01769                 case FOURCC_3VID:
01770                 case FOURCC_3vid:
01771                     return FOURCC_DIV3;
01772                 case FOURCC_DIVX:
01773                 case FOURCC_divx:
01774                 case FOURCC_MP4S:
01775                 case FOURCC_mp4s:
01776                 case FOURCC_M4S2:
01777                 case FOURCC_m4s2:
01778                 case FOURCC_xvid:
01779                 case FOURCC_XVID:
01780                 case FOURCC_XviD:
01781                 case FOURCC_DX50:
01782                 case FOURCC_dx50:
01783                 case FOURCC_mp4v:
01784                 case FOURCC_4:
01785                 case FOURCC_3IV2:
01786                 case FOURCC_3iv2:
01787                     return FOURCC_mp4v;
01788             }
01789         default:
01790             return VLC_FOURCC( 'u', 'n', 'd', 'f' );
01791     }
01792 }
01793 
01794 /****************************************************************************
01795  *
01796  ****************************************************************************/
01797 static void AVI_ParseStreamHeader( vlc_fourcc_t i_id,
01798                                    int *pi_number, int *pi_type )
01799 {
01800 #define SET_PTR( p, v ) if( p ) *(p) = (v);
01801     int c1, c2;
01802 
01803     c1 = ((uint8_t *)&i_id)[0];
01804     c2 = ((uint8_t *)&i_id)[1];
01805 
01806     if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' )
01807     {
01808         SET_PTR( pi_number, 100 ); /* > max stream number */
01809         SET_PTR( pi_type, UNKNOWN_ES );
01810     }
01811     else
01812     {
01813         SET_PTR( pi_number, (c1 - '0') * 10 + (c2 - '0' ) );
01814         switch( VLC_TWOCC( ((uint8_t *)&i_id)[2], ((uint8_t *)&i_id)[3] ) )
01815         {
01816             case AVITWOCC_wb:
01817                 SET_PTR( pi_type, AUDIO_ES );
01818                 break;
01819             case AVITWOCC_dc:
01820             case AVITWOCC_db:
01821                 SET_PTR( pi_type, VIDEO_ES );
01822                 break;
01823             default:
01824                 SET_PTR( pi_type, UNKNOWN_ES );
01825                 break;
01826         }
01827     }
01828 #undef SET_PTR
01829 }
01830 
01831 /****************************************************************************
01832  *
01833  ****************************************************************************/
01834 static int AVI_PacketGetHeader( demux_t *p_demux, avi_packet_t *p_pk )
01835 {
01836     uint8_t  *p_peek;
01837 
01838     if( stream_Peek( p_demux->s, &p_peek, 16 ) < 16 )
01839     {
01840         return VLC_EGENERIC;
01841     }
01842     p_pk->i_fourcc  = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
01843     p_pk->i_size    = GetDWLE( p_peek + 4 );
01844     p_pk->i_pos     = stream_Tell( p_demux->s );
01845     if( p_pk->i_fourcc == AVIFOURCC_LIST || p_pk->i_fourcc == AVIFOURCC_RIFF )
01846     {
01847         p_pk->i_type = VLC_FOURCC( p_peek[8],  p_peek[9],
01848                                    p_peek[10], p_peek[11] );
01849     }
01850     else
01851     {
01852         p_pk->i_type = 0;
01853     }
01854 
01855     memcpy( p_pk->i_peek, p_peek + 8, 8 );
01856 
01857     AVI_ParseStreamHeader( p_pk->i_fourcc, &p_pk->i_stream, &p_pk->i_cat );
01858     return VLC_SUCCESS;
01859 }
01860 
01861 static int AVI_PacketNext( demux_t *p_demux )
01862 {
01863     avi_packet_t    avi_ck;
01864     int             i_skip = 0;
01865 
01866     if( AVI_PacketGetHeader( p_demux, &avi_ck ) )
01867     {
01868         return VLC_EGENERIC;
01869     }
01870 
01871     if( avi_ck.i_fourcc == AVIFOURCC_LIST &&
01872         ( avi_ck.i_type == AVIFOURCC_rec || avi_ck.i_type == AVIFOURCC_movi ) )
01873     {
01874         i_skip = 12;
01875     }
01876     else if( avi_ck.i_fourcc == AVIFOURCC_RIFF &&
01877              avi_ck.i_type == AVIFOURCC_AVIX )
01878     {
01879         i_skip = 24;
01880     }
01881     else
01882     {
01883         i_skip = __EVEN( avi_ck.i_size ) + 8;
01884     }
01885 
01886     if( stream_Read( p_demux->s, NULL, i_skip ) != i_skip )
01887     {
01888         return VLC_EGENERIC;
01889     }
01890     return VLC_SUCCESS;
01891 }
01892 
01893 static int AVI_PacketRead( demux_t   *p_demux,
01894                            avi_packet_t     *p_pk,
01895                            block_t          **pp_frame )
01896 {
01897     size_t i_size;
01898 
01899     i_size = __EVEN( p_pk->i_size + 8 );
01900 
01901     if( ( *pp_frame = stream_Block( p_demux->s, i_size ) ) == NULL )
01902     {
01903         return VLC_EGENERIC;
01904     }
01905     (*pp_frame)->p_buffer += 8;
01906     (*pp_frame)->i_buffer -= 8;
01907 
01908     if( i_size != p_pk->i_size + 8 )
01909     {
01910         (*pp_frame)->i_buffer--;
01911     }
01912 
01913     return VLC_SUCCESS;
01914 }
01915 
01916 static int AVI_PacketSearch( demux_t *p_demux )
01917 {
01918     demux_sys_t     *p_sys = p_demux->p_sys;
01919     avi_packet_t    avi_pk;
01920     int             i_count = 0;
01921 
01922     for( ;; )
01923     {
01924         if( stream_Read( p_demux->s, NULL, 1 ) != 1 )
01925         {
01926             return VLC_EGENERIC;
01927         }
01928         AVI_PacketGetHeader( p_demux, &avi_pk );
01929         if( avi_pk.i_stream < p_sys->i_track &&
01930             ( avi_pk.i_cat == AUDIO_ES || avi_pk.i_cat == VIDEO_ES ) )
01931         {
01932             return VLC_SUCCESS;
01933         }
01934         switch( avi_pk.i_fourcc )
01935         {
01936             case AVIFOURCC_JUNK:
01937             case AVIFOURCC_LIST:
01938             case AVIFOURCC_RIFF:
01939             case AVIFOURCC_idx1:
01940                 return VLC_SUCCESS;
01941         }
01942 
01943         /* Prevents from eating all the CPU with broken files.
01944          * This value should be low enough so that it doesn't affect the
01945          * reading speed too much (not that we care much anyway because
01946          * this code is called only on broken files). */
01947         if( !(++i_count % 1024) )
01948         {
01949             if( p_demux->b_die ) return VLC_EGENERIC;
01950 
01951             msleep( 10000 );
01952             if( !(i_count % (1024 * 10)) )
01953                 msg_Warn( p_demux, "trying to resync..." );
01954         }
01955     }
01956 }
01957 
01958 /****************************************************************************
01959  * Index stuff.
01960  ****************************************************************************/
01961 static void AVI_IndexAddEntry( demux_sys_t *p_sys,
01962                                int i_stream,
01963                                avi_entry_t *p_index)
01964 {
01965     avi_track_t *tk = p_sys->track[i_stream];
01966 
01967     /* Update i_movi_lastchunk_pos */
01968     if( p_sys->i_movi_lastchunk_pos < p_index->i_pos )
01969     {
01970         p_sys->i_movi_lastchunk_pos = p_index->i_pos;
01971     }
01972 
01973     /* add the entry */
01974     if( tk->i_idxnb >= tk->i_idxmax )
01975     {
01976         tk->i_idxmax += 16384;
01977         tk->p_index = realloc( tk->p_index,
01978                                tk->i_idxmax * sizeof( avi_entry_t ) );
01979         if( tk->p_index == NULL )
01980         {
01981             return;
01982         }
01983     }
01984     /* calculate cumulate length */
01985     if( tk->i_idxnb > 0 )
01986     {
01987         p_index->i_lengthtotal =
01988             tk->p_index[tk->i_idxnb - 1].i_length +
01989                 tk->p_index[tk->i_idxnb - 1].i_lengthtotal;
01990     }
01991     else
01992     {
01993         p_index->i_lengthtotal = 0;
01994     }
01995 
01996     tk->p_index[tk->i_idxnb++] = *p_index;
01997 }
01998 
01999 static int AVI_IndexLoad_idx1( demux_t *p_demux )
02000 {
02001     demux_sys_t *p_sys = p_demux->p_sys;
02002 
02003     avi_chunk_list_t    *p_riff;
02004     avi_chunk_list_t    *p_movi;
02005     avi_chunk_idx1_t    *p_idx1;
02006 
02007     unsigned int i_stream;
02008     unsigned int i_index;
02009     off_t        i_offset;
02010     unsigned int i;
02011 
02012     vlc_bool_t b_keyset[100];
02013 
02014     p_riff = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0);
02015     p_idx1 = AVI_ChunkFind( p_riff, AVIFOURCC_idx1, 0);
02016     p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0);
02017 
02018     if( !p_idx1 )
02019     {
02020         msg_Warn( p_demux, "cannot find idx1 chunk, no index defined" );
02021         return VLC_EGENERIC;
02022     }
02023 
02024     /* *** calculate offset *** */
02025     /* Well, avi is __SHIT__ so test more than one entry
02026      * (needed for some avi files) */
02027     i_offset = 0;
02028     for( i = 0; i < __MIN( p_idx1->i_entry_count, 10 ); i++ )
02029     {
02030         if( p_idx1->entry[i].i_pos < p_movi->i_chunk_pos )
02031         {
02032             i_offset = p_movi->i_chunk_pos + 8;
02033             break;
02034         }
02035     }
02036 
02037     /* Reset b_keyset */
02038     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
02039         b_keyset[i_stream] = VLC_FALSE;
02040 
02041     for( i_index = 0; i_index < p_idx1->i_entry_count; i_index++ )
02042     {
02043         unsigned int i_cat;
02044 
02045         AVI_ParseStreamHeader( p_idx1->entry[i_index].i_fourcc,
02046                                &i_stream,
02047                                &i_cat );
02048         if( i_stream < p_sys->i_track &&
02049             i_cat == p_sys->track[i_stream]->i_cat )
02050         {
02051             avi_entry_t index;
02052             index.i_id      = p_idx1->entry[i_index].i_fourcc;
02053             index.i_flags   =
02054                 p_idx1->entry[i_index].i_flags&(~AVIIF_FIXKEYFRAME);
02055             index.i_pos     = p_idx1->entry[i_index].i_pos + i_offset;
02056             index.i_length  = p_idx1->entry[i_index].i_length;
02057             AVI_IndexAddEntry( p_sys, i_stream, &index );
02058 
02059             if( index.i_flags&AVIIF_KEYFRAME )
02060                 b_keyset[i_stream] = VLC_TRUE;
02061         }
02062     }
02063 
02064     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
02065     {
02066         if( !b_keyset[i_stream] )
02067         {
02068             avi_track_t *tk = p_sys->track[i_stream];
02069 
02070             msg_Dbg( p_demux, "no key frame set for track %d", i_stream );
02071             for( i_index = 0; i_index < tk->i_idxnb; i_index++ )
02072                 tk->p_index[i_index].i_flags |= AVIIF_KEYFRAME;
02073         }
02074     }
02075     return VLC_SUCCESS;
02076 }
02077 
02078 static void __Parse_indx( demux_t    *p_demux,
02079                           int               i_stream,
02080                           avi_chunk_indx_t  *p_indx )
02081 {
02082     demux_sys_t         *p_sys    = p_demux->p_sys;
02083     avi_entry_t     index;
02084     int32_t             i;
02085 
02086     msg_Dbg( p_demux, "loading subindex(0x%x) %d entries", p_indx->i_indextype, p_indx->i_entriesinuse );
02087     if( p_indx->i_indexsubtype == 0 )
02088     {
02089         for( i = 0; i < p_indx->i_entriesinuse; i++ )
02090         {
02091             index.i_id      = p_indx->i_id;
02092             index.i_flags   = p_indx->idx.std[i].i_size & 0x80000000 ? 0 : AVIIF_KEYFRAME;
02093             index.i_pos     = p_indx->i_baseoffset + p_indx->idx.std[i].i_offset - 8;
02094             index.i_length  = p_indx->idx.std[i].i_size&0x7fffffff;
02095 
02096             AVI_IndexAddEntry( p_sys, i_stream, &index );
02097         }
02098     }
02099     else if( p_indx->i_indexsubtype == AVI_INDEX_2FIELD )
02100     {
02101         for( i = 0; i < p_indx->i_entriesinuse; i++ )
02102         {
02103             index.i_id      = p_indx->i_id;
02104             index.i_flags   = p_indx->idx.field[i].i_size & 0x80000000 ? 0 : AVIIF_KEYFRAME;
02105             index.i_pos     = p_indx->i_baseoffset + p_indx->idx.field[i].i_offset - 8;
02106             index.i_length  = p_indx->idx.field[i].i_size;
02107 
02108             AVI_IndexAddEntry( p_sys, i_stream, &index );
02109         }
02110     }
02111     else
02112     {
02113         msg_Warn( p_demux, "unknown subtype index(0x%x)", p_indx->i_indexsubtype );
02114     }
02115 }
02116 
02117 static void AVI_IndexLoad_indx( demux_t *p_demux )
02118 {
02119     demux_sys_t         *p_sys = p_demux->p_sys;
02120     unsigned int        i_stream;
02121     int32_t             i;
02122 
02123     avi_chunk_list_t    *p_riff;
02124     avi_chunk_list_t    *p_hdrl;
02125 
02126     p_riff = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0);
02127     p_hdrl = AVI_ChunkFind( p_riff, AVIFOURCC_hdrl, 0 );
02128 
02129     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
02130     {
02131         avi_chunk_list_t    *p_strl;
02132         avi_chunk_indx_t    *p_indx;
02133 
02134 #define p_stream  p_sys->track[i_stream]
02135         p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i_stream );
02136         p_indx = AVI_ChunkFind( p_strl, AVIFOURCC_indx, 0 );
02137 
02138         if( !p_indx )
02139         {
02140             msg_Warn( p_demux, "cannot find indx (misdetect/broken OpenDML file?)" );
02141             continue;
02142         }
02143 
02144         if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS )
02145         {
02146             __Parse_indx( p_demux, i_stream, p_indx );
02147         }
02148         else if( p_indx->i_indextype == AVI_INDEX_OF_INDEXES )
02149         {
02150             avi_chunk_t    ck_sub;
02151             for( i = 0; i < p_indx->i_entriesinuse; i++ )
02152             {
02153                 if( stream_Seek( p_demux->s, p_indx->idx.super[i].i_offset )||
02154                     AVI_ChunkRead( p_demux->s, &ck_sub, NULL  ) )
02155                 {
02156                     break;
02157                 }
02158                 __Parse_indx( p_demux, i_stream, &ck_sub.indx );
02159             }
02160         }
02161         else
02162         {
02163             msg_Warn( p_demux, "unknown type index(0x%x)", p_indx->i_indextype );
02164         }
02165 #undef p_stream
02166     }
02167 }
02168 
02169 static void AVI_IndexLoad( demux_t *p_demux )
02170 {
02171     demux_sys_t *p_sys = p_demux->p_sys;
02172     unsigned int i_stream;
02173 
02174     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
02175     {
02176         p_sys->track[i_stream]->i_idxnb  = 0;
02177         p_sys->track[i_stream]->i_idxmax = 0;
02178         p_sys->track[i_stream]->p_index  = NULL;
02179     }
02180 
02181     if( p_sys->b_odml )
02182     {
02183         AVI_IndexLoad_indx( p_demux );
02184     }
02185     else  if( AVI_IndexLoad_idx1( p_demux ) )
02186     {
02187         /* try indx if idx1 failed as some "normal" file have indx too */
02188         AVI_IndexLoad_indx( p_demux );
02189     }
02190 
02191     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
02192     {
02193         msg_Dbg( p_demux, "stream[%d] created %d index entries",
02194                 i_stream, p_sys->track[i_stream]->i_idxnb );
02195     }
02196 }
02197 
02198 static void AVI_IndexCreate( demux_t *p_demux )
02199 {
02200     demux_sys_t *p_sys = p_demux->p_sys;
02201 
02202     avi_chunk_list_t    *p_riff;
02203     avi_chunk_list_t    *p_movi;
02204 
02205     unsigned int i_stream;
02206     off_t i_movi_end;
02207 
02208     p_riff = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0);
02209     p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0);
02210 
02211     if( !p_movi )
02212     {
02213         msg_Err( p_demux, "cannot find p_movi" );
02214         return;
02215     }
02216 
02217     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
02218     {
02219         p_sys->track[i_stream]->i_idxnb  = 0;
02220         p_sys->track[i_stream]->i_idxmax = 0;
02221         p_sys->track[i_stream]->p_index  = NULL;
02222     }
02223     i_movi_end = __MIN( (off_t)(p_movi->i_chunk_pos + p_movi->i_chunk_size),
02224                         stream_Size( p_demux->s ) );
02225 
02226     stream_Seek( p_demux->s, p_movi->i_chunk_pos + 12 );
02227     msg_Warn( p_demux, "creating index from LIST-movi, will take time !" );
02228     for( ;; )
02229     {
02230         avi_packet_t pk;
02231 
02232         if( p_demux->b_die )
02233         {
02234             return;
02235         }
02236 
02237         if( AVI_PacketGetHeader( p_demux, &pk ) )
02238         {
02239             break;
02240         }
02241         if( pk.i_stream < p_sys->i_track &&
02242             pk.i_cat == p_sys->track[pk.i_stream]->i_cat )
02243         {
02244             avi_entry_t index;
02245             index.i_id      = pk.i_fourcc;
02246             index.i_flags   =
02247                AVI_GetKeyFlag(p_sys->track[pk.i_stream]->i_codec, pk.i_peek);
02248             index.i_pos     = pk.i_pos;
02249             index.i_length  = pk.i_size;
02250             AVI_IndexAddEntry( p_sys, pk.i_stream, &index );
02251         }
02252         else
02253         {
02254             switch( pk.i_fourcc )
02255             {
02256                 case AVIFOURCC_idx1:
02257                     if( p_sys->b_odml )
02258                     {
02259                         avi_chunk_list_t *p_sysx;
02260                         p_sysx = AVI_ChunkFind( &p_sys->ck_root,
02261                                                 AVIFOURCC_RIFF, 1 );
02262 
02263                         msg_Dbg( p_demux, "looking for new RIFF chunk" );
02264                         if( stream_Seek( p_demux->s, p_sysx->i_chunk_pos + 24))
02265                         {
02266                             goto print_stat;
02267                         }
02268                         break;
02269                     }
02270                     goto print_stat;
02271                 case AVIFOURCC_RIFF:
02272                         msg_Dbg( p_demux, "new RIFF chunk found" );
02273                 case AVIFOURCC_rec:
02274                 case AVIFOURCC_JUNK:
02275                     break;
02276                 default:
02277                     msg_Warn( p_demux, "need resync, probably broken avi" );
02278                     if( AVI_PacketSearch( p_demux ) )
02279                     {
02280                         msg_Warn( p_demux, "lost sync, abord index creation" );
02281                         goto print_stat;
02282                     }
02283             }
02284         }
02285 
02286         if( ( !p_sys->b_odml && pk.i_pos + pk.i_size >= i_movi_end ) ||
02287             AVI_PacketNext( p_demux ) )
02288         {
02289             break;
02290         }
02291     }
02292 
02293 print_stat:
02294     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
02295     {
02296         msg_Dbg( p_demux,
02297                 "stream[%d] creating %d index entries",
02298                 i_stream,
02299                 p_sys->track[i_stream]->i_idxnb );
02300     }
02301 }
02302 
02303 /*****************************************************************************
02304  * Stream management
02305  *****************************************************************************/
02306 static int AVI_TrackStopFinishedStreams( demux_t *p_demux )
02307 {
02308     demux_sys_t *p_sys = p_demux->p_sys;
02309     unsigned int i;
02310     int b_end = VLC_TRUE;
02311 
02312     for( i = 0; i < p_sys->i_track; i++ )
02313     {
02314         avi_track_t *tk = p_sys->track[i];
02315         if( tk->i_idxposc >= tk->i_idxnb )
02316         {
02317             tk->b_activated = VLC_FALSE;
02318             es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, tk->p_es, VLC_FALSE );
02319         }
02320         else
02321         {
02322             b_end = VLC_FALSE;
02323         }
02324     }
02325     return( b_end );
02326 }
02327 
02328 /****************************************************************************
02329  * AVI_MovieGetLength give max streams length in second
02330  ****************************************************************************/
02331 static mtime_t  AVI_MovieGetLength( demux_t *p_demux )
02332 {
02333     demux_sys_t  *p_sys = p_demux->p_sys;
02334     mtime_t      i_maxlength = 0;
02335     unsigned int i;
02336 
02337     for( i = 0; i < p_sys->i_track; i++ )
02338     {
02339         avi_track_t *tk = p_sys->track[i];
02340         mtime_t i_length;
02341 
02342         /* fix length for each stream */
02343         if( tk->i_idxnb < 1 || !tk->p_index )
02344         {
02345             continue;
02346         }
02347 
02348         if( tk->i_samplesize )
02349         {
02350             i_length = AVI_GetDPTS( tk,
02351                                     tk->p_index[tk->i_idxnb-1].i_lengthtotal +
02352                                         tk->p_index[tk->i_idxnb-1].i_length );
02353         }
02354         else
02355         {
02356             i_length = AVI_GetDPTS( tk, tk->i_idxnb );
02357         }
02358         i_length /= (mtime_t)1000000;    /* in seconds */
02359 
02360         msg_Dbg( p_demux,
02361                  "stream[%d] length:"I64Fd" (based on index)",
02362                  i,
02363                  i_length );
02364         i_maxlength = __MAX( i_maxlength, i_length );
02365     }
02366 
02367     return i_maxlength;
02368 }

Generated on Tue Dec 20 10:14:31 2005 for vlc-0.8.4a by  doxygen 1.4.2