ffmpeg-4.2.2:音频解码流程(MP3解码成pcm)

本文详细介绍使用FFMPEG进行音频解码的过程,包括打开音频流、查找流信息、选择和初始化解码器等关键步骤,并提供源代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于FFMPEG的音频解码器,可以将MP3数据解码成pcm。
主要是记录一下自己学习FFMPEG时总结的音频解码流程。
ffmpeg版本:ffmpeg-4.2.2
libmp3lame-version:3.100

流程图

在这里插入图片描述简单介绍下各个函数的功能:
avformat_open_input():打开输入的音频流
avformat_find_stream_info():查找流的信息,填充AVFormatContext
av_find_best_stream():找到输入流中想要的流,返回流的编号
avcodec_find_decoder():通过解码器ID查找解码器
avcodec_alloc_context3():初始化AVCodecContext
avcodec_open2():打开解码器
av_packet_alloc():初始化AVPacket
av_frame_alloc():初始化AVFrame
av_read_frame():从流中读取一个AVPacket包数据
avcodec_send_packet():向解码器发生一个AVPacket包
av_get_bytes_per_sample():获取一个采样的字节数
avcodec_receive_frame():从解码器中读取一帧音频数据

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libavformat/avformat.h>

static void decode(AVCodecContext *cdc_ctx, AVFrame *frame, AVPacket *pkt, FILE *fp_out)
{
	int ret = 0;
	int data_size = 0;
	int i, ch;

	if ((ret = avcodec_send_packet(cdc_ctx, pkt)) < 0)
	{
		fprintf(stderr, "avcodec_send_packet failed.\n");
		exit(1);
	}

	data_size = av_get_bytes_per_sample(cdc_ctx->sample_fmt);

	while ((ret = avcodec_receive_frame(cdc_ctx, frame)) >= 0)
	{
		printf("Write 1 frame.\n");

		for (i = 0; i < frame->nb_samples; i++)
		{
			for (ch = 0; ch < cdc_ctx->channels; ch++)
			{
				fwrite(frame->data[ch] + data_size * i, 1, data_size, fp_out);
			}
		}
	}

	if ((ret != AVERROR(EAGAIN)) && (ret != AVERROR_EOF))
	{
		fprintf(stderr, "avcodec_receive_packet failed.\n");
		exit(1);
	}
}

void decode_audio(const char *input_file, const char *output_file)
{
	int ret = 0;
	AVCodec *codec = NULL;
	AVCodecContext *cdc_ctx = NULL;
	AVPacket *pkt = NULL;
	AVFrame *frame = NULL;
	FILE *fp_out;
	AVFormatContext *fmt_ctx = NULL;

	if ((ret = avformat_open_input(&fmt_ctx, input_file, NULL, NULL)) < 0)
	{
		fprintf(stderr, "avformat_open_input failed.\n");
		goto ret1;
	}

	if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0)
	{
		fprintf(stderr, "avformat_find_stream_info failed.\n");
		goto ret2;
	}

	if ((ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0)) < 0)
	{
		fprintf(stderr, "av_find_best_stream failed.\n");
		goto ret2;
	}

	if ((codec = avcodec_find_decoder(fmt_ctx->streams[ret]->codecpar->codec_id)) == NULL)
	{
		fprintf(stderr, "avcodec_find_decoder failed.\n");
		goto ret2;
	}

	if ((cdc_ctx = avcodec_alloc_context3(codec)) == NULL)
	{
		fprintf(stderr, "avcodec_alloc_context3 failed.\n");
		goto ret2;
	}

	if ((ret = avcodec_open2(cdc_ctx, codec, NULL)) < 0)
	{
		fprintf(stderr, "avcodec_open2 failed.\n");
		goto ret3;
	}

	if ((pkt = av_packet_alloc()) == NULL)
	{
		fprintf(stderr, "av_packet_alloc failed.\n");
		goto ret4;
	}

	if ((frame = av_frame_alloc()) == NULL)
	{
		fprintf(stderr, "av_frame_alloc failed.\n");
		goto ret5;
	}

	if ((fp_out = fopen(output_file, "wb")) == NULL)
	{
		fprintf(stderr, "fopen %s failed.\n", output_file);
		goto ret6;
	}

	while ((ret = av_read_frame(fmt_ctx, pkt)) == 0)
	{
		if (pkt->size > 0)
			decode(cdc_ctx, frame, pkt, fp_out);
	}

	decode(cdc_ctx, frame, NULL, fp_out);


	fclose(fp_out);
	av_frame_free(&frame);
	av_packet_free(&pkt);
	avcodec_close(cdc_ctx);
	avcodec_free_context(&cdc_ctx);
	avformat_close_input(&fmt_ctx);
	return;
ret6:
	av_frame_free(&frame);
ret5:
	av_packet_free(&pkt);
ret4:
	avcodec_close(cdc_ctx);
ret3:
	avcodec_free_context(&cdc_ctx);
ret2:
	avformat_close_input(&fmt_ctx);
ret1:
	exit(1);
}

int main(int argc, const char *argv[])
{
	if (argc < 3)
	{
		fprintf(stderr, "Uage:<input file> <output file>\n");
		exit(0);
	}

	decode_audio(argv[1], argv[2]);
	
	return 0;
}

注:音频解码后,数据在AVFrame结构体中,如果采样格式是fltp,则左通道在AVFrame->data[0]中,右通道在AVFrame->data[1]中;采样格式是S16P,则左右通道交错保存在AVFrame->data[0]中


下载

项目主页

Github:https://github.com/newbie-plan/decode_audio

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值