This source file includes following definitions.
- dc_audio_decoder_open
- ensure_resampler
- resample_audio
- dc_audio_decoder_read
- dc_audio_decoder_close
#include "audio_decoder.h"
int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio_data_conf, int mode, int no_loop, int video_framerate)
{
u32 i;
AVCodecContext *codec_ctx;
AVCodec *codec;
AVInputFormat *in_fmt = NULL;
if (!audio_data_conf) return -1;
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio Decoder enter setup at UTC "LLU"\n", gf_net_get_utc() ));
if (strcmp(audio_data_conf->format,"") != 0) {
in_fmt = av_find_input_format(audio_data_conf->format);
if (in_fmt == NULL) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find the format %s.\n", audio_data_conf->format));
return -1;
}
}
if (!audio_input_file->av_fmt_ctx) {
s32 ret;
AVDictionary *options = NULL;
if (video_framerate > 0) {
char vfr[16];
snprintf(vfr, sizeof(vfr), "%d", video_framerate);
ret = av_dict_set(&options, "framerate", vfr, 0);
if (ret < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set video framerate %s.\n", vfr));
return -1;
}
}
ret = avformat_open_input(&audio_input_file->av_fmt_ctx, audio_data_conf->filename, in_fmt, options ? &options : NULL);
if (ret != 0) {
if (options) {
av_dict_free(&options);
options = NULL;
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error %d opening input - retrying without options\n", ret));
ret = avformat_open_input(&audio_input_file->av_fmt_ctx, audio_data_conf->filename, in_fmt, NULL);
}
if (ret != 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open file: %s\n", audio_data_conf->filename));
return -1;
}
}
if (options) av_dict_free(&options);
if (avformat_find_stream_info(audio_input_file->av_fmt_ctx, NULL) < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find stream information\n"));
return -1;
}
av_dump_format(audio_input_file->av_fmt_ctx, 0, audio_data_conf->filename, 0);
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio capture open at UTC "LLU"\n", gf_net_get_utc() ));
audio_input_file->astream_idx = -1;
for (i=0; i<audio_input_file->av_fmt_ctx->nb_streams; i++) {
if (audio_input_file->av_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
audio_input_file->astream_idx = i;
break;
}
}
if (audio_input_file->astream_idx == -1) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find a audio stream\n"));
return -1;
}
codec_ctx = audio_input_file->av_fmt_ctx->streams[audio_input_file->astream_idx]->codec;
codec = avcodec_find_decoder(codec_ctx->codec_id);
if (codec == NULL) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Input audio codec is not supported.\n"));
avformat_close_input(&audio_input_file->av_fmt_ctx);
return -1;
}
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input audio codec.\n"));
avformat_close_input(&audio_input_file->av_fmt_ctx);
return -1;
}
#ifdef DC_AUDIO_RESAMPLER
audio_input_file->aresampler = NULL;
#endif
audio_input_file->fifo = av_fifo_alloc(2 * MAX_AUDIO_PACKET_SIZE);
audio_data_conf->channels = codec_ctx->channels;
audio_data_conf->samplerate = codec_ctx->sample_rate;
audio_input_file->mode = mode;
audio_input_file->no_loop = no_loop;
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio Decoder open at UTC "LLU"\n", gf_net_get_utc() ));
return 0;
}
#ifdef DC_AUDIO_RESAMPLER
static int ensure_resampler(AudioInputFile *audio_input_file, int sample_rate, int num_channels, u64 channel_layout, enum AVSampleFormat sample_format)
{
if (!audio_input_file->aresampler) {
audio_input_file->aresampler = avresample_alloc_context();
if (!audio_input_file->aresampler) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate the audio resampler. Aborting.\n"));
return -1;
}
av_opt_set_int(audio_input_file->aresampler, "in_channel_layout", channel_layout, 0);
av_opt_set_int(audio_input_file->aresampler, "out_channel_layout", DC_AUDIO_CHANNEL_LAYOUT, 0);
av_opt_set_int(audio_input_file->aresampler, "in_sample_fmt", sample_format, 0);
av_opt_set_int(audio_input_file->aresampler, "out_sample_fmt", DC_AUDIO_SAMPLE_FORMAT, 0);
av_opt_set_int(audio_input_file->aresampler, "in_sample_rate", sample_rate, 0);
av_opt_set_int(audio_input_file->aresampler, "out_sample_rate", DC_AUDIO_SAMPLE_RATE, 0);
av_opt_set_int(audio_input_file->aresampler, "in_channels", num_channels, 0);
av_opt_set_int(audio_input_file->aresampler, "out_channels", DC_AUDIO_NUM_CHANNELS, 0);
if (avresample_open(audio_input_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(AudioInputFile *audio_input_file, AudioInputData *audio_input_data, AVCodecContext *audio_codec_ctx, uint8_t ***output, int *num_planes_out, int num_channels, enum AVSampleFormat sample_format)
{
int i;
*num_planes_out = av_sample_fmt_is_planar(DC_AUDIO_SAMPLE_FORMAT) ? DC_AUDIO_NUM_CHANNELS : 1;
*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(DC_AUDIO_MAX_CHUNCK_SIZE);
}
i = avresample_convert(audio_input_file->aresampler, *output, DC_AUDIO_MAX_CHUNCK_SIZE, audio_input_data->aframe->nb_samples, audio_input_data->aframe->extended_data, audio_input_data->aframe->linesize[0], audio_input_data->aframe->nb_samples);
if (i < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not resample audio frame. Aborting.\n"));
return -1;
}
return i;
}
#endif
int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audio_input_data)
{
int ret;
AVPacket packet;
int got_frame = 0;
AVCodecContext *codec_ctx;
AudioDataNode *audio_data_node;
codec_ctx = audio_input_file->av_fmt_ctx->streams[audio_input_file->astream_idx]->codec;
while (1) {
if (audio_input_file->av_pkt_list) {
if (gf_list_count(audio_input_file->av_pkt_list)) {
AVPacket *packet_copy;
assert(audio_input_file->av_pkt_list);
gf_mx_p(audio_input_file->av_pkt_list_mutex);
packet_copy = (AVPacket*)gf_list_pop_front(audio_input_file->av_pkt_list);
gf_mx_v(audio_input_file->av_pkt_list_mutex);
if (packet_copy == NULL) {
ret = AVERROR_EOF;
} else {
memcpy(&packet, packet_copy, sizeof(AVPacket));
gf_free(packet_copy);
ret = 0;
}
} else {
gf_sleep(1);
continue;
}
} else {
ret = av_read_frame(audio_input_file->av_fmt_ctx, &packet);
}
if (ret == AVERROR_EOF) {
if (audio_input_file->mode == LIVE_MEDIA && audio_input_file->no_loop == 0) {
av_seek_frame(audio_input_file->av_fmt_ctx, audio_input_file->astream_idx, 0, 0);
continue;
}
packet.data = NULL;
packet.size = 0;
#ifndef FF_API_AVFRAME_LAVC
avcodec_get_frame_defaults(audio_input_data->aframe);
#else
av_frame_unref(audio_input_data->aframe);
#endif
avcodec_decode_audio4(codec_ctx, audio_input_data->aframe, &got_frame, &packet);
if (got_frame) {
dc_producer_lock(&audio_input_data->producer, &audio_input_data->circular_buf);
dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf);
audio_data_node = (AudioDataNode*)dc_producer_produce(&audio_input_data->producer, &audio_input_data->circular_buf);
audio_data_node->abuf_size = audio_input_data->aframe->linesize[0];
memcpy(audio_data_node->abuf, audio_input_data->aframe->data[0], audio_data_node->abuf_size);
dc_producer_advance(&audio_input_data->producer, &audio_input_data->circular_buf);
return 0;
}
dc_producer_end_signal(&audio_input_data->producer, &audio_input_data->circular_buf);
dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf);
return -2;
}
else if (ret < 0)
{
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot read audio frame.\n"));
continue;
}
if (packet.stream_index == audio_input_file->astream_idx) {
#ifndef FF_API_AVFRAME_LAVC
avcodec_get_frame_defaults(audio_input_data->aframe);
#else
av_frame_unref(audio_input_data->aframe);
#endif
if (avcodec_decode_audio4(codec_ctx, audio_input_data->aframe, &got_frame, &packet) < 0) {
av_free_packet(&packet);
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while decoding audio.\n"));
dc_producer_end_signal(&audio_input_data->producer, &audio_input_data->circular_buf);
dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf);
return -1;
}
if (audio_input_data->aframe->pts != AV_NOPTS_VALUE)
audio_input_data->next_pts = audio_input_data->aframe->pts;
audio_input_data->next_pts += ((int64_t)AV_TIME_BASE * audio_input_data->aframe->nb_samples) / codec_ctx->sample_rate;
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Decode audio frame pts %d at UTC "LLU"\n", audio_input_data->next_pts, gf_net_get_utc() ));
if (got_frame) {
uint8_t **data;
int data_size;
enum AVSampleFormat sample_format;
Bool resample;
#ifdef DC_AUDIO_RESAMPLER
int num_planes_out=0;
#endif
#ifdef GPAC_USE_LIBAV
int sample_rate = codec_ctx->sample_rate;
int num_channels = codec_ctx->channels;
u64 channel_layout = codec_ctx->channel_layout;
#else
int sample_rate = audio_input_data->aframe->sample_rate;
int num_channels = audio_input_data->aframe->channels;
u64 channel_layout;
if (!audio_input_data->aframe->channel_layout) {
if (audio_input_data->aframe->channels == 2) {
audio_input_data->aframe->channel_layout = AV_CH_LAYOUT_STEREO;
} else if (audio_input_data->aframe->channels == 1) {
audio_input_data->aframe->channel_layout = AV_CH_LAYOUT_MONO;
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Unknown input channel layout for %d channels. Aborting.\n", audio_input_data->aframe->channels));
exit(1);
}
}
channel_layout = audio_input_data->aframe->channel_layout;
#endif
sample_format = (enum AVSampleFormat)audio_input_data->aframe->format;
resample = (sample_rate != DC_AUDIO_SAMPLE_RATE
|| num_channels != DC_AUDIO_NUM_CHANNELS
|| channel_layout != DC_AUDIO_CHANNEL_LAYOUT
|| sample_format != DC_AUDIO_SAMPLE_FORMAT);
if (resample) {
#ifndef DC_AUDIO_RESAMPLER
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Audio resampling is needed at the decoding stage, but not supported by your version of DashCast. Aborting.\n"));
exit(1);
#else
uint8_t **output;
int nb_samp;
if (ensure_resampler(audio_input_file, sample_rate, num_channels, channel_layout, sample_format)) {
return -1;
}
nb_samp = resample_audio(audio_input_file, audio_input_data, codec_ctx, &output, &num_planes_out, num_channels, sample_format);
if (nb_samp<0) {
return -1;
}
av_samples_get_buffer_size(&data_size, DC_AUDIO_NUM_CHANNELS, nb_samp, DC_AUDIO_SAMPLE_FORMAT, 0);
data = output;
#endif
} else {
data = audio_input_data->aframe->extended_data;
data_size = audio_input_data->aframe->linesize[0];
}
assert(!av_sample_fmt_is_planar(DC_AUDIO_SAMPLE_FORMAT));
av_fifo_generic_write(audio_input_file->fifo, data[0], data_size, NULL);
if (audio_input_file->mode == ON_DEMAND || audio_input_file->mode == LIVE_MEDIA) {
dc_producer_lock(&audio_input_data->producer, &audio_input_data->circular_buf);
dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf);
audio_data_node = (AudioDataNode *) dc_producer_produce(&audio_input_data->producer, &audio_input_data->circular_buf);
audio_data_node->channels = DC_AUDIO_NUM_CHANNELS;
audio_data_node->channel_layout = DC_AUDIO_CHANNEL_LAYOUT;
audio_data_node->sample_rate = DC_AUDIO_SAMPLE_RATE;
audio_data_node->format = DC_AUDIO_SAMPLE_FORMAT;
audio_data_node->abuf_size = data_size;
av_fifo_generic_read(audio_input_file->fifo, audio_data_node->abuf, audio_data_node->abuf_size, NULL);
dc_producer_advance(&audio_input_data->producer, &audio_input_data->circular_buf);
} else {
while (av_fifo_size(audio_input_file->fifo) >= LIVE_FRAME_SIZE) {
if (dc_producer_lock(&audio_input_data->producer, &audio_input_data->circular_buf) < 0) {
continue;
}
dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf);
audio_data_node = (AudioDataNode *) dc_producer_produce(&audio_input_data->producer, &audio_input_data->circular_buf);
audio_data_node->abuf_size = LIVE_FRAME_SIZE;
av_fifo_generic_read(audio_input_file->fifo, audio_data_node->abuf, audio_data_node->abuf_size, NULL);
dc_producer_advance(&audio_input_data->producer, &audio_input_data->circular_buf);
}
}
#ifdef DC_AUDIO_RESAMPLER
if (resample) {
int i;
for (i=0; i<num_planes_out; ++i) {
av_free(data[i]);
}
av_free(data);
}
#endif
return 0;
}
}
av_free_packet(&packet);
}
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Unknown error while reading audio frame.\n"));
return -1;
}
void dc_audio_decoder_close(AudioInputFile *audio_input_file)
{
avformat_close_input(&audio_input_file->av_fmt_ctx);
if (audio_input_file->av_pkt_list_mutex) {
gf_mx_p(audio_input_file->av_pkt_list_mutex);
while (gf_list_count(audio_input_file->av_pkt_list)) {
AVPacket *pkt = (AVPacket*)gf_list_last(audio_input_file->av_pkt_list);
av_free_packet(pkt);
gf_list_rem_last(audio_input_file->av_pkt_list);
}
gf_list_del(audio_input_file->av_pkt_list);
gf_mx_v(audio_input_file->av_pkt_list_mutex);
gf_mx_del(audio_input_file->av_pkt_list_mutex);
}
av_fifo_free(audio_input_file->fifo);
#ifdef DC_AUDIO_RESAMPLER
avresample_free(&audio_input_file->aresampler);
#endif
}