我正在尝试使用LibAV库将流音频文件(通过AVIOContext
)转换为签名的16位PCM。但是,我很难阅读自动生成的文档和示例以执行我要尝试执行的操作。
以下是我尝试对extern函数read_packet
提供的任何流音频文件进行解码并将结果PCM数据馈送到extern函数process_data
中的情况。
#define BUFFER_SIZE 4096
extern int read_packet(void *, uint8_t *, int);
extern void process_data(uint8_t *, int);
int perform_decoding() {
AVFormatContext *ctx = avformat_alloc_context();
uint8_t *buffer = av_malloc(BUFFER_SIZE);
AVIOContext *aioctx = avio_alloc_context(
buffer, // Buffer
BUFFER_SIZE, // Buffer size
0, // write_flag
NULL, // opaque
read_packet, // read_packet
NULL, // write_packet
NULL // seek
);
ctx->pb = aioctx;
avformat_open_input(&ctx, "stream", NULL, NULL);
if (avformat_find_stream_info(ctx, NULL) < 0) { return -1; }
int audio_stream_index = -1;
AVStream *stream = NULL;
for (int i = 0; i < ctx->nb_streams; i++) {
stream = ctx->streams[i];
if (stream->codec.codec_type == AVMEDIA_TYPE_AUDIO) {
audio_stream_index = i;
break;
}
}
if (audio_stream_index == -1) { return -2; }
AVCodecContext *cctx = stream->codec;
AVCodecParameters *params = stream->codecpar;
/// At this point we have
/// (1) The codec context
/// (2) The codec parameters for the incoming song (which can change per incoming file stream)
/// At this point I do not have the AVCodec* which I need to decode frames
/// And `cctx->codec` == NULL at this point (this would have been my AVCodec*)
/// ---------- Confusion starts below this line ----------
/// To the best of my knowledge, this is the best way to get one
/// I am not sure if one already exists that I can use.
AVCodec *codec = avcodec_find_decoder(cctx->codec_id);
if (codec == NULL) { return -3; } // Codec not found
/// These three commented out lines are lines I have always found when `avcodec_find_decoder` is performed
// cctx = avcodec_alloc_context3(codec); // Do I need?
// avcodec_alloc_context3(cctx, codec, NULL); // Do I need?
// avcodec_open2(cctx, codec, NULL) { return -3; } // Do I need?
/// ---------- Decoder section ----------
SwrContext *swr = swr_alloc_set_opts(
NULL, // Allocating a new context
params->channel_layout, // Input channel layout
params->format, // Input format
params->sample_rate, // Input sample rate
STEREO, // Output channel layout
AV_SAMPLE_FMT_S16, // Output format
48000, // Output sample rate
0, // Log offset
NULL // Log ctx
);
if (swr == NULL) { return -4; }
AVPacket *packet = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
while (av_read_frame(ctx, packet) >= 0) { // Fetch a packet
avcodec_send_packet(cctx, packet); // Toss the packet into the codec context
avcodec_receive_frame(cctx, frame); // Pull out a frame
/// Send the data to an external function that exects the decoded track in signed 16bit PCM format (bytes)
/// where the first argument is the pointer to the buffer and the second argument is the size
process_data(frame->data[0], frame->linesize[0]);
/// Do I need to reallocate these bellow? Or can I just reuse the packet & frame objects?
// packet = av_packet_alloc();
// frame = av_frame_alloc();
}
return 0;
}
如上所述,下面的应用程序将提供没有数据的帧(大小为0)。当我在不确定的部分中发表评论时,我能得到的最多的是第一个提供完整的null帧的帧,然后在随后的每个帧中完全废弃数据。
所以,我认为鉴于结果,我将编解码器初始化错误。一切都在混乱的注释行中签出。采样率,格式和通道均从参数中检出。运行av_dump_format(ctx, 0, "stream", 0)
甚至可以提供正确的轨道调试信息,包括轨道本身的长度。
答案 0 :(得分:0)
When calling swr_alloc_set_opts
, the input options and output options were reversed via arguments -- which does not make sense. Swapping these fixed the issue. Output now provides PCM.