我正在尝试使用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,因此我认为它是库中的错误。在这种情况下,我该如何解决它。