[Libav-user] Exoplayer with Ffrmpeg deocder and avfilters dont work with some audioformats

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[Libav-user] Exoplayer with Ffrmpeg deocder and avfilters dont work with some audioformats

Aleksej Otjan

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.


_______________________________________________
Libav-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/libav-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".