📄 avi.c
字号:
/***************************************************************************** * avi.c : AVI file Stream input module for vlc ***************************************************************************** * Copyright (C) 2001-2004 VideoLAN * $Id: avi.c 10753 2005-04-20 14:55:46Z gbazin $ * Authors: Laurent Aimar <fenrir@via.ecp.fr> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include <stdlib.h> /* malloc(), free() */#include <vlc/vlc.h>#include <vlc/input.h>#include "vlc_meta.h"#include "codecs.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 so we can seek trough it more reliably." )static int Open ( vlc_object_t * );static void Close( vlc_object_t * );vlc_module_begin(); set_shortname( "AVI" ); set_description( _("AVI demuxer") ); set_capability( "demux2", 212 ); set_category( CAT_INPUT ); set_subcategory( SUBCAT_INPUT_DEMUX ); add_bool( "avi-interleaved", 0, NULL, INTERLEAVE_TEXT, INTERLEAVE_LONGTEXT, VLC_TRUE ); add_bool( "avi-index", 0, NULL, INDEX_TEXT, INDEX_LONGTEXT, VLC_TRUE ); 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 FREE( p ) if( p ) { free( p ); (p) = NULL; }#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{ vlc_bool_t 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_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 */ /* For VBR audio only */ unsigned int i_blockno; unsigned int i_blocksize;} avi_track_t;struct demux_sys_t{ mtime_t i_time; mtime_t i_length; vlc_bool_t b_seekable; avi_chunk_t ck_root; vlc_bool_t 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; 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; 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( &p_peek[0], "RIFF", 4 ) && !strncmp( &p_peek[8], "AVI ", 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 = VLC_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 = VLC_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_Add( p_sys->meta, VLC_META_SETTING, 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 ) ); 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; avi_chunk_strf_vids_t *p_vids; es_format_t fmt; tk->b_activated = VLC_FALSE; tk->p_index = 0; tk->i_idxnb = 0; tk->i_idxmax = 0; tk->i_idxposc = 0; tk->i_idxposb = 0; tk->i_blockno = 0; tk->i_blocksize = 0; 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 ); if( ( tk->i_blocksize = p_auds->p_wf->nBlockAlign ) == 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; } } es_format_Init( &fmt, AUDIO_ES, tk->i_codec ); fmt.audio.i_channels = p_auds->p_wf->nChannels; fmt.audio.i_rate = p_auds->p_wf->nSamplesPerSec; fmt.i_bitrate = p_auds->p_wf->nAvgBytesPerSec*8; fmt.audio.i_blockalign = p_auds->p_wf->nBlockAlign; fmt.audio.i_bitspersample = p_auds->p_wf->wBitsPerSample; fmt.i_extra = __MIN( p_auds->p_wf->cbSize, p_auds->i_chunk_size - sizeof(WAVEFORMATEX) ); fmt.p_extra = &p_auds->p_wf[1]; msg_Dbg( p_demux, "stream[%d] audio(0x%x) %d channels %dHz %dbits", i, p_auds->p_wf->wFormatTag, p_auds->p_wf->nChannels, p_auds->p_wf->nSamplesPerSec, p_auds->p_wf->wBitsPerSample); break; case( AVIFOURCC_vids ): tk->i_cat = VIDEO_ES; tk->i_codec = AVI_FourccGetCodec( VIDEO_ES, p_vids->p_bih->biCompression ); if( p_vids->p_bih->biCompression == 0x00 ) { switch( p_vids->p_bih->biBitCount ) { case 32: tk->i_codec = VLC_FOURCC('R','V','3','2'); break; case 24: tk->i_codec = VLC_FOURCC('R','V','2','4'); break; case 16: /* tk->i_codec = VLC_FOURCC('R','V','1','6');*/ /* break;*/ case 15: tk->i_codec = VLC_FOURCC('R','V','1','5'); break; case 9: tk->i_codec = VLC_FOURCC( 'Y', 'V', 'U', '9' ); /* <- TODO check that */ break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -