⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libavi.c

📁 video linux conference
💻 C
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************** * libavi.c : LibAVI ***************************************************************************** * Copyright (C) 2001 VideoLAN * $Id: libavi.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. *****************************************************************************/#include <stdlib.h>                                      /* malloc(), free() */#include <vlc/vlc.h>#include <vlc/input.h>#include "codecs.h"                                      /* BITMAPINFOHEADER */#include "libavi.h"#define AVI_DEBUG 1#define FREE( p ) \    if( p ) {free( p ); p = NULL; }#define __EVEN( x ) ( (x)&0x01 ? (x)+1 : (x) )static vlc_fourcc_t GetFOURCC( byte_t *p_buff ){    return VLC_FOURCC( p_buff[0], p_buff[1], p_buff[2], p_buff[3] );}#define AVI_ChunkFree( a, b ) _AVI_ChunkFree( (a), (avi_chunk_t*)(b) )void    _AVI_ChunkFree( stream_t *, avi_chunk_t *p_chk );/**************************************************************************** * * Basics functions to manipulates chunks * ****************************************************************************/static int AVI_ChunkReadCommon( stream_t *s, avi_chunk_t *p_chk ){    uint8_t  *p_peek;    int i_peek;    memset( p_chk, 0, sizeof( avi_chunk_t ) );    if( ( i_peek = stream_Peek( s, &p_peek, 8 ) ) < 8 )    {        return VLC_EGENERIC;    }    p_chk->common.i_chunk_fourcc = GetFOURCC( p_peek );    p_chk->common.i_chunk_size   = GetDWLE( p_peek + 4 );    p_chk->common.i_chunk_pos    = stream_Tell( s );    p_chk->common.p_father = NULL;    p_chk->common.p_next = NULL;    p_chk->common.p_first = NULL;    p_chk->common.p_next = NULL;#ifdef AVI_DEBUG    msg_Dbg( (vlc_object_t*)s,             "found Chunk fourcc:%8.8x (%4.4s) size:"I64Fd" pos:"I64Fd,             p_chk->common.i_chunk_fourcc,             (char*)&p_chk->common.i_chunk_fourcc,             p_chk->common.i_chunk_size,             p_chk->common.i_chunk_pos );#endif    return VLC_SUCCESS;}static int AVI_NextChunk( stream_t *s, avi_chunk_t *p_chk ){    avi_chunk_t chk;    if( !p_chk )    {        if( AVI_ChunkReadCommon( s, &chk ) )        {            return VLC_EGENERIC;        }        p_chk = &chk;    }    if( p_chk->common.p_father )    {        if( p_chk->common.p_father->common.i_chunk_pos +                __EVEN( p_chk->common.p_father->common.i_chunk_size ) + 8 <            p_chk->common.i_chunk_pos +                __EVEN( p_chk->common.i_chunk_size ) + 8 )        {            return VLC_EGENERIC;        }    }    return stream_Seek( s, p_chk->common.i_chunk_pos +                                 __EVEN( p_chk->common.i_chunk_size ) + 8 );}/**************************************************************************** * * Functions to read chunks * ****************************************************************************/static int AVI_ChunkRead_list( stream_t *s, avi_chunk_t *p_container ){    avi_chunk_t *p_chk;    uint8_t *p_peek;    vlc_bool_t b_seekable;    if( p_container->common.i_chunk_size > 0 && p_container->common.i_chunk_size < 8 )    {        /* empty box */        msg_Warn( (vlc_object_t*)s, "empty list chunk" );        return VLC_EGENERIC;    }    if( stream_Peek( s, &p_peek, 12 ) < 12 )    {        msg_Warn( (vlc_object_t*)s, "cannot peek while reading list chunk" );        return VLC_EGENERIC;    }    stream_Control( s, STREAM_CAN_FASTSEEK, &b_seekable );    p_container->list.i_type = GetFOURCC( p_peek + 8 );    if( p_container->common.i_chunk_fourcc == AVIFOURCC_LIST &&        p_container->list.i_type == AVIFOURCC_movi )    {        msg_Dbg( (vlc_object_t*)s, "skipping movi chunk" );        if( b_seekable )        {            return AVI_NextChunk( s, p_container );        }        return VLC_SUCCESS; /* point at begining of LIST-movi */    }    if( stream_Read( s, NULL, 12 ) != 12 )    {        msg_Warn( (vlc_object_t*)s, "cannot enter chunk" );        return VLC_EGENERIC;    }#ifdef AVI_DEBUG    msg_Dbg( (vlc_object_t*)s,             "found LIST chunk: \'%4.4s\'",             (char*)&p_container->list.i_type );#endif    msg_Dbg( (vlc_object_t*)s, "<list \'%4.4s\'>", (char*)&p_container->list.i_type );    for( ; ; )    {        p_chk = malloc( sizeof( avi_chunk_t ) );        memset( p_chk, 0, sizeof( avi_chunk_t ) );        if( !p_container->common.p_first )        {            p_container->common.p_first = p_chk;        }        else        {            p_container->common.p_last->common.p_next = p_chk;        }        p_container->common.p_last = p_chk;        if( AVI_ChunkRead( s, p_chk, p_container ) )        {            break;        }        if( p_chk->common.p_father->common.i_chunk_size > 0 &&           ( stream_Tell( s ) >=              (off_t)p_chk->common.p_father->common.i_chunk_pos +               (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) )        {            break;        }        /* If we can't seek then stop when we 've found LIST-movi */        if( p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST &&            p_chk->list.i_type == AVIFOURCC_movi &&            ( !b_seekable || p_chk->common.i_chunk_size == 0 ) )        {            break;        }    }    msg_Dbg( (vlc_object_t*)s, "</list \'%4.4s\'>", (char*)&p_container->list.i_type );    return VLC_SUCCESS;}#define AVI_READCHUNK_ENTER \    int64_t i_read = __EVEN(p_chk->common.i_chunk_size ) + 8; \    uint8_t  *p_read, *p_buff;    \    if( !( p_read = p_buff = malloc(i_read ) ) ) \    { \        return VLC_EGENERIC; \    } \    i_read = stream_Read( s, p_read, i_read ); \    if( i_read < (int64_t)__EVEN(p_chk->common.i_chunk_size ) + 8 ) \    { \        return VLC_EGENERIC; \    }\    p_read += 8; \    i_read -= 8#define AVI_READCHUNK_EXIT( code ) \    free( p_buff ); \    if( i_read < 0 ) \    { \        msg_Warn( (vlc_object_t*)s, "not enough data" ); \    } \    return code#define AVI_READ1BYTE( i_byte ) \    i_byte = *p_read; \    p_read++; \    i_read--#define AVI_READ2BYTES( i_word ) \    i_word = GetWLE( p_read ); \    p_read += 2; \    i_read -= 2#define AVI_READ4BYTES( i_dword ) \    i_dword = GetDWLE( p_read ); \    p_read += 4; \    i_read -= 4#define AVI_READ8BYTES( i_dword ) \    i_dword = GetQWLE( p_read ); \    p_read += 8; \    i_read -= 8#define AVI_READFOURCC( i_dword ) \    i_dword = GetFOURCC( p_read ); \    p_read += 4; \    i_read -= 4static int AVI_ChunkRead_avih( stream_t *s, avi_chunk_t *p_chk ){    AVI_READCHUNK_ENTER;    AVI_READ4BYTES( p_chk->avih.i_microsecperframe);    AVI_READ4BYTES( p_chk->avih.i_maxbytespersec );    AVI_READ4BYTES( p_chk->avih.i_reserved1 );    AVI_READ4BYTES( p_chk->avih.i_flags );    AVI_READ4BYTES( p_chk->avih.i_totalframes );    AVI_READ4BYTES( p_chk->avih.i_initialframes );    AVI_READ4BYTES( p_chk->avih.i_streams );    AVI_READ4BYTES( p_chk->avih.i_suggestedbuffersize );    AVI_READ4BYTES( p_chk->avih.i_width );    AVI_READ4BYTES( p_chk->avih.i_height );    AVI_READ4BYTES( p_chk->avih.i_scale );    AVI_READ4BYTES( p_chk->avih.i_rate );    AVI_READ4BYTES( p_chk->avih.i_start );    AVI_READ4BYTES( p_chk->avih.i_length );#ifdef AVI_DEBUG    msg_Dbg( (vlc_object_t*)s,             "avih: streams:%d flags:%s%s%s%s %dx%d",             p_chk->avih.i_streams,             p_chk->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",             p_chk->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",             p_chk->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",             p_chk->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"",             p_chk->avih.i_width, p_chk->avih.i_height );#endif    AVI_READCHUNK_EXIT( VLC_SUCCESS );}static int AVI_ChunkRead_strh( stream_t *s, avi_chunk_t *p_chk ){    AVI_READCHUNK_ENTER;    AVI_READFOURCC( p_chk->strh.i_type );    AVI_READFOURCC( p_chk->strh.i_handler );    AVI_READ4BYTES( p_chk->strh.i_flags );    AVI_READ4BYTES( p_chk->strh.i_reserved1 );    AVI_READ4BYTES( p_chk->strh.i_initialframes );    AVI_READ4BYTES( p_chk->strh.i_scale );    AVI_READ4BYTES( p_chk->strh.i_rate );    AVI_READ4BYTES( p_chk->strh.i_start );    AVI_READ4BYTES( p_chk->strh.i_length );    AVI_READ4BYTES( p_chk->strh.i_suggestedbuffersize );    AVI_READ4BYTES( p_chk->strh.i_quality );    AVI_READ4BYTES( p_chk->strh.i_samplesize );#ifdef AVI_DEBUG    msg_Dbg( (vlc_object_t*)s,             "strh: type:%4.4s handler:0x%8.8x samplesize:%d %.2ffps",             (char*)&p_chk->strh.i_type,             p_chk->strh.i_handler,             p_chk->strh.i_samplesize,             ( p_chk->strh.i_scale ?                (float)p_chk->strh.i_rate / (float)p_chk->strh.i_scale : -1) );#endif    AVI_READCHUNK_EXIT( VLC_SUCCESS );}static int AVI_ChunkRead_strf( stream_t *s, avi_chunk_t *p_chk ){    avi_chunk_t *p_strh;    AVI_READCHUNK_ENTER;    if( p_chk->common.p_father == NULL )    {        msg_Err( (vlc_object_t*)s, "malformed avi file" );        AVI_READCHUNK_EXIT( VLC_EGENERIC );    }    if( !( p_strh = AVI_ChunkFind( p_chk->common.p_father, AVIFOURCC_strh, 0 ) ) )    {        msg_Err( (vlc_object_t*)s, "malformed avi file" );        AVI_READCHUNK_EXIT( VLC_EGENERIC );    }    switch( p_strh->strh.i_type )    {        case( AVIFOURCC_auds ):            p_chk->strf.auds.i_cat = AUDIO_ES;            p_chk->strf.auds.p_wf = malloc( __MAX( p_chk->common.i_chunk_size, sizeof( WAVEFORMATEX ) ) );            AVI_READ2BYTES( p_chk->strf.auds.p_wf->wFormatTag );            AVI_READ2BYTES( p_chk->strf.auds.p_wf->nChannels );            AVI_READ4BYTES( p_chk->strf.auds.p_wf->nSamplesPerSec );            AVI_READ4BYTES( p_chk->strf.auds.p_wf->nAvgBytesPerSec );            AVI_READ2BYTES( p_chk->strf.auds.p_wf->nBlockAlign );            AVI_READ2BYTES( p_chk->strf.auds.p_wf->wBitsPerSample );            if( p_chk->strf.auds.p_wf->wFormatTag != WAVE_FORMAT_PCM                 && p_chk->common.i_chunk_size > sizeof( WAVEFORMATEX ) )            {                AVI_READ2BYTES( p_chk->strf.auds.p_wf->cbSize );                /* prevent segfault */                if( p_chk->strf.auds.p_wf->cbSize >                        p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX ) )                {                    p_chk->strf.auds.p_wf->cbSize =                        p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX );                }                if( p_chk->strf.auds.p_wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE )                {                    /* Found an extensible header atm almost nothing uses that. */                    msg_Warn( (vlc_object_t*)s, "WAVE_FORMAT_EXTENSIBLE or "                              "vorbis audio dectected: not supported" );                }            }            else            {                p_chk->strf.auds.p_wf->cbSize = 0;            }            if( p_chk->strf.auds.p_wf->cbSize > 0 )            {                memcpy( &p_chk->strf.auds.p_wf[1] ,                        p_buff + 8 + sizeof( WAVEFORMATEX ),    /*  8=fourrc+size */                        p_chk->strf.auds.p_wf->cbSize );            }#ifdef AVI_DEBUG            msg_Dbg( (vlc_object_t*)s,                     "strf: audio:0x%4.4x channels:%d %dHz %dbits/sample %dkb/s",                     p_chk->strf.auds.p_wf->wFormatTag,                     p_chk->strf.auds.p_wf->nChannels,                     p_chk->strf.auds.p_wf->nSamplesPerSec,                     p_chk->strf.auds.p_wf->wBitsPerSample,                     p_chk->strf.auds.p_wf->nAvgBytesPerSec * 8 / 1024 );#endif            break;        case( AVIFOURCC_vids ):            p_strh->strh.i_samplesize = 0; /* XXX for ffmpeg avi file */            p_chk->strf.vids.i_cat = VIDEO_ES;            p_chk->strf.vids.p_bih = malloc( p_chk->common.i_chunk_size );            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSize );            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biWidth );            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biHeight );            AVI_READ2BYTES( p_chk->strf.vids.p_bih->biPlanes );            AVI_READ2BYTES( p_chk->strf.vids.p_bih->biBitCount );            AVI_READFOURCC( p_chk->strf.vids.p_bih->biCompression );            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSizeImage );            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biXPelsPerMeter );            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biYPelsPerMeter );            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrUsed );            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrImportant );            if( p_chk->strf.vids.p_bih->biSize > p_chk->common.i_chunk_size )            {                p_chk->strf.vids.p_bih->biSize = p_chk->common.i_chunk_size;            }            if( p_chk->strf.vids.p_bih->biSize - sizeof(BITMAPINFOHEADER) > 0 )            {                memcpy( &p_chk->strf.vids.p_bih[1],                        p_buff + 8 + sizeof(BITMAPINFOHEADER), /* 8=fourrc+size */                        p_chk->common.i_chunk_size -sizeof(BITMAPINFOHEADER) );            }#ifdef AVI_DEBUG            msg_Dbg( (vlc_object_t*)s,                     "strf: video:%4.4s %dx%d planes:%d %dbpp",                     (char*)&p_chk->strf.vids.p_bih->biCompression,                     p_chk->strf.vids.p_bih->biWidth,                     p_chk->strf.vids.p_bih->biHeight,                     p_chk->strf.vids.p_bih->biPlanes,                     p_chk->strf.vids.p_bih->biBitCount );#endif            break;        default:            msg_Warn( (vlc_object_t*)s, "unknown stream type" );            p_chk->strf.common.i_cat = UNKNOWN_ES;            break;    }    AVI_READCHUNK_EXIT( VLC_SUCCESS );}static void AVI_ChunkFree_strf( avi_chunk_t *p_chk ){    avi_chunk_strf_t *p_strf = (avi_chunk_strf_t*)p_chk;    if( p_strf->common.i_cat == AUDIO_ES )    {        FREE( p_strf->auds.p_wf );    }    else if( p_strf->common.i_cat == VIDEO_ES )    {        FREE( p_strf->vids.p_bih );    }}static int AVI_ChunkRead_strd( stream_t *s, avi_chunk_t *p_chk ){    AVI_READCHUNK_ENTER;    p_chk->strd.p_data = malloc( p_chk->common.i_chunk_size );    memcpy( p_chk->strd.p_data,            p_buff + 8,            p_chk->common.i_chunk_size );    AVI_READCHUNK_EXIT( VLC_SUCCESS );}static int AVI_ChunkRead_idx1( stream_t *s, avi_chunk_t *p_chk ){    unsigned int i_count, i_index;    AVI_READCHUNK_ENTER;    i_count = __MIN( (int64_t)p_chk->common.i_chunk_size, i_read ) / 16;    p_chk->idx1.i_entry_count = i_count;    p_chk->idx1.i_entry_max   = i_count;    if( i_count > 0 )    {        p_chk->idx1.entry = calloc( i_count, sizeof( idx1_entry_t ) );        for( i_index = 0; i_index < i_count ; i_index++ )        {            AVI_READFOURCC( p_chk->idx1.entry[i_index].i_fourcc );            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_flags );            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_pos );            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_length );        }    }    else    {        p_chk->idx1.entry = NULL;    }#ifdef AVI_DEBUG    msg_Dbg( (vlc_object_t*)s, "idx1: index entry:%d", i_count );#endif    AVI_READCHUNK_EXIT( VLC_SUCCESS );}

⌨️ 快捷键说明

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