📄 mpeg4audio.c
字号:
/***************************************************************************** * mpeg4audio.c: parse and packetize an MPEG 4 audio stream ***************************************************************************** * Copyright (C) 2001, 2002, 2006 the VideoLAN team * $Id$ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * Gildas Bazin <gbazin@netcourrier.com> * * 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_aout.h>#include <vlc_codec.h>#include <vlc_block.h>#include <vlc_sout.h>#include <vlc_codecs.h>#include <vlc_input.h>#include <vlc_bits.h>#include "vlc_block_helper.h"#include <assert.h>/* AAC Config in ES: * * AudioObjectType 5 bits * samplingFrequencyIndex 4 bits * if (samplingFrequencyIndex == 0xF) * samplingFrequency 24 bits * channelConfiguration 4 bits * GA_SpecificConfig * FrameLengthFlag 1 bit 1024 or 960 * DependsOnCoreCoder 1 bit (always 0) * ExtensionFlag 1 bit (always 0) *//***************************************************************************** * decoder_sys_t : decoder descriptor *****************************************************************************/typedef struct{ int i_object_type; int i_samplerate; int i_channel; int i_sbr; // 0: no sbr, 1: sbr, -1: unknown struct { int i_object_type; int i_samplerate; } extension; /* GASpecific */ int i_frame_length; // 1024 or 960} mpeg4_cfg_t;#define LATM_MAX_EXTRA_SIZE 64typedef struct{ int i_program; int i_layer; int i_frame_length_type; int i_frame_length; // type 1 int i_frame_length_index; // type 3 4 5 6 7 mpeg4_cfg_t cfg; /* Raw configuration */ int i_extra; uint8_t extra[LATM_MAX_EXTRA_SIZE];} latm_stream_t;#define LATM_MAX_LAYER (8)#define LATM_MAX_PROGRAM (16)typedef struct{ int b_same_time_framing; int i_sub_frames; int i_programs; int pi_layers[LATM_MAX_PROGRAM]; int pi_stream[LATM_MAX_PROGRAM][LATM_MAX_LAYER]; int i_streams; latm_stream_t stream[LATM_MAX_PROGRAM*LATM_MAX_LAYER]; int i_other_data; int i_crc; /* -1 if not set */} latm_mux_t;struct decoder_sys_t{ /* * Input properties */ int i_state; int i_type; block_bytestream_t bytestream; /* * Common properties */ audio_date_t end_date; mtime_t i_pts; int i_frame_size; unsigned int i_channels; unsigned int i_rate, i_frame_length, i_header_size; int i_input_rate; /* LOAS */ bool b_latm_cfg; latm_mux_t latm;};enum { STATE_NOSYNC, STATE_SYNC, STATE_HEADER, STATE_NEXT_SYNC, STATE_GET_DATA, STATE_SEND_DATA};enum { TYPE_NONE, TYPE_RAW, TYPE_ADTS, TYPE_LOAS};static const int pi_sample_rates[16] ={ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0};#define ADTS_HEADER_SIZE 9#define LOAS_HEADER_SIZE 3/**************************************************************************** * Local prototypes ****************************************************************************/static int OpenPacketizer( vlc_object_t * );static void ClosePacketizer( vlc_object_t * );static block_t *PacketizeRawBlock ( decoder_t *, block_t ** );static block_t *PacketizeStreamBlock( decoder_t *, block_t ** );/***************************************************************************** * Module descriptor *****************************************************************************/vlc_module_begin(); set_category( CAT_SOUT ); set_subcategory( SUBCAT_SOUT_PACKETIZER ); set_description( N_("MPEG4 audio packetizer") ); set_capability( "packetizer", 50 ); set_callbacks( OpenPacketizer, ClosePacketizer );vlc_module_end();/***************************************************************************** * OpenPacketizer: probe the packetizer and return score *****************************************************************************/static int OpenPacketizer( 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( 'm', 'p', '4', 'a' ) ) { 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 ) return VLC_ENOMEM; /* Misc init */ p_sys->i_state = STATE_NOSYNC; aout_DateSet( &p_sys->end_date, 0 ); p_sys->bytestream = block_BytestreamInit(); p_sys->i_input_rate = INPUT_RATE_DEFAULT; p_sys->b_latm_cfg = false; /* Set output properties */ p_dec->fmt_out.i_cat = AUDIO_ES; p_dec->fmt_out.i_codec = VLC_FOURCC('m','p','4','a'); msg_Dbg( p_dec, "running MPEG4 audio packetizer" ); if( p_dec->fmt_in.i_extra > 0 ) { uint8_t *p_config = (uint8_t*)p_dec->fmt_in.p_extra; int i_index; i_index = ( ( p_config[0] << 1 ) | ( p_config[1] >> 7 ) ) & 0x0f; if( i_index != 0x0f ) { p_dec->fmt_out.audio.i_rate = pi_sample_rates[i_index]; p_dec->fmt_out.audio.i_frame_length = (( p_config[1] >> 2 ) & 0x01) ? 960 : 1024; } else { p_dec->fmt_out.audio.i_rate = ( ( p_config[1] & 0x7f ) << 17 ) | ( p_config[2] << 9 ) | ( p_config[3] << 1 ) | ( p_config[4] >> 7 ); p_dec->fmt_out.audio.i_frame_length = (( p_config[4] >> 2 ) & 0x01) ? 960 : 1024; } p_dec->fmt_out.audio.i_channels = (p_config[i_index == 0x0f ? 4 : 1] >> 3) & 0x0f; msg_Dbg( p_dec, "AAC %dHz %d samples/frame", p_dec->fmt_out.audio.i_rate, p_dec->fmt_out.audio.i_frame_length ); aout_DateInit( &p_sys->end_date, p_dec->fmt_out.audio.i_rate ); p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; p_dec->fmt_out.p_extra = malloc( p_dec->fmt_in.i_extra ); if( !p_dec->fmt_out.p_extra ) { p_dec->fmt_out.i_extra = 0; return VLC_ENOMEM; } memcpy( p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ); /* Set callback */ p_dec->pf_packetize = PacketizeRawBlock; p_sys->i_type = TYPE_RAW; } else { msg_Dbg( p_dec, "no decoder specific info, must be an ADTS or LOAS stream" ); aout_DateInit( &p_sys->end_date, p_dec->fmt_in.audio.i_rate ); /* We will try to create a AAC Config from adts/loas */ p_dec->fmt_out.i_extra = 0; p_dec->fmt_out.p_extra = NULL; /* Set callback */ p_dec->pf_packetize = PacketizeStreamBlock; p_sys->i_type = TYPE_NONE; } return VLC_SUCCESS;}/**************************************************************************** * PacketizeRawBlock: the whole thing **************************************************************************** * This function must be fed with complete frames. ****************************************************************************/static block_t *PacketizeRawBlock( decoder_t *p_dec, block_t **pp_block ){ decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; if( !pp_block || !*pp_block ) return NULL; if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { //aout_DateSet( &p_sys->end_date, 0 ); block_Release( *pp_block ); return NULL; } p_block = *pp_block; *pp_block = NULL; /* Don't reuse this block */ if( !aout_DateGet( &p_sys->end_date ) && !p_block->i_pts ) { /* We've just started the stream, wait for the first PTS. */ block_Release( p_block ); return NULL; } else if( p_block->i_pts != 0 && p_block->i_pts != aout_DateGet( &p_sys->end_date ) ) { aout_DateSet( &p_sys->end_date, p_block->i_pts ); } p_block->i_pts = p_block->i_dts = aout_DateGet( &p_sys->end_date ); p_block->i_length = aout_DateIncrement( &p_sys->end_date, p_dec->fmt_out.audio.i_frame_length * p_sys->i_input_rate / INPUT_RATE_DEFAULT ) - p_block->i_pts; return p_block;}/**************************************************************************** * ADTS helpers ****************************************************************************/static int ADTSSyncInfo( decoder_t * p_dec, const uint8_t * p_buf, unsigned int * pi_channels, unsigned int * pi_sample_rate, unsigned int * pi_frame_length, unsigned int * pi_header_size ){ int i_profile, i_sample_rate_idx, i_frame_size; bool b_crc; /* Fixed header between frames */ //int i_id = ( (p_buf[1] >> 3) & 0x01) ? 2 : 4; /* MPEG-2 or 4 */ b_crc = !(p_buf[1] & 0x01); i_profile = p_buf[2] >> 6; i_sample_rate_idx = (p_buf[2] >> 2) & 0x0f; *pi_sample_rate = pi_sample_rates[i_sample_rate_idx]; //private_bit = (p_buf[2] >> 1) & 0x01; *pi_channels = ((p_buf[2] & 0x01) << 2) | ((p_buf[3] >> 6) & 0x03); //original_copy = (p_buf[3] >> 5) & 0x01; //home = (p_buf[3] >> 4) & 0x01; /* Variable header */ //copyright_id_bit = (p_buf[3] >> 3) & 0x01; //copyright_id_start = (p_buf[3] >> 2) & 0x01; i_frame_size = ((p_buf[3] & 0x03) << 11) | (p_buf[4] << 3) | ((p_buf[5] >> 5) /*& 0x7*/); //uint16_t buffer_fullness = ((p_buf[5] & 0x1f) << 6) | (p_buf[6] >> 2); unsigned short i_raw_blocks_in_frame = p_buf[6] & 0x03; if( !*pi_sample_rate || !*pi_channels || !i_frame_size ) { msg_Warn( p_dec, "Invalid ADTS header" ); return 0; } *pi_frame_length = 1024; if( i_raw_blocks_in_frame == 0 ) { if( b_crc ) { msg_Warn( p_dec, "ADTS CRC not supported" ); //uint16_t crc = (p_buf[7] << 8) | p_buf[8]; } } else { msg_Err( p_dec, "Multiple blocks per frame in ADTS not supported" ); return 0;#if 0 int i; const uint8_t *p_pos = p_buf + 7; uint16_t crc_block; uint16_t i_block_pos[3]; if( b_crc ) { for( i = 0 ; i < i_raw_blocks_in_frame ; i++ ) { /* the 1st block's position is known ... */ i_block_pos[i] = (*p_pos << 8) | *(p_pos+1); p_pos += 2; } crc_block = (*p_pos << 8) | *(p_pos+1); p_pos += 2; } for( i = 0 ; i <= i_raw_blocks_in_frame ; i++ ) { //read 1 block if( b_crc ) { msg_Err( p_dec, "ADTS CRC not supported" ); //uint16_t crc = (*p_pos << 8) | *(p_pos+1); //p_pos += 2; } }#endif } /* Build the decoder specific info header */ if( !p_dec->fmt_out.i_extra ) { p_dec->fmt_out.p_extra = malloc( 2 ); if( !p_dec->fmt_out.p_extra ) { p_dec->fmt_out.i_extra = 0; return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -