This source file includes following definitions.
- dc_audio_encoder_open
- dc_audio_encoder_read
- dc_audio_encoder_flush
- ensure_resampler
- resample_audio
- dc_audio_encoder_encode
- dc_audio_encoder_close
#include "audio_encoder.h"
extern void build_dict(void *priv_data, const char *options);
int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *audio_data_conf)
{
AVDictionary *opts = NULL;
audio_output_file->audio_data_conf = audio_data_conf;
audio_output_file->fifo = av_fifo_alloc(2 * MAX_AUDIO_PACKET_SIZE);
audio_output_file->aframe = FF_ALLOC_FRAME();
audio_output_file->adata_buf = (uint8_t*) av_malloc(2 * MAX_AUDIO_PACKET_SIZE);
#ifndef GPAC_USE_LIBAV
audio_output_file->aframe->channels = -1;
#endif
#ifndef LIBAV_FRAME_OLD
audio_output_file->aframe->channel_layout = 0;
audio_output_file->aframe->sample_rate = -1;
#endif
audio_output_file->aframe->format = -1;
audio_output_file->codec = avcodec_find_encoder_by_name(audio_data_conf->codec);
if (audio_output_file->codec == NULL) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Output audio codec %s not found\n", audio_data_conf->codec));
return -1;
}
audio_output_file->codec_ctx = avcodec_alloc_context3(audio_output_file->codec);
audio_output_file->codec_ctx->codec_id = audio_output_file->codec->id;
audio_output_file->codec_ctx->codec_type = AVMEDIA_TYPE_AUDIO;
audio_output_file->codec_ctx->bit_rate = audio_data_conf->bitrate;
audio_output_file->codec_ctx->sample_rate = DC_AUDIO_SAMPLE_RATE ;
{
AVRational time_base;
time_base.num = 1;
time_base.den = audio_output_file->codec_ctx->sample_rate;
audio_output_file->codec_ctx->time_base = time_base;
}
audio_output_file->codec_ctx->channels = audio_data_conf->channels;
if (audio_data_conf->channels == 1) {
audio_output_file->codec_ctx->channel_layout = AV_CH_LAYOUT_MONO;
} else {
audio_output_file->codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
}
audio_output_file->codec_ctx->sample_fmt = audio_output_file->codec->sample_fmts[0];
#ifdef DC_AUDIO_RESAMPLER
audio_output_file->aresampler = NULL;
#endif
if (strcmp(audio_data_conf->custom, "")) {
build_dict(audio_output_file->codec_ctx->priv_data, audio_data_conf->custom);
}
audio_output_file->astream_idx = 0;
av_dict_set(&opts, "strict", "experimental", 0);
if (avcodec_open2(audio_output_file->codec_ctx, audio_output_file->codec, &opts) < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output audio codec\n"));
av_dict_free(&opts);
return -1;
}
av_dict_free(&opts);
audio_output_file->frame_bytes = audio_output_file->codec_ctx->frame_size * av_get_bytes_per_sample(DC_AUDIO_SAMPLE_FORMAT) * DC_AUDIO_NUM_CHANNELS;
#ifndef FF_API_AVFRAME_LAVC
avcodec_get_frame_defaults(audio_output_file->aframe);
#else
av_frame_unref(audio_output_file->aframe);
#endif
audio_output_file->aframe->nb_samples = audio_output_file->codec_ctx->frame_size;
if (avcodec_fill_audio_frame(audio_output_file->aframe, audio_output_file->codec_ctx->channels, audio_output_file->codec_ctx->sample_fmt,
audio_output_file->adata_buf, audio_output_file->codec_ctx->frame_size * av_get_bytes_per_sample(audio_output_file->codec_ctx->sample_fmt) * audio_output_file->codec_ctx->channels, 1) < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Fill audio frame failed\n"));
return -1;
}
return 0;
}
int dc_audio_encoder_read(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data)
{
int ret;
AudioDataNode *audio_data_node;
ret = dc_consumer_lock(&audio_output_file->consumer, &audio_input_data->circular_buf);
if (ret < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Audio encoder got an end of buffer!\n"));
return -2;
}
dc_consumer_unlock_previous(&audio_output_file->consumer, &audio_input_data->circular_buf);
audio_data_node = (AudioDataNode *) dc_consumer_consume(&audio_output_file->consumer, &audio_input_data->circular_buf);
#ifndef GPAC_USE_LIBAV
audio_output_file->aframe->channels = audio_output_file->codec_ctx->channels;
#endif
#ifndef LIBAV_FRAME_OLD
audio_output_file->aframe->channel_layout = audio_output_file->codec_ctx->channel_layout;
audio_output_file->aframe->sample_rate = audio_output_file->codec_ctx->sample_rate;
#endif
audio_output_file->aframe->format = audio_output_file->codec_ctx->sample_fmt;
av_fifo_generic_write(audio_output_file->fifo, audio_data_node->abuf, audio_data_node->abuf_size, NULL);
dc_consumer_advance(&audio_output_file->consumer);
return 0;
}
#if 0
int dc_audio_encoder_flush(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data)
{
int got_pkt;
AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx;
av_init_packet(&audio_output_file->packet);
audio_output_file->packet.data = NULL;
audio_output_file->packet.size = 0;
audio_output_file->aframe->pts = audio_input_data->next_pts;
#ifdef DC_AUDIO_RESAMPLER
#error resampling is not done here
#endif
if (avcodec_encode_audio2(audio_codec_ctx, &audio_output_file->packet, NULL, &got_pkt) != 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while encoding audio.\n"));
return -1;
}
if (got_pkt) {
return 0;
}
av_free_packet(&audio_output_file->packet);
return 1;
}
#endif
#ifdef DC_AUDIO_RESAMPLER
static int ensure_resampler(AudioOutputFile *audio_output_file, AVCodecContext *audio_codec_ctx)
{
if (!audio_output_file->aresampler) {
audio_output_file->aresampler = avresample_alloc_context();
if (!audio_output_file->aresampler) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate the audio resampler. Aborting.\n"));
return -1;
}
av_opt_set_int(audio_output_file->aresampler, "in_channel_layout", DC_AUDIO_CHANNEL_LAYOUT, 0);
av_opt_set_int(audio_output_file->aresampler, "out_channel_layout", audio_codec_ctx->channel_layout, 0);
av_opt_set_int(audio_output_file->aresampler, "in_sample_fmt", DC_AUDIO_SAMPLE_FORMAT, 0);
av_opt_set_int(audio_output_file->aresampler, "out_sample_fmt", audio_codec_ctx->sample_fmt, 0);
av_opt_set_int(audio_output_file->aresampler, "in_sample_rate", DC_AUDIO_SAMPLE_RATE, 0);
av_opt_set_int(audio_output_file->aresampler, "out_sample_rate", audio_codec_ctx->sample_rate, 0);
av_opt_set_int(audio_output_file->aresampler, "in_channels", DC_AUDIO_NUM_CHANNELS, 0);
av_opt_set_int(audio_output_file->aresampler, "out_channels", audio_codec_ctx->channels, 0);
if (avresample_open(audio_output_file->aresampler)) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not open the audio resampler. Aborting.\n"));
return -1;
}
}
return 0;
}
static int resample_audio(AudioOutputFile *audio_output_file, AVCodecContext *audio_codec_ctx, int *num_planes_out)
{
int i, linesize;
uint8_t **output;
*num_planes_out = av_sample_fmt_is_planar(audio_output_file->codec->sample_fmts[0]) ? audio_output_file->codec_ctx->channels : 1;
linesize = audio_output_file->codec_ctx->frame_size * av_get_bytes_per_sample(audio_output_file->codec->sample_fmts[0]) * audio_output_file->codec_ctx->channels / *num_planes_out;
output = (uint8_t**)av_malloc(*num_planes_out*sizeof(uint8_t*));
for (i=0; i<*num_planes_out; i++) {
output[i] = (uint8_t*)av_malloc(linesize);
}
if (avresample_convert(audio_output_file->aresampler, output, linesize, audio_output_file->aframe->nb_samples, audio_output_file->aframe->extended_data, audio_output_file->aframe->linesize[0], audio_output_file->aframe->nb_samples) < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not resample audio frame. Aborting.\n"));
return -1;
}
audio_output_file->aframe->extended_data = output;
for (i=0; i<*num_planes_out; i++) {
audio_output_file->aframe->linesize[i] = linesize;
}
audio_codec_ctx->channel_layout = audio_output_file->aframe->channel_layout;
audio_codec_ctx->sample_fmt = audio_output_file->aframe->format;
audio_codec_ctx->sample_rate = audio_output_file->aframe->sample_rate;
#ifndef GPAC_USE_LIBAV
audio_codec_ctx->channels = audio_output_file->aframe->channels;
#endif
return 0;
}
#endif
int dc_audio_encoder_encode(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data)
{
int got_pkt;
AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx;
while (av_fifo_size(audio_output_file->fifo) >= audio_output_file->frame_bytes) {
#ifdef DC_AUDIO_RESAMPLER
uint8_t **data = NULL;
int num_planes_out = 0;
#endif
Bool resample;
av_fifo_generic_read(audio_output_file->fifo, audio_output_file->adata_buf, audio_output_file->frame_bytes, NULL);
audio_output_file->aframe->data[0] = audio_output_file->adata_buf;
audio_output_file->aframe->linesize[0] = audio_output_file->frame_bytes;
audio_output_file->aframe->linesize[1] = 0;
av_init_packet(&audio_output_file->packet);
audio_output_file->packet.data = NULL;
audio_output_file->packet.size = 0;
resample = (DC_AUDIO_SAMPLE_FORMAT != audio_codec_ctx->sample_fmt
|| DC_AUDIO_SAMPLE_RATE != audio_codec_ctx->sample_rate
|| DC_AUDIO_NUM_CHANNELS != audio_codec_ctx->channels
|| DC_AUDIO_CHANNEL_LAYOUT != audio_codec_ctx->channel_layout);
if (resample) {
#ifndef DC_AUDIO_RESAMPLER
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Audio resampling is needed at the encoding stage, but not supported by your version of DashCast. Aborting.\n"));
exit(1);
#else
if (ensure_resampler(audio_output_file, audio_codec_ctx)) {
return -1;
}
data = audio_output_file->aframe->extended_data;
if (resample_audio(audio_output_file, audio_codec_ctx, &num_planes_out)) {
return -1;
}
#endif
}
if (avcodec_encode_audio2(audio_codec_ctx, &audio_output_file->packet, audio_output_file->aframe, &got_pkt) != 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while encoding audio.\n"));
#ifdef DC_AUDIO_RESAMPLER
if (resample) {
int i;
for (i=0; i<num_planes_out; ++i) {
av_free(audio_output_file->aframe->extended_data[i]);
}
av_free(audio_output_file->aframe->extended_data);
audio_output_file->aframe->extended_data = data;
}
#endif
return -1;
}
#ifdef DC_AUDIO_RESAMPLER
if (resample) {
int i;
for (i=0; i<num_planes_out; ++i) {
av_free(audio_output_file->aframe->extended_data[i]);
}
av_free(audio_output_file->aframe->extended_data);
audio_output_file->aframe->extended_data = data;
}
#endif
if (got_pkt) {
return 0;
}
av_free_packet(&audio_output_file->packet);
}
return 1;
}
void dc_audio_encoder_close(AudioOutputFile *audio_output_file)
{
av_fifo_free(audio_output_file->fifo);
av_free(audio_output_file->adata_buf);
av_free(audio_output_file->aframe);
avcodec_close(audio_output_file->codec_ctx);
av_free(audio_output_file->codec_ctx);
#ifdef DC_AUDIO_RESAMPLER
avresample_free(&audio_output_file->aresampler);
#endif
}