胡斌

support build-in speex to aac,controled by the root config keyword: speex2aac on/off

[submodule "trunk/3rdparty/speex"]
path = trunk/3rdparty/speex
url = git@123.56.226.173:hubin/speex.git
[submodule "trunk/3rdparty/fdk-aac"]
path = trunk/3rdparty/fdk-aac
url = git@123.56.226.173:hubin/fdk-aac.git
... ...
fdk-aac @ db608fee
Subproject commit db608feeed80cb1e7d6db6818293fa24900d967a
... ...
speex @ 6da384f4
Subproject commit 6da384f4f06d8db9510937aa0206c340dcacc7a2
... ...
... ... @@ -62,6 +62,9 @@ work_dir ./;
# @reamrk do not support reload.
# default: off
asprocess off;
# whether using build-in speex to aac transcoding
# default: off
speex2aac off;
#############################################################################################
# heartbeat/stats sections
... ... @@ -928,6 +931,16 @@ vhost same.vhost.forward.srs.com {
# active-active for cdn to build high available fault tolerance system.
# format: {ip}:{port} {ip_N}:{port_N}
forward 127.0.0.1:1936 127.0.0.1:1937;
# forward_in_turn all publish stream to the specified server in turn.
# this used to split/forward the current stream for transcode and make load balance
# active-active for cdn to build high available fault tolerance system.
# format: {ip}:{port} {ip_N}:{port_N}
forward_in_turn 127.0.0.1:19351 127.0.0.1:19352;
#if the forward server is same as this server , a origin,try use forward_peer,
#the stream pushed from other forward peer will not forward any more in this server
forward_peer 127.0.0.1:1936;
#list out the servers which is not srs ,used in forward or forward_in_turn,and forward_peer for example,forward to some CDN
forward_server_other 127.0.0.1:19351;
}
# the main comments for transcode
... ...
# main config for srs.
# @see full.conf for detail config.
listen 1935;
max_connections 1000;
srs_log_tank file;
srs_log_file ./objs/srs.log;
speex2aac on;
vhost __defaultVhost__ {
}
... ...
#!/bin/bash
#####################################################################################
# the main output dir, all configure and make output are in this dir.
#####################################################################################
... ... @@ -125,6 +123,8 @@ if [ $SRS_SSL = YES ]; then if [ $SRS_USE_SYS_SSL = NO ]; then LibSSLRoot="${SRS
# gperftools-2.1, for mem check and mem/cpu profile
LibGperfRoot=""; LibGperfFile=""
if [ $SRS_GPERF = YES ]; then LibGperfRoot="${SRS_OBJS_DIR}/gperf/include"; LibGperfFile="${SRS_OBJS_DIR}/gperf/lib/libtcmalloc_and_profiler.a"; fi
# codec libs:speex fdk-aac for SPEEX2AAC
LibSpeex2aacRoot="${SRS_OBJS_DIR}/libs/include"; LibSpeex2aacfile="${SRS_OBJS_DIR}/libs/lib/libspeex.a ${SRS_OBJS_DIR}/libs/lib/libfdk-aac.a"
# the link options, always use static link
SrsLinkOptions="-ldl";
if [ $SRS_SSL = YES ]; then if [ $SRS_USE_SYS_SSL = YES ]; then SrsLinkOptions="${SrsLinkOptions} -lssl -lcrypto"; fi fi
... ... @@ -166,10 +166,18 @@ MODULE_FILES=("srs_rtmp_amf0" "srs_rtmp_io" "srs_rtmp_stack"
PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh
PROTOCOL_OBJS="${MODULE_OBJS[@]}"
#
#SPEEX2AAC speex to aac
MODULE_ID="SPEEX2AAC"
MODULE_DEPENDS=("CORE" "KERNEL")
ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSpeex2aacRoot})
MODULE_FILES=("srs_tc_adc_speex" "srs_tc_aec_aac" "srs_tc_common")
SPEEX2AAC_INCS="src/transcode"; MODULE_DIR=${SPEEX2AAC_INCS} . auto/modules.sh
SPEEX2AAC_OBJS="${MODULE_OBJS[@]}"
#
#App Module
if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
MODULE_ID="APP"
MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL")
MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SPEEX2AAC")
ModuleLibIncs=(${LibSTRoot} ${LibHttpParserRoot} ${LibSSLRoot} ${SRS_OBJS_DIR})
MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source"
"srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream"
... ... @@ -202,8 +210,8 @@ LIBS_OBJS="${MODULE_OBJS[@]}"
#Main Module
if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
MODULE_ID="MAIN"
MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP")
ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibHttpParserRoot} ${LibSSLRoot})
MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP" "SPEEX2AAC")
ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibHttpParserRoot} ${LibSSLRoot} ${LibSpeex2aacRoot})
MODULE_FILES=("srs_main_server" "srs_main_ingest_hls")
# add each modules for main
for SRS_MODULE in ${SRS_MODULES[*]}; do
... ... @@ -229,9 +237,9 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
done
#
# all depends libraries
ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile} ${LibSSLfile} ${LibGperfFile})
ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile} ${LibSSLfile} ${LibGperfFile} ${LibSpeex2aacfile})
# all depends objects
MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]} ${MAIN_OBJS[@]}"
MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]} ${MAIN_OBJS[@]} ${SPEEX2AAC_OBJS[@]}"
LINK_OPTIONS="${SrsLinkOptions}${SrsGprofLink}${SrsGperfLink}"
#
# srs: srs(simple rtmp server) over st(state-threads)
... ... @@ -258,10 +266,10 @@ if [ $SRS_UTEST = YES ]; then
MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol"
"srs_utest_kernel" "srs_utest_core" "srs_utest_config"
"srs_utest_reload")
ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot})
ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile} ${LibSSLfile})
ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot} ${LibSpeex2aacRoot})
ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile} ${LibSSLfile} ${LibSpeex2aacfile})
MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP")
MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]}"
MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]} ${SPEEX2AAC_OBJS[@]}"
LINK_OPTIONS="-lpthread ${SrsLinkOptions}" MODULE_DIR="src/utest" APP_NAME="srs_utest" . auto/utest.sh
fi
... ... @@ -349,6 +357,7 @@ else
server: _prepare_dir
@echo "build the srs(simple rtmp server) over st(state-threads)"
./scripts/version.sh
./scripts/build_libs.sh
\$(MAKE) -f ${SRS_OBJS_DIR}/${SRS_MAKEFILE} srs
srs_ingest_hls: _prepare_dir
@echo "build the srs_ingest_hls for srs"
... ...
#!/bin/bash
mkdir -p objs
root=$PWD
if [ ! -d "$root/3rdparty/speex/.git" ]; then
cd ..
git submodule update --init
cd trunk
fi
if [ "$1" == "-f" ]; then
rm -rf objs/libs
fi
if [ ! -d "$root/objs/libs/include/speex" ]; then
cd 3rdparty/speex && ./autogen.sh && ./configure --prefix=$root/objs/libs --enable-shared=no && make && make install
cd $root
fi
if [ ! -d "$root/objs/libs/include/fdk-aac" ]; then
cd 3rdparty/fdk-aac && ./autogen.sh && ./configure --prefix=$root/objs/libs --enable-shared=no && make && make install
fi
... ...
... ... @@ -463,6 +463,8 @@ SrsConfig::SrsConfig()
root = new SrsConfDirective();
root->conf_line = 0;
root->name = "root";
_speex2aac = false;
}
SrsConfig::~SrsConfig()
... ... @@ -1005,6 +1007,8 @@ int SrsConfig::reload_conf(SrsConfig* conf)
return ret;
}
set_config_static();
return ret;
}
... ... @@ -1579,7 +1583,7 @@ int SrsConfig::check_config()
&& n != "max_connections" && n != "daemon" && n != "heartbeat"
&& n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms"
&& n != "http_stream" && n != "http_server" && n != "stream_caster"
&& n != "utc_time" && n != "work_dir" && n != "asprocess"
&& n != "utc_time" && n != "work_dir" && n != "asprocess" && n != "speex2aac"
) {
ret = ERROR_SYSTEM_CONFIG_INVALID;
srs_error("unsupported directive %s, ret=%d", n.c_str(), ret);
... ... @@ -2080,9 +2084,27 @@ int SrsConfig::check_config()
return ret;
}
set_config_static();
return ret;
}
void SrsConfig::set_config_static()
{
SrsConfDirective* conf = root->get("speex2aac");
if(conf){
if(conf->arg0() == "on"){
_speex2aac = true;
}
else
_speex2aac = false;
}
else
_speex2aac = false;
}
int SrsConfig::parse_buffer(SrsConfigBuffer* buffer)
{
int ret = ERROR_SUCCESS;
... ...
... ... @@ -1141,6 +1141,18 @@ public:
* @return the disk device name to stat. NULL if not configed.
*/
virtual SrsConfDirective* get_stats_disk_device();
public:
/**
* the flag to indicate auto transcode with build-in modules
*/
bool _speex2aac;
private:
/**
* set the global static variables from config file
*/
void set_config_static();
};
namespace _srs_internal
... ...
... ... @@ -46,6 +46,7 @@ using namespace std;
#include <srs_app_statistic.hpp>
#include <srs_core_autofree.hpp>
#include <srs_rtmp_utility.hpp>
#include <srs_tc_av_codec.hpp>
#define CONST_MAX_JITTER_MS 250
#define CONST_MAX_JITTER_MS_NEG -250
... ... @@ -970,6 +971,8 @@ SrsSource::SrsSource()
_srs_config->subscribe(this);
atc = false;
_speex_opt = NULL;
_aac_opt = NULL;
}
SrsSource::~SrsSource()
... ... @@ -1013,6 +1016,15 @@ SrsSource::~SrsSource()
#endif
srs_freep(_req);
if (_speex_opt){
adc_spx.close_codec((tc_audio_opt *)_speex_opt);
_speex_opt = NULL;
}
if (_aac_opt) {
aec_aac.close_codec((tc_audio_opt *)_aac_opt);
_aac_opt = NULL;
}
}
void SrsSource::dispose()
... ... @@ -1662,6 +1674,101 @@ int SrsSource::on_data(SrsCommonMessage* shared_data)
int SrsSource::on_audio(SrsCommonMessage* shared_audio)
{
int ret = ERROR_SUCCESS;
if(_srs_config->_speex2aac && SrsFlvCodec::audio_is_speex(shared_audio->payload, shared_audio->size)){
if (NULL == _speex_opt){
tc_audio_opt * speex_opt = new tc_audio_opt();
_speex_opt = speex_opt;
speex_opt->sample_rate = 16000;
speex_opt->channels = 1;
speex_opt->frame_size = 320;
speex_opt->buffer_size = 640;
adc_spx.open_codec(speex_opt);
if (NULL == _aac_opt){
tc_audio_opt * aac_opt = new tc_audio_opt();
_aac_opt = aac_opt;
aac_opt->sample_rate = 16000;
aac_opt->channels = 1;
aac_opt->frame_size = 1024;
aac_opt->buffer_size = 2048;
aac_opt->audio_bitrate = 64000;
aec_aac.open_codec(aac_opt);
char * buf = new char[aac_opt->extradata_size + 2];
buf[0] = 0xAF;
buf[1] = 0x00;
memcpy(buf + 2, aac_opt->extradata, aac_opt->extradata_size);
SrsCommonMessage msg;
msg.header = shared_audio->header;
msg.payload = buf;
msg.size = aac_opt->extradata_size + 2;
ret = _on_audio(&msg);
freep(msg.payload);
if(ret != ERROR_SUCCESS){
freep(shared_audio->payload);
return ret;
}
}
}
uint8_t* packet_data = (uint8_t *)shared_audio->payload + 1;
int packet_size = shared_audio->size - 1;
char * payload = shared_audio->payload;
do {
uint8_t out_data[1024];
uint32_t out_size;
int ret_spx = adc_spx.decode_frame((tc_audio_opt*)_speex_opt, packet_data, packet_size, out_data);
if (ret_spx >= 0) {
#if 0
static FILE * fp = NULL;
if (!fp){
fp = fopen("testout.pcm", "wb");
}
if (fp){
fwrite(out_data, 1, 640, fp);
}
#endif
((tc_audio_opt *)_aac_opt)->buffer_size = ((tc_audio_opt*)_speex_opt)->buffer_size;
shared_audio->payload = new char[1024];
out_size = 1022;
int ret_aac = aec_aac.encode_frame((tc_audio_opt *)_aac_opt, out_data, (uint8_t *)shared_audio->payload + 2 , &out_size);
if (ret_aac >= 0){
if (out_size){
shared_audio->payload[0] = 0xAF;
shared_audio->payload[1] = 0x01;
shared_audio->size = out_size +2;
ret = _on_audio(shared_audio);
#if 0
static int max_out_size = 0;
if(out_size > max_out_size){
max_out_size = out_size;
srs_trace("max_speex_aac_outsize:%d",max_out_size);
}
#endif
}
}
}
packet_data += ret_spx;
packet_size -= ret_spx;
} while (packet_size > 0);
freep(payload);
}
else {
return _on_audio(shared_audio);
}
return ret;
}
int SrsSource::_on_audio(SrsCommonMessage* shared_audio)
{
int ret = ERROR_SUCCESS;
// monotically increase detect.
... ...
... ... @@ -511,6 +511,8 @@ private:
SrsSharedPtrMessage* cache_sh_video;
// the cached audio sequence header.
SrsSharedPtrMessage* cache_sh_audio;
void * _speex_opt;
void * _aac_opt;
public:
SrsSource();
virtual ~SrsSource();
... ... @@ -559,6 +561,7 @@ public:
public:
virtual int on_audio(SrsCommonMessage* audio);
private:
virtual int _on_audio(SrsCommonMessage* audio);
virtual int on_audio_imp(SrsSharedPtrMessage* audio);
public:
virtual int on_video(SrsCommonMessage* video);
... ...
... ... @@ -266,6 +266,18 @@ bool SrsFlvCodec::audio_is_aac(char* data, int size)
return sound_format == SrsCodecAudioAAC;
}
bool SrsFlvCodec::audio_is_speex(char* data, int size)
{
// 1bytes required.
if (size < 1) {
return false;
}
char sound_format = (*data >> 4) & 0x0F;
return sound_format == SrsCodecAudioSpeex;
}
bool SrsFlvCodec::video_is_acceptable(char* data, int size)
{
// 1bytes required.
... ...
... ... @@ -223,6 +223,10 @@ public:
*/
static bool audio_is_aac(char* data, int size);
/**
* check codec speex.
*/
static bool audio_is_speex(char* data, int size);
/**
* check the video RTMP/flv header info,
* @return true if video RTMP/flv header is ok.
* @remark all type of audio is possible, no need to check audio.
... ...
#include "speex/speex.h"
#include "srs_tc_av_codec.hpp"
#include "srs_tc_common.hpp"
typedef struct {
SpeexBits bits;
void *dec_state;
int dec_frame_size;
int dec_buffer_size;
spx_int16_t* output_buffer;
} handle_adc_spx_t;
static int open_codec_spx(tc_audio_opt* opt) {
handle_adc_spx_t* s = (handle_adc_spx_t*)calloc(1, sizeof(handle_adc_spx_t));
opt->handle = s;
speex_bits_init(&s->bits);
s->dec_state = speex_decoder_init(&speex_wb_mode);
speex_decoder_ctl(s->dec_state, SPEEX_GET_FRAME_SIZE, &s->dec_frame_size);
s->dec_buffer_size = s->dec_frame_size * sizeof(spx_int16_t);
opt->sample_rate = 16000;
opt->channels = 1;
opt->buffer_size = s->dec_buffer_size ;
opt->frame_size = s->dec_frame_size;
return 0;
}
static int decode_frame_spx(tc_audio_opt* opt, uint8_t* inData, uint32_t inDataSize, uint8_t* outData) {
handle_adc_spx_t* s = (handle_adc_spx_t*)opt->handle;
int consumed = 0;
if (speex_bits_remaining(&s->bits) < 5 ||
speex_bits_peek_unsigned(&s->bits, 5) == 0xF) {
speex_bits_read_from(&s->bits, (char*)inData, inDataSize);
consumed = inDataSize;
}
int err = 0;
if ((err = speex_decode_int(s->dec_state, &s->bits, (spx_int16_t *)outData)) == 0) {
return consumed;
} else {
tc_log(LOG_LEVEL_ERROR, "speex_decode_int error: %d", err);
return -1;
}
}
static int close_codec_spx(tc_audio_opt* opt) {
handle_adc_spx_t* s = (handle_adc_spx_t*)opt->handle;
speex_decoder_destroy(s->dec_state);
speex_bits_destroy(&s->bits);
return 0;
}
const tc_av_codec_t adc_spx = {
11,
"adc_spx",
open_codec_spx,
decode_frame_spx,
NULL,
close_codec_spx
};
\ No newline at end of file
... ...
#include "fdk-aac/aacenc_lib.h"
#include "srs_tc_av_codec.hpp"
#include "srs_tc_common.hpp"
static const char *aac_get_error(AACENC_ERROR err)
{
switch (err) {
case AACENC_OK:
return "No error";
case AACENC_INVALID_HANDLE:
return "Invalid handle";
case AACENC_MEMORY_ERROR:
return "Memory allocation error";
case AACENC_UNSUPPORTED_PARAMETER:
return "Unsupported parameter";
case AACENC_INVALID_CONFIG:
return "Invalid config";
case AACENC_INIT_ERROR:
return "Initialization error";
case AACENC_INIT_AAC_ERROR:
return "AAC library initialization error";
case AACENC_INIT_SBR_ERROR:
return "SBR library initialization error";
case AACENC_INIT_TP_ERROR:
return "Transport library initialization error";
case AACENC_INIT_META_ERROR:
return "Metadata library initialization error";
case AACENC_ENCODE_ERROR:
return "Encoding error";
case AACENC_ENCODE_EOF:
return "End of file";
default:
return "Unknown error";
}
}
typedef struct {
HANDLE_AACENCODER handle;
int afterburner;
int eld_sbr;
int signaling;
int latm;
int header_period;
int vbr;
uint8_t buf[2048];
int data_len;
} handle_aec_aac_t;
static int open_codec_aac(tc_audio_opt* opt) {
handle_aec_aac_t* s = (handle_aec_aac_t*)calloc(1, sizeof(handle_aec_aac_t));
opt->handle = s;
AACENC_ERROR err = AACENC_OK;
AACENC_InfoStruct info = { 0 };
CHANNEL_MODE mode;
int sce = 0, cpe = 0;
do{
if ((err = aacEncOpen(&s->handle, 0, opt->channels)) != AACENC_OK) {
tc_log(LOG_LEVEL_ERROR, "[aac] Unable to open the encoder.\n");
break;
}
int aot;
if(opt->audio_profile == 0) {
aot = 2; //LC-AAC
}else {
aot = 5; //HE-AAC
}
//set audio object type
if ((err = aacEncoder_SetParam(s->handle, AACENC_AOT, aot)) != AACENC_OK) {
tc_log(LOG_LEVEL_ERROR, "[aac] Unable to set the AOT %d: %s\n",aot, aac_get_error(err));
break;
}
//set sample rate
if ((err = aacEncoder_SetParam(s->handle, AACENC_SAMPLERATE, opt->sample_rate)) != AACENC_OK) {
tc_log(LOG_LEVEL_ERROR, "[aac] Unable to set the sample rate %d: %s\n",opt->sample_rate, aac_get_error(err));
break;
}
switch (opt->channels) {
case 1: mode = MODE_1; sce = 1; cpe = 0; break;
case 2: mode = MODE_2; sce = 0; cpe = 1; break;
default:mode = MODE_1; sce = 1; cpe = 0; break;
}
if ((err = aacEncoder_SetParam(s->handle, AACENC_CHANNELMODE, mode)) != AACENC_OK) {
tc_log(LOG_LEVEL_ERROR, "[aac] Unable to set channel mode %d: %s\n", mode, aac_get_error(err));
break;
}
if ((err = aacEncoder_SetParam(s->handle, AACENC_CHANNELORDER, 1)) != AACENC_OK) {
tc_log(LOG_LEVEL_ERROR, "[aac] Unable to set channel order %d: %s\n", mode, aac_get_error(err));
break;
}
if ((err = aacEncoder_SetParam(s->handle, AACENC_BITRATE, opt->audio_bitrate)) != AACENC_OK) {
tc_log(LOG_LEVEL_ERROR, "[aac] Unable to set the bitrate %d: %s\n", opt->audio_bitrate, aac_get_error(err));
break;
}
if (aacEncoder_SetParam(s->handle, AACENC_TRANSMUX, 0) != AACENC_OK) {
tc_log(LOG_LEVEL_ERROR, "Unable to set the ADTS transmux\n");
break;
}
if ((err = aacEncoder_SetParam(s->handle, AACENC_SIGNALING_MODE, 2)) != AACENC_OK) {
tc_log(LOG_LEVEL_ERROR, "Unable to set signaling mode %d: %s\n",2, aac_get_error(err));
break;
}
if (aacEncEncode(s->handle, NULL, NULL, NULL, NULL) != AACENC_OK) {
tc_log(LOG_LEVEL_ERROR, "Unable to initialize the encoder\n");
return 1;
}
if (aacEncInfo(s->handle, &info) != AACENC_OK) {
tc_log(LOG_LEVEL_ERROR, "Unable to get the encoder info\n");
return 1;
}
opt->extradata = (uint8_t *)malloc(info.confSize);
opt->extradata_size = info.confSize;
memcpy(opt->extradata, info.confBuf, info.confSize);
}while (0);
if( err != AACENC_OK) {
aacEncClose(&s->handle);
}
return 0;
}
static int encode_frame_aac(tc_audio_opt* opt, uint8_t* inData, uint8_t* inOutData, uint32_t* inOutDataSize) {
handle_aec_aac_t* s = (handle_aec_aac_t*)opt->handle;
AACENC_BufDesc in_buf = { 0 }, out_buf = { 0 };
AACENC_InArgs in_args = { 0 };
AACENC_OutArgs out_args = { 0 };
int in_identifier = IN_AUDIO_DATA;
int in_size, in_elem_size;
int out_identifier = OUT_BITSTREAM_DATA;
int out_size, out_elem_size;
void *in_ptr, *out_ptr;
AACENC_ERROR err;
if (s->data_len + opt->buffer_size < 2048){
memcpy(s->buf + s->data_len, inData, opt->buffer_size);
s->data_len += opt->buffer_size;
*inOutDataSize = 0;
return 0;
}
else{
memcpy(s->buf + s->data_len, inData, 2048 - s->data_len);
in_ptr = s->buf;
in_size = 2048;
in_elem_size = 2;
in_args.numInSamples = opt->frame_size;
in_buf.numBufs = 1;
in_buf.bufs = &in_ptr;
in_buf.bufferIdentifiers = &in_identifier;
in_buf.bufSizes = &in_size;
in_buf.bufElSizes = &in_elem_size;
out_ptr = inOutData;
out_size = *inOutDataSize;
out_elem_size = 1;
out_buf.numBufs = 1;
out_buf.bufs = &out_ptr;
out_buf.bufferIdentifiers = &out_identifier;
out_buf.bufSizes = &out_size;
out_buf.bufElSizes = &out_elem_size;
if ((err = aacEncEncode(s->handle, &in_buf, &out_buf, &in_args, &out_args)) != AACENC_OK) {
tc_log(LOG_LEVEL_ERROR, "[aac] Unable to encode frame: %s\n", aac_get_error(err));
return -1;
}
*inOutDataSize = out_args.numOutBytes;
memcpy(s->buf, inData + 2048 - s->data_len, opt->buffer_size -( 2048 - s->data_len));
s->data_len = opt->buffer_size - (2048 - s->data_len);
}
return 0;
}
static int close_codec_aac(tc_audio_opt* opt) {
handle_aec_aac_t* s = (handle_aec_aac_t*)opt->handle;
if (s->handle) {
aacEncClose(&s->handle);
}
freep(opt->extradata);
freep(opt->handle);
return 0;
}
const tc_av_codec_t aec_aac = {
10,
"aec_aac",
open_codec_aac,
NULL,
encode_frame_aac,
close_codec_aac
};
... ...
#ifndef TC_AV_CODEC_H
#define TC_AV_CODEC_H
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_EXTRA 3
typedef void* handle_t;
typedef struct {
int sample_rate;
int channels;
int frame_size;
int buffer_size;
int audio_profile;
int audio_bitrate;
handle_t handle;
uint32_t extradata_size;
uint8_t* extradata;
}tc_audio_opt;
typedef struct {
int codec_id;
const char* codec_name;
int (*open_codec)(tc_audio_opt* opt);
int (*decode_frame)(tc_audio_opt* opt, uint8_t* inData, uint32_t inDataSize, uint8_t* outData);
int (*encode_frame)(tc_audio_opt* opt, uint8_t* inData, uint8_t* inoutData, uint32_t* inoutDataSize);
int (*close_codec)(tc_audio_opt* opt);
}tc_av_codec_t;
extern const tc_av_codec_t adc_aac;
extern const tc_av_codec_t aec_aac;
extern const tc_av_codec_t adc_spx;
#define freep(x) if(x){ free(x); x = NULL;}
#endif /* tc_av_codec_h */
... ...
#include "srs_tc_common.hpp"
#include <stdarg.h>
#include <srs_kernel_log.hpp>
void tc_log(int log_level, const char *format, ...)
{
va_list args;
va_start(args, format);
if (log_level == LOG_LEVEL_INFO){
srs_info(format, args);
}
else if (log_level == LOG_LEVEL_WARN){
srs_warn(format, args);
}
else if (log_level == LOG_LEVEL_ERROR){
srs_error(format, args);
}
va_end(args);
}
... ...
#ifndef TC_COMMON_H_
#define TC_COMMON_H_
enum LOG_LEVEL
{
LOG_LEVEL_INFO,
LOG_LEVEL_WARN,
LOG_LEVEL_ERROR,
};
void tc_log(int log_level, const char *format, ...);
#endif
\ No newline at end of file
... ...