libavcodec / ffmpeg在解码时会报告两个通道,但在尝试访问第二个时会报告段错误

时间:2017-12-01 09:47:24

标签: c ffmpeg segmentation-fault libavcodec

我正在尝试使用FFMpeg的libavcodec将音频文件解码为原始pcm数据。到目前为止,我有以下代码,但由于某种原因尝试访问第二个音频通道时会出现段错误。

#include <stdio.h>
#include <string.h>
#include <ao/ao.h>
#include <math.h>

#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>

#define BUF_SIZE 4096


#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096

int decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, uint8_t* out_data, int* index) {

    int i, ch;
    int ret, data_size;

    ret = avcodec_send_packet(dec_ctx, pkt);
    if (ret < 0) {
        fprintf(stderr, "Error submitting packet to decoder\n");
        exit(1);
    }

    while (ret >= 0) {
        ret = avcodec_receive_frame(dec_ctx, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return 0;
        }
        else if (ret < 0) {
            fprintf(stderr, "Error during decoding\n");
            exit(1);
        }

        data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
        if (data_size < 0) {
            fprintf(stderr, "Failed to calculate data size\n");
            exit(1);
        }
        for (i = 0; i < frame->nb_samples; ++i)
            for (ch = 0; ch < dec_ctx->channels; ++ch) {

                //Things go wrong here...
                memcpy(out_data + *index, frame->data[ch] + (data_size*i), data_size);
                *index += data_size;
            }
    }

    return 0;
}

int decode_audio_file(const char* path, uint8_t* out_data, int size) {
    const AVCodec *codec;
    AVCodecContext *c = NULL;
    AVCodecParserContext *parser = NULL;
    int len, ret;
    FILE *f;
    uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
    uint8_t *data;
    size_t data_size;
    AVPacket *pkt;
    AVFrame *decoded_frame = NULL;


    avcodec_register_all();
    pkt = av_packet_alloc();
    codec = avcodec_find_decoder(AV_CODEC_ID_FLAC);
    if (!codec) {
        fprintf(stderr, "Codec not found!\n");
        return -1;
    }

    parser = av_parser_init(codec->id);
    if (!parser) {
        fprintf(stderr, "Parser not found!\n");
        return -1;
    }

    c = avcodec_alloc_context3(codec);
    if (!c) {
        fprintf(stderr, "Could not allocate audio context!\n");
        return -1;
    }

    if(avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }

    f = fopen(path, "rb");
    if(!f) {
        fprintf(stderr, "Could not open %s\n", path);
        exit(1);
    }

    data = inbuf;
    data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);

    int index = 0;  
    while (data_size > 0) {
        if (!decoded_frame) {
            if (!(decoded_frame = av_frame_alloc())) {
                fprintf(stderr, "Could not allocate audio frame\n");
                exit(1);
            }
        }

        ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size, data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
        if (ret < 0) {
            fprintf(stderr, "Error while parsing\n");
            exit(1);
        }
        data += ret;
        data_size -= ret;

        if (pkt->size)
            decode(c, pkt, decoded_frame, out_data, &index);
        if (data_size < AUDIO_REFILL_THRESH) {
            memmove(inbuf, data, data_size);
            data = inbuf;
            len = fread(data + data_size, 1, AUDIO_INBUF_SIZE - data_size, f);
            if (len > 0)
                data_size += len;
        }
    }
    avcodec_free_context(&c);
    av_parser_close(parser);
    av_frame_free(&decoded_frame);
    av_packet_free(&pkt);

    return 0;
}


int main(int argc, char **argv)
{
    int bsize = 1024*1024*60;
    uint8_t* audio_buffer = calloc(bsize, sizeof(uint8_t));
    decode_audio_file("testsong.flac", audio_buffer, bsize);
}

以下是违规行:

memcpy(out_data + *index, frame->data[ch] + (data_size*i), data_size);

如果您访问frame->data[0]就可以了,但如果您尝试访问frame->data[1],则会出现段错误。上下文报告两个通道,文件包含两个通道(尝试使用几个不同的轨道)。 但它变得更加怪异。如果我将违规行切换到memcpy(out_data + *index, frame->data[0] + (data_size*i*2 + ch), data_size); ,则左声道将具有正确的数据,而右声道则为白噪声。 这告诉我(我可能错了)第一个通道实际上包含2个音频交错通道,实际左通道,还有一个白噪声的垃圾通道。 我错了,我忘了ch多个data_size。如果该行是memcpy(out_data + *index, frame->data[0] + (data_size*i*2 + ch*data_size), data_size);,事情似乎按预期工作。这一切似乎仍然非常粗略,但如果有人能够彻底解释这里发生的事情,那就太好了。

我一直在处理ffmpeg文档here中提供的decode_audio示例,尽管稍作修改。

如果我使用vanilla示例并且唯一的更改是将编解码器设置为FLAC,则会发生此ALSO,因此我认为它是库中的错误。在这种情况下,我该如何解决它。

0 个答案:

没有答案