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

📄 flac.c

📁 video linux conference
💻 C
📖 第 1 页 / 共 3 页
字号:
/***************************************************************************** * flac.c: flac decoder/packetizer/encoder module making use of libflac ***************************************************************************** * Copyright (C) 1999-2001 VideoLAN * $Id: flac.c 10169 2005-03-06 18:46:43Z gbazin $ * * Authors: Gildas Bazin <gbazin@videolan.org> *          Sigmund Augdal <sigmunau@idi.ntnu.no> * * 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 <vlc/vlc.h>#include <vlc/decoder.h>#ifdef HAVE_FLAC_STREAM_DECODER_H#   include <FLAC/stream_decoder.h>#   include <FLAC/stream_encoder.h>#   define USE_LIBFLAC#endif#include "vlc_block_helper.h"#include "vlc_bits.h"#define MAX_FLAC_HEADER_SIZE 16/***************************************************************************** * decoder_sys_t : FLAC decoder descriptor *****************************************************************************/struct decoder_sys_t{    /*     * Input properties     */    int i_state;    block_bytestream_t bytestream;    /*     * Input/Output properties     */    block_t *p_block;    aout_buffer_t *p_aout_buffer;    /*     * FLAC properties     */#ifdef USE_LIBFLAC    FLAC__StreamDecoder *p_flac;    FLAC__StreamMetadata_StreamInfo stream_info;#else    struct    {        unsigned min_blocksize, max_blocksize;        unsigned min_framesize, max_framesize;        unsigned sample_rate;        unsigned channels;        unsigned bits_per_sample;    } stream_info;#endif    vlc_bool_t b_stream_info;    /*     * Common properties     */    audio_date_t end_date;    mtime_t i_pts;    int i_frame_size, i_frame_length, i_bits_per_sample;    unsigned int i_rate, i_channels, i_channels_conf;};enum {    STATE_NOSYNC,    STATE_SYNC,    STATE_HEADER,    STATE_NEXT_SYNC,    STATE_GET_DATA,    STATE_SEND_DATA};static int pi_channels_maps[6] ={    0,    AOUT_CHAN_CENTER,    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,    AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT     | AOUT_CHAN_REARRIGHT,    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER     | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT};/***************************************************************************** * Local prototypes *****************************************************************************/static int  OpenDecoder   ( vlc_object_t * );static int  OpenPacketizer( vlc_object_t * );static void CloseDecoder  ( vlc_object_t * );#ifdef USE_LIBFLACstatic int OpenEncoder   ( vlc_object_t * );static void CloseEncoder ( vlc_object_t * );#endif#ifdef USE_LIBFLACstatic aout_buffer_t *DecodeBlock( decoder_t *, block_t ** );#endifstatic block_t *PacketizeBlock( decoder_t *, block_t ** );static int SyncInfo( decoder_t *, uint8_t *, int *, int *, int *,int * );#ifdef USE_LIBFLACstatic FLAC__StreamDecoderReadStatusDecoderReadCallback( const FLAC__StreamDecoder *decoder,                     FLAC__byte buffer[], unsigned *bytes, void *client_data );static FLAC__StreamDecoderWriteStatusDecoderWriteCallback( const FLAC__StreamDecoder *decoder,                      const FLAC__Frame *frame,                      const FLAC__int32 *const buffer[], void *client_data );static void DecoderMetadataCallback( const FLAC__StreamDecoder *decoder,                                     const FLAC__StreamMetadata *metadata,                                     void *client_data );static void DecoderErrorCallback( const FLAC__StreamDecoder *decoder,                                  FLAC__StreamDecoderErrorStatus status,                                  void *client_data);static void Interleave32( int32_t *p_out, const int32_t * const *pp_in,                          int i_nb_channels, int i_samples );static void Interleave16( int16_t *p_out, const int32_t * const *pp_in,                          int i_nb_channels, int i_samples );static void decoder_state_error( decoder_t *p_dec,                                 FLAC__StreamDecoderState state );#endifstatic uint64_t read_utf8( const uint8_t *p_buf, int *pi_read );static uint8_t flac_crc8( const uint8_t *data, unsigned len );/***************************************************************************** * Module descriptor *****************************************************************************/vlc_module_begin();    set_category( CAT_INPUT );    set_subcategory( SUBCAT_INPUT_ACODEC );#ifdef USE_LIBFLAC    set_description( _("Flac audio decoder") );    set_capability( "decoder", 100 );    set_callbacks( OpenDecoder, CloseDecoder );    add_submodule();    set_description( _("Flac audio encoder") );    set_capability( "encoder", 100 );    set_callbacks( OpenEncoder, CloseEncoder );    add_submodule();#endif    set_description( _("Flac audio packetizer") );    set_capability( "packetizer", 100 );    set_callbacks( OpenPacketizer, CloseDecoder );    add_shortcut( "flac" );vlc_module_end();/***************************************************************************** * OpenDecoder: probe the decoder and return score *****************************************************************************/static int OpenDecoder( vlc_object_t *p_this ){    decoder_t *p_dec = (decoder_t*)p_this;    decoder_sys_t *p_sys;    if( p_dec->fmt_in.i_codec != VLC_FOURCC('f','l','a','c') )    {        return VLC_EGENERIC;    }    /* Allocate the memory needed to store the decoder's structure */    if( ( p_dec->p_sys = p_sys =          (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )    {        msg_Err( p_dec, "out of memory" );        return VLC_EGENERIC;    }    /* Misc init */    aout_DateSet( &p_sys->end_date, 0 );    p_sys->i_state = STATE_NOSYNC;    p_sys->b_stream_info = VLC_FALSE;    p_sys->bytestream = block_BytestreamInit( p_dec );#ifdef USE_LIBFLAC    /* Take care of flac init */    if( !(p_sys->p_flac = FLAC__stream_decoder_new()) )    {        msg_Err( p_dec, "FLAC__stream_decoder_new() failed" );        free( p_sys );        return VLC_EGENERIC;    }    FLAC__stream_decoder_set_read_callback( p_sys->p_flac,                                            DecoderReadCallback );    FLAC__stream_decoder_set_write_callback( p_sys->p_flac,                                             DecoderWriteCallback );    FLAC__stream_decoder_set_metadata_callback( p_sys->p_flac,                                                DecoderMetadataCallback );    FLAC__stream_decoder_set_error_callback( p_sys->p_flac,                                             DecoderErrorCallback );    FLAC__stream_decoder_set_client_data( p_sys->p_flac, p_dec );    FLAC__stream_decoder_init( p_sys->p_flac );#endif    /* Set output properties */    p_dec->fmt_out.i_cat = AUDIO_ES;    p_dec->fmt_out.i_codec = VLC_FOURCC('f','l','3','2');    /* Set callbacks */#ifdef USE_LIBFLAC    p_dec->pf_decode_audio = DecodeBlock;#endif    p_dec->pf_packetize    = PacketizeBlock;    return VLC_SUCCESS;}static int OpenPacketizer( vlc_object_t *p_this ){    decoder_t *p_dec = (decoder_t*)p_this;    int i_ret;    /* Hmmm, mem leak ?*/    es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );    i_ret = OpenDecoder( p_this );    /* Set output properties */    p_dec->fmt_out.i_codec = VLC_FOURCC('f','l','a','c');    if( i_ret != VLC_SUCCESS ) return i_ret;    return i_ret;}/***************************************************************************** * CloseDecoder: flac decoder destruction *****************************************************************************/static void CloseDecoder( vlc_object_t *p_this ){    decoder_t *p_dec = (decoder_t *)p_this;    decoder_sys_t *p_sys = p_dec->p_sys;#ifdef USE_LIBFLAC    FLAC__stream_decoder_finish( p_sys->p_flac );    FLAC__stream_decoder_delete( p_sys->p_flac );#endif    if( p_sys->p_block ) free( p_sys->p_block );    free( p_sys );}/***************************************************************************** * ProcessHeader: processe Flac header. *****************************************************************************/static void ProcessHeader( decoder_t *p_dec ){    decoder_sys_t *p_sys = p_dec->p_sys;#ifdef USE_LIBFLAC    if( !p_dec->fmt_in.i_extra ) return;    /* Decode STREAMINFO */    msg_Dbg( p_dec, "decode STREAMINFO" );    p_sys->p_block = block_New( p_dec, p_dec->fmt_in.i_extra );    memcpy( p_sys->p_block->p_buffer, p_dec->fmt_in.p_extra,            p_dec->fmt_in.i_extra );    FLAC__stream_decoder_process_until_end_of_metadata( p_sys->p_flac );    msg_Dbg( p_dec, "STREAMINFO decoded" );#else    bs_t bs;    if( !p_dec->fmt_in.i_extra ) return;    bs_init( &bs, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra );    p_sys->stream_info.min_blocksize = bs_read( &bs, 16 );    p_sys->stream_info.max_blocksize = bs_read( &bs, 16 );    p_sys->stream_info.min_framesize = bs_read( &bs, 24 );    p_sys->stream_info.max_framesize = bs_read( &bs, 24 );    p_sys->stream_info.sample_rate = bs_read( &bs, 20 );    p_sys->stream_info.channels = bs_read( &bs, 3 ) + 1;    p_sys->stream_info.bits_per_sample = bs_read( &bs, 5 ) + 1;#endif    if( !p_sys->b_stream_info ) return;    if( p_dec->fmt_out.i_codec == VLC_FOURCC('f','l','a','c') )    {        p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;        p_dec->fmt_out.p_extra =            realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );        memcpy( p_dec->fmt_out.p_extra,                p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );    }}/**************************************************************************** * PacketizeBlock: the whole thing **************************************************************************** * This function is called just after the thread is launched. ****************************************************************************/static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ){    decoder_sys_t *p_sys = p_dec->p_sys;    uint8_t p_header[MAX_FLAC_HEADER_SIZE];    block_t *p_sout_block;    if( !pp_block || !*pp_block ) return NULL;    if( !p_sys->b_stream_info ) ProcessHeader( p_dec );    if( !aout_DateGet( &p_sys->end_date ) && !(*pp_block)->i_pts )    {        /* We've just started the stream, wait for the first PTS. */        block_Release( *pp_block );        return NULL;    }    else if( !aout_DateGet( &p_sys->end_date ) )    {        /* The first PTS is as good as anything else. */        aout_DateSet( &p_sys->end_date, (*pp_block)->i_pts );    }    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )    {        p_sys->i_state = STATE_NOSYNC;    }    block_BytestreamPush( &p_sys->bytestream, *pp_block );    while( 1 )    {        switch( p_sys->i_state )        {        case STATE_NOSYNC:            while( block_PeekBytes( &p_sys->bytestream, p_header, 2 )                   == VLC_SUCCESS )            {                if( p_header[0] == 0xFF && p_header[1] == 0xF8 )                {                    p_sys->i_state = STATE_SYNC;                    break;                }                block_SkipByte( &p_sys->bytestream );            }            if( p_sys->i_state != STATE_SYNC )            {                block_BytestreamFlush( &p_sys->bytestream );                /* Need more data */                return NULL;            }        case STATE_SYNC:            /* New frame, set the Presentation Time Stamp */            p_sys->i_pts = p_sys->bytestream.p_block->i_pts;            if( p_sys->i_pts != 0 &&                p_sys->i_pts != aout_DateGet( &p_sys->end_date ) )            {                aout_DateSet( &p_sys->end_date, p_sys->i_pts );            }            p_sys->i_state = STATE_HEADER;        case STATE_HEADER:            /* Get FLAC frame header (MAX_FLAC_HEADER_SIZE bytes) */            if( block_PeekBytes( &p_sys->bytestream, p_header,                                 MAX_FLAC_HEADER_SIZE ) != VLC_SUCCESS )            {                /* Need more data */                return NULL;            }            /* Check if frame is valid and get frame info */            p_sys->i_frame_length = SyncInfo( p_dec, p_header,                                              &p_sys->i_channels,                                              &p_sys->i_channels_conf,                                              &p_sys->i_rate,                                              &p_sys->i_bits_per_sample );            if( !p_sys->i_frame_length )            {                msg_Dbg( p_dec, "emulated sync word" );                block_SkipByte( &p_sys->bytestream );                p_sys->i_state = STATE_NOSYNC;                break;            }            if( p_sys->i_rate != p_dec->fmt_out.audio.i_rate )            {                p_dec->fmt_out.audio.i_rate = p_sys->i_rate;                aout_DateInit( &p_sys->end_date, p_sys->i_rate );            }            p_sys->i_state = STATE_NEXT_SYNC;            p_sys->i_frame_size = 1;        case STATE_NEXT_SYNC:            /* TODO: If pp_block == NULL, flush the buffer without checking the             * next sync word */            /* Check if next expected frame contains the sync word */            while( block_PeekOffsetBytes( &p_sys->bytestream,                                          p_sys->i_frame_size, p_header,                                          MAX_FLAC_HEADER_SIZE )                   == VLC_SUCCESS )

⌨️ 快捷键说明

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