[Libav-user] Exoplayer with Ffrmpeg deocder and avfilters dont work with some audioformats
Aleksej Otjan
rokney.slevin at gmail.com
Thu Jun 25 13:35:28 EEST 2020
Hi. Have a code to play audio with exoplayer and ffmpeg decoder. It works.
Then I was needed to add equalizer functionality. I did it with ffmpeg
avfilters. But now, it crash at some audio formats(if dont use avfilters it
works with this formats).
Decode func:
int decodePacket(AVCodecContext *context, AVPacket *packet,
uint8_t *outputBuffer, int outputSize) {
int result = 0;
// Queue input data.
result = avcodec_send_packet(context, packet);
if (result) {
logError("avcodec_send_packet", result);
return result == AVERROR_INVALIDDATA ? DECODER_ERROR_INVALID_DATA
: DECODER_ERROR_OTHER;
}
// Dequeue output data until it runs out.
int outSize = 0;
if (EQUALIZER != nullptr) {
LOGE("INIT FILTER GRAPH");
init_filter_graph(context, EQUALIZER);
}
while (true) {
AVFrame *frame = av_frame_alloc();
if (!frame) {
LOGE("Failed to allocate output frame.");
return -1;
}
result = avcodec_receive_frame(context, frame);
if (result) {
av_frame_free(&frame);
if (result == AVERROR(EAGAIN)) {
break;
}
logError("avcodec_receive_frame", result);
return result;
}
// Resample output.
AVSampleFormat sampleFormat = context->sample_fmt;
int channelCount = context->channels;
int channelLayout = context->channel_layout;
int sampleRate = context->sample_rate;
int sampleCount = frame->nb_samples;
int dataSize = av_samples_get_buffer_size(NULL, channelCount,
sampleCount,
sampleFormat, 1);
SwrContext *resampleContext;
if (context->opaque) {
resampleContext = (SwrContext *) context->opaque;
} else {
resampleContext = swr_alloc();
av_opt_set_int(resampleContext, "in_channel_layout",
channelLayout, 0);
av_opt_set_int(resampleContext, "out_channel_layout",
channelLayout, 0);
av_opt_set_int(resampleContext, "in_sample_rate", sampleRate, 0);
av_opt_set_int(resampleContext, "out_sample_rate", sampleRate, 0);
av_opt_set_int(resampleContext, "in_sample_fmt", sampleFormat, 0);
// The output format is always the requested format.
av_opt_set_int(resampleContext, "out_sample_fmt",
context->request_sample_fmt, 0);
result = swr_init(resampleContext);
if (result < 0) {
logError("swr_init", result);
av_frame_free(&frame);
return -1;
}
context->opaque = resampleContext;
}
int inSampleSize = av_get_bytes_per_sample(sampleFormat);
int outSampleSize =
av_get_bytes_per_sample(context->request_sample_fmt);
int outSamples = swr_get_out_samples(resampleContext, sampleCount);
int bufferOutSize = outSampleSize * channelCount * outSamples;
if (outSize + bufferOutSize > outputSize) {
LOGE("Output buffer size (%d) too small for output data (%d).",
outputSize, outSize + bufferOutSize);
av_frame_free(&frame);
return -1;
}
if (EQUALIZER != nullptr && graph != nullptr) {
result = av_buffersrc_add_frame_flags(src,
frame,AV_BUFFERSRC_FLAG_KEEP_REF);
if (result < 0) {
av_frame_unref(frame);
LOGE("Error submitting the frame to the filtergraph:");
return -1;
}
// Get all the filtered output that is available.
result = av_buffersink_get_frame(sink, frame);
LOGE("ERROR SWR %s", av_err2str(result));
if (result == AVERROR(EAGAIN) || result == AVERROR_EOF) {
av_frame_unref(frame);
break;
}
if (result < 0) {
av_frame_unref(frame);
return -1;
}
result = swr_convert(resampleContext, &outputBuffer,
bufferOutSize,
(const uint8_t **) frame->data,
frame->nb_samples);
}else{
result = swr_convert(resampleContext, &outputBuffer, bufferOutSize,
(const uint8_t **) frame->data,
frame->nb_samples);
}
av_frame_free(&frame);
if (result < 0) {
logError("swr_convert", result);
return result;
}
int available = swr_get_out_samples(resampleContext, 0);
if (available != 0) {
LOGE("Expected no samples remaining after resampling, but
found %d.",
available);
return -1;
}
outputBuffer += bufferOutSize;
outSize += bufferOutSize;
}
avfilter_graph_free(&graph);
return outSize;}
Init graph func:
int init_filter_graph(AVCodecContext *dec_ctx, const char *eq) {
char args[512];
int ret = 0;
graph = avfilter_graph_alloc();
const AVFilter *abuffersrc = avfilter_get_by_name("abuffer");
const AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
AVFilterInOut *outputs = avfilter_inout_alloc();
AVFilterInOut *inputs = avfilter_inout_alloc();
static const enum AVSampleFormat out_sample_fmts[] =
{dec_ctx->request_sample_fmt,
static_cast<const AVSampleFormat>(-1)};
static const int64_t out_channel_layouts[] =
{static_cast<int64_t>(dec_ctx->channel_layout),
-1};
static const int out_sample_rates[] = {dec_ctx->sample_rate, -1};
const AVFilterLink *outlink;
AVRational time_base = dec_ctx->time_base;
if (!outputs || !inputs || !graph) {
ret = AVERROR(ENOMEM);
goto end;
}
/* buffer audio source: the decoded frames from the decoder will
be inserted here. */
if (!dec_ctx->channel_layout)
dec_ctx->channel_layout =
av_get_default_channel_layout(dec_ctx->channels);
snprintf(args, sizeof(args),
"time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"
PRIx64,
1, dec_ctx->sample_rate, dec_ctx->sample_rate,
av_get_sample_fmt_name(dec_ctx->sample_fmt),
dec_ctx->channel_layout);
ret = avfilter_graph_create_filter(&src, abuffersrc, "in",
args, NULL, graph);
if (ret < 0) {
LOGE("Cannot create audio buffer source\n");
goto end;
}
/* buffer audio sink: to terminate the filter chain. */
ret = avfilter_graph_create_filter(&sink, abuffersink, "out",
NULL, NULL, graph);
if (ret < 0) {
LOGE("Cannot create audio buffer sink\n");
goto end;
}
ret = av_opt_set_int_list(sink, "sample_fmts", out_sample_fmts, -1,
AV_OPT_SEARCH_CHILDREN);
if (ret < 0) {
LOGE("Cannot set output sample format\n");
goto end;
}
ret = av_opt_set_int_list(sink, "channel_layouts", out_channel_layouts, -1,
AV_OPT_SEARCH_CHILDREN);
if (ret < 0) {
LOGE("Cannot set output channel layout\n");
goto end;
}
ret = av_opt_set_int_list(sink, "sample_rates", out_sample_rates, -1,
AV_OPT_SEARCH_CHILDREN);
if (ret < 0) {
LOGE("Cannot set output sample rate\n");
goto end;
}
/*
* Set the endpoints for the filter graph. The graph will
* be linked to the graph described by filters_descr.
*/
/*
* The buffer source output must be connected to the input pad of
* the first filter described by filters_descr; since the first
* filter input label is not specified, it is set to "in" by
* default.
*/
outputs->name = av_strdup("in");
outputs->filter_ctx = src;
outputs->pad_idx = 0;
outputs->next = NULL;
/*
* The buffer sink input must be connected to the output pad of
* the last filter described by filters_descr; since the last
* filter output label is not specified, it is set to "out" by
* default.
*/
inputs->name = av_strdup("out");
inputs->filter_ctx = sink;
inputs->pad_idx = 0;
inputs->next = NULL;
if ((ret = avfilter_graph_parse_ptr(graph, eq,
&inputs, &outputs, NULL)) < 0) {
goto end;
}
if ((ret = avfilter_graph_config(graph, NULL)) < 0)
goto end;
/* Print summary of the sink buffer
* Note: args buffer is reused to store channel layout string */
outlink = sink->inputs[0];
av_get_channel_layout_string(args, sizeof(args), -1,
outlink->channel_layout);
LOGE("Output: srate:%dHz chlayout:%s\n",
(int) outlink->sample_rate,
args);
end:
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
return ret;}
Crash when try to play aac, alac audio at this line :
result = swr_convert(resampleContext, &outputBuffer,
bufferOutSize,(const uint8_t **) frame->data, frame->nb_samples);
with
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
but work fine when play mp3, flac. What is wrong? Thx for help.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://ffmpeg.org/pipermail/libav-user/attachments/20200625/b334eb08/attachment.html>
More information about the Libav-user
mailing list