avi.c

来自「VLC媒体播放程序」· C语言 代码 · 共 2,041 行 · 第 1/5 页

C
2,041
字号
/***************************************************************************** * avi.c : AVI file Stream input module for vlc ***************************************************************************** * Copyright (C) 2001-2004 VideoLAN * $Id: avi.c,v 1.89 2004/02/27 14:22:18 fenrir Exp $ * 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"#include "avi.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_description( _("AVI demuxer") );    set_capability( "demux", 212 );    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         ( input_thread_t *, int, va_list );static int    Seek            ( input_thread_t *, mtime_t, int );static int    Demux_Seekable  ( input_thread_t * );static int    Demux_UnSeekable( input_thread_t *p_input );#define FREE( p ) if( p ) { free( p ); (p) = NULL; }#define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) )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( input_thread_t *, unsigned int i_stream );static int AVI_StreamChunkSet ( input_thread_t *,                                unsigned int i_stream, unsigned int i_ck );static int AVI_StreamBytesSet ( input_thread_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( input_thread_t *, avi_packet_t *p_pk );static int AVI_PacketNext     ( input_thread_t * );static int AVI_PacketRead     ( input_thread_t *, avi_packet_t *, block_t **);static int AVI_PacketSearch   ( input_thread_t * );static void AVI_IndexLoad    ( input_thread_t * );static void AVI_IndexCreate  ( input_thread_t * );static void AVI_IndexAddEntry( demux_sys_t *, int, AVIIndexEntry_t * );static mtime_t  AVI_MovieGetLength( input_thread_t * );/***************************************************************************** * Stream management *****************************************************************************/static int        AVI_TrackSeek  ( input_thread_t *, int, mtime_t );static int        AVI_TrackStopFinishedStreams( input_thread_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 ){    input_thread_t  *p_input = (input_thread_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;    uint8_t  *p_peek;    /* Is it an avi file ? */    if( stream_Peek( p_input->s, &p_peek, 12 ) < 12 )    {        msg_Err( p_input, "cannot peek()" );        return VLC_EGENERIC;    }    if( strncmp( &p_peek[0], "RIFF", 4 ) || strncmp( &p_peek[8], "AVI ", 4 ) )    {        msg_Warn( p_input, "avi module discarded (invalid header)" );        return VLC_EGENERIC;    }    /* Initialize input  structures. */    p_sys = p_input->p_demux_data = 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_pcr    = 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_input->s, STREAM_CAN_FASTSEEK, &p_sys->b_seekable );    p_input->pf_demux_control = Control;    p_input->pf_demux = Demux_Seekable;    /* For unseekable stream, automaticaly use Demux_UnSeekable */    if( !p_sys->b_seekable || config_GetInt( p_input, "avi-interleaved" ) )    {        p_input->pf_demux = Demux_UnSeekable;    }    if( AVI_ChunkReadRoot( p_input->s, &p_sys->ck_root ) )    {        msg_Err( p_input, "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_input, "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_input, "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_input, "avi module discarded (invalid file)" );        goto error;    }    if( !( p_avih = AVI_ChunkFind( p_hdrl, AVIFOURCC_avih, 0 ) ) )    {        msg_Err( p_input, "cannot find avih chunk" );        goto error;    }    i_track = AVI_ChunkCount( p_hdrl, AVIFOURCC_strl );    if( p_avih->i_streams != i_track )    {        msg_Warn( p_input,                  "found %d stream but %d are declared",                  i_track, p_avih->i_streams );    }    if( i_track == 0 )    {        msg_Err( p_input, "no stream defined!" );        goto error;    }    /*  create one program */    vlc_mutex_lock( &p_input->stream.stream_lock );    if( input_InitStream( p_input, 0 ) == -1)    {        vlc_mutex_unlock( &p_input->stream.stream_lock );        msg_Err( p_input, "cannot init stream" );        goto error;    }    p_input->stream.i_mux_rate = 0; /* Fixed later */    vlc_mutex_unlock( &p_input->stream.stream_lock );    /* print informations on streams */    msg_Dbg( p_input, "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_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_auds = (void*)p_vids = (void*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 );        if( p_strl == NULL || p_strh == NULL || p_auds == NULL || p_vids == NULL )        {            msg_Warn( p_input, "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_input, "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_input, "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;                    }                    es_format_Init( &fmt, VIDEO_ES, tk->i_codec );                }                else                {                    es_format_Init( &fmt, VIDEO_ES, p_vids->p_bih->biCompression );                }                tk->i_samplesize = 0;                fmt.video.i_width  = p_vids->p_bih->biWidth;                fmt.video.i_height = p_vids->p_bih->biHeight;                fmt.video.i_bits_per_pixel = p_vids->p_bih->biBitCount;                fmt.i_extra =                    __MIN( p_vids->p_bih->biSize - sizeof( BITMAPINFOHEADER ),                           p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER) );                fmt.p_extra = &p_vids->p_bih[1];                msg_Dbg( p_input, "stream[%d] video(%4.4s) %dx%d %dbpp %ffps",                        i,                         (char*)&p_vids->p_bih->biCompression,                         p_vids->p_bih->biWidth,                         p_vids->p_bih->biHeight,                         p_vids->p_bih->biBitCount,                         (float)tk->i_rate/(float)tk->i_scale );                break;            default:                msg_Warn( p_input, "stream[%d] unknown type", i );                free( tk );                continue;        }        tk->p_es = es_out_Add( p_input->p_es_out, &fmt );        TAB_APPEND( p_sys->i_track, p_sys->track, tk );    }    if( p_sys->i_track <= 0 )    {        msg_Err( p_input, "no valid track" );        goto error;    }    if( config_GetInt( p_input, "avi-index" ) )    {        if( p_sys->b_seekable )        {            AVI_IndexCreate( p_input );        }        else        {            msg_Warn( p_input, "cannot create index (unseekable stream)" );            AVI_IndexLoad( p_input );        }    }    else    {        AVI_IndexLoad( p_input );    }    /* *** movie length in sec *** */    p_sys->i_length = AVI_MovieGetLength( p_input );    if( p_sys->i_length < (mtime_t)p_avih->i_totalframes *                          (mtime_t)p_avih->i_microsecperframe /                          (mtime_t)1000000 )    {        msg_Warn( p_input, "broken or missing index, 'seek' will be axproximative or will have strange behavour" );    }    /* fix some BeOS MediaKit generated file */    for( i = 0 ; i < p_sys->i_track; i++ )

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?