📄 avi.c
字号:
/***************************************************************************** * avi.c : AVI file Stream input module for vlc ***************************************************************************** * Copyright (C) 2001-2004 the VideoLAN team * $Id: 2d8975cd286cc6850615b639ad862f2cf4a66970 $ * Authors: Laurent Aimar <fenrir@via.ecp.fr> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_plugin.h>#include <vlc_demux.h>#include <vlc_interface.h>#include <vlc_meta.h>#include <vlc_codecs.h>#include <vlc_charset.h>#include "libavi.h"/***************************************************************************** * Module descriptor *****************************************************************************/#define INTERLEAVE_TEXT N_("Force interleaved method" )#define INTERLEAVE_LONGTEXT N_( "Force interleaved method." )#define INDEX_TEXT N_("Force index creation")#define INDEX_LONGTEXT N_( \ "Recreate a index for the AVI file. Use this if your AVI file is damaged "\ "or incomplete (not seekable)." )static int Open ( vlc_object_t * );static void Close( vlc_object_t * );static const int pi_index[] = {0,1,2};static const char *const ppsz_indexes[] = { N_("Ask"), N_("Always fix"), N_("Never fix") };vlc_module_begin(); set_shortname( "AVI" ); set_description( N_("AVI demuxer") ); set_capability( "demux", 212 ); set_category( CAT_INPUT ); set_subcategory( SUBCAT_INPUT_DEMUX ); add_bool( "avi-interleaved", 0, NULL, INTERLEAVE_TEXT, INTERLEAVE_LONGTEXT, true ); add_integer( "avi-index", 0, NULL, INDEX_TEXT, INDEX_LONGTEXT, false ); change_integer_list( pi_index, ppsz_indexes, NULL ); set_callbacks( Open, Close );vlc_module_end();/***************************************************************************** * Local prototypes *****************************************************************************/static int Control ( demux_t *, int, va_list );static int Seek ( demux_t *, mtime_t, int );static int Demux_Seekable ( demux_t * );static int Demux_UnSeekable( demux_t * );#define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) )typedef struct{ vlc_fourcc_t i_fourcc; off_t i_pos; uint32_t i_size; vlc_fourcc_t i_type; /* only for AVIFOURCC_LIST */ uint8_t i_peek[8]; /* first 8 bytes */ unsigned int i_stream; unsigned int i_cat;} avi_packet_t;typedef struct{ vlc_fourcc_t i_id; uint32_t i_flags; off_t i_pos; uint32_t i_length; uint32_t i_lengthtotal;} avi_entry_t;typedef struct{ bool b_activated; unsigned int i_cat; /* AUDIO_ES, VIDEO_ES */ vlc_fourcc_t i_codec; int i_rate; int i_scale; int i_samplesize; es_out_id_t *p_es; /* Avi Index */ avi_entry_t *p_index; unsigned int i_idxnb; unsigned int i_idxmax; unsigned int i_idxposc; /* numero of chunk */ unsigned int i_idxposb; /* byte in the current chunk */ /* extra information given to the decoder */ void *p_extra; /* For VBR audio only */ unsigned int i_blockno; unsigned int i_blocksize; /* For muxed streams */ stream_t *p_out_muxed;} avi_track_t;struct demux_sys_t{ mtime_t i_time; mtime_t i_length; bool b_seekable; bool b_muxed; avi_chunk_t ck_root; bool b_odml; off_t i_movi_begin; off_t i_movi_lastchunk_pos; /* XXX position of last valid chunk */ /* number of streams and information */ unsigned int i_track; avi_track_t **track; /* meta */ vlc_meta_t *meta;};static inline off_t __EVEN( off_t i ){ return (i & 1) ? i + 1 : i;}static mtime_t AVI_PTSToChunk( avi_track_t *, mtime_t i_pts );static mtime_t AVI_PTSToByte ( avi_track_t *, mtime_t i_pts );static mtime_t AVI_GetDPTS ( avi_track_t *, int64_t i_count );static mtime_t AVI_GetPTS ( avi_track_t * );static int AVI_StreamChunkFind( demux_t *, unsigned int i_stream );static int AVI_StreamChunkSet ( demux_t *, unsigned int i_stream, unsigned int i_ck );static int AVI_StreamBytesSet ( demux_t *, unsigned int i_stream, off_t i_byte );vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t );static int AVI_GetKeyFlag ( vlc_fourcc_t , uint8_t * );static int AVI_PacketGetHeader( demux_t *, avi_packet_t *p_pk );static int AVI_PacketNext ( demux_t * );static int AVI_PacketRead ( demux_t *, avi_packet_t *, block_t **);static int AVI_PacketSearch ( demux_t * );static void AVI_IndexLoad ( demux_t * );static void AVI_IndexCreate ( demux_t * );static void AVI_IndexAddEntry( demux_sys_t *, int, avi_entry_t * );static mtime_t AVI_MovieGetLength( demux_t * );/***************************************************************************** * Stream management *****************************************************************************/static int AVI_TrackSeek ( demux_t *, int, mtime_t );static int AVI_TrackStopFinishedStreams( demux_t *);/* Remarks: - For VBR mp3 stream: count blocks by rounded-up chunksizes instead of chunks we need full emulation of dshow avi demuxer bugs :( fixes silly nandub-style a-v delaying in avi with vbr mp3... (from mplayer 2002/08/02) - to complete.... *//***************************************************************************** * Open: check file and initializes AVI structures *****************************************************************************/static int Open( vlc_object_t * p_this ){ demux_t *p_demux = (demux_t *)p_this; demux_sys_t *p_sys; bool b_index = false; int i_do_index; avi_chunk_t ck_riff; avi_chunk_list_t *p_riff = (avi_chunk_list_t*)&ck_riff; avi_chunk_list_t *p_hdrl, *p_movi; avi_chunk_avih_t *p_avih; unsigned int i_track; unsigned int i, i_peeker; const uint8_t *p_peek; /* Is it an avi file ? */ if( stream_Peek( p_demux->s, &p_peek, 200 ) < 200 ) return VLC_EGENERIC; for( i_peeker = 0; i_peeker < 188; i_peeker++ ) { if( !strncmp( (char *)&p_peek[0], "RIFF", 4 ) && !strncmp( (char *)&p_peek[8], "AVI ", 4 ) ) break; if( !strncmp( (char *)&p_peek[0], "ON2 ", 4 ) && !strncmp( (char *)&p_peek[8], "ON2f", 4 ) ) break; p_peek++; } if( i_peeker == 188 ) { return VLC_EGENERIC; } /* Initialize input structures. */ p_sys = p_demux->p_sys = malloc( sizeof(demux_sys_t) ); memset( p_sys, 0, sizeof( demux_sys_t ) ); p_sys->i_time = 0; p_sys->i_length = 0; p_sys->i_movi_lastchunk_pos = 0; p_sys->b_odml = false; p_sys->b_muxed = false; p_sys->i_track = 0; p_sys->track = NULL; p_sys->meta = NULL; stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &p_sys->b_seekable ); p_demux->pf_control = Control; p_demux->pf_demux = Demux_Seekable; /* For unseekable stream, automaticaly use Demux_UnSeekable */ if( !p_sys->b_seekable || config_GetInt( p_demux, "avi-interleaved" ) ) { p_demux->pf_demux = Demux_UnSeekable; } if( i_peeker > 0 ) { stream_Read( p_demux->s, NULL, i_peeker ); } if( AVI_ChunkReadRoot( p_demux->s, &p_sys->ck_root ) ) { msg_Err( p_demux, "avi module discarded (invalid file)" ); return VLC_EGENERIC; } if( AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF ) > 1 ) { unsigned int i_count = AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF ); msg_Warn( p_demux, "multiple riff -> OpenDML ?" ); for( i = 1; i < i_count; i++ ) { avi_chunk_list_t *p_sysx; p_sysx = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, i ); if( p_sysx->i_type == AVIFOURCC_AVIX ) { msg_Warn( p_demux, "detected OpenDML file" ); p_sys->b_odml = true; break; } } } p_riff = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0 ); p_hdrl = AVI_ChunkFind( p_riff, AVIFOURCC_hdrl, 0 ); p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0 ); if( !p_hdrl || !p_movi ) { msg_Err( p_demux, "avi module discarded (invalid file)" ); goto error; } if( !( p_avih = AVI_ChunkFind( p_hdrl, AVIFOURCC_avih, 0 ) ) ) { msg_Err( p_demux, "cannot find avih chunk" ); goto error; } i_track = AVI_ChunkCount( p_hdrl, AVIFOURCC_strl ); if( p_avih->i_streams != i_track ) { msg_Warn( p_demux, "found %d stream but %d are declared", i_track, p_avih->i_streams ); } if( i_track == 0 ) { msg_Err( p_demux, "no stream defined!" ); goto error; } /* print information on streams */ msg_Dbg( p_demux, "AVIH: %d stream, flags %s%s%s%s ", i_track, p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"", p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"", p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"", p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" ); if( ( p_sys->meta = vlc_meta_New() ) ) { char buffer[200]; sprintf( buffer, "%s%s%s%s", p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"", p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"", p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"", p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" ); vlc_meta_SetSetting( p_sys->meta, buffer ); } /* now read info on each stream and create ES */ for( i = 0 ; i < i_track; i++ ) { avi_track_t *tk = malloc( sizeof( avi_track_t ) ); if( !tk ) goto error; avi_chunk_list_t *p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i ); avi_chunk_strh_t *p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 ); avi_chunk_STRING_t *p_strn = AVI_ChunkFind( p_strl, AVIFOURCC_strn, 0 ); avi_chunk_strf_auds_t *p_auds = NULL; avi_chunk_strf_vids_t *p_vids = NULL; es_format_t fmt; memset( tk, 0, sizeof( avi_track_t ) ); p_vids = (avi_chunk_strf_vids_t*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 ); p_auds = (avi_chunk_strf_auds_t*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 ); if( p_strl == NULL || p_strh == NULL || p_auds == NULL || p_vids == NULL ) { msg_Warn( p_demux, "stream[%d] incomplete", i ); continue; } tk->i_rate = p_strh->i_rate; tk->i_scale = p_strh->i_scale; tk->i_samplesize = p_strh->i_samplesize; msg_Dbg( p_demux, "stream[%d] rate:%d scale:%d samplesize:%d", i, tk->i_rate, tk->i_scale, tk->i_samplesize ); switch( p_strh->i_type ) { case( AVIFOURCC_auds ): tk->i_cat = AUDIO_ES; tk->i_codec = AVI_FourccGetCodec( AUDIO_ES, p_auds->p_wf->wFormatTag ); tk->i_blocksize = p_auds->p_wf->nBlockAlign; if( tk->i_blocksize == 0 ) { if( p_auds->p_wf->wFormatTag == 1 ) tk->i_blocksize = p_auds->p_wf->nChannels * (p_auds->p_wf->wBitsPerSample/8); else tk->i_blocksize = 1; } else if( tk->i_samplesize != 0 && tk->i_samplesize != tk->i_blocksize ) { msg_Warn( p_demux, "track[%d] samplesize=%d and blocksize=%d are not equal." "Using blocksize as a workaround.",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -