FFmpeg音频解码流程详解及简单demo参考

这篇具有很好参考价值的文章主要介绍了FFmpeg音频解码流程详解及简单demo参考。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        本文主要讲解FFmpeg的音频解码具体流程,API使用。最后再以一个非常简单的demo演示将一个mp3格式的音频文件解码为原始数据pcm文件。 本文主要基于FFmpeg音频解码新接口。

一、FFmpeg音频解码API调用流程图      

   API接口简单大体讲解如下:

av_register_all():注册FFmpeg所有编解码器。
 
avformat_open_input():打开音频地址并获取里面的内容(解封装)
 
avformat_find_stream_info():获取内容
 
avcodec_find_decoder():寻找解码器
 
avcodec_alloc_context3():申请解码器相关上下文
 
avcodec_open2():打开解码器
 
av_read_frame():从原始有格式文件中一帧一帧读取出来
 
avcodec_send_packet():解码核心接口新接口,发送一帧音频给解码器。即是AVPacket(存储AAC等音频格式码流数据)。
 
avcodec_receive_frame():解码核心接口新接口,接收解码器解码后的一帧视频,AVFrame(PCM原始数据)。
 

二、音频解码过程API调用流程

1、注册各大组件

        这一步是ffmpeg的任何程序的第一步都是需要先注册ffmpeg相关的各大组件的:

    //注册各大组件
    av_register_all();
    LOGE("注册成功")

2、打开音频文件并获取相关上下文

        在解码之前我们得获取里面的内容,这一步就是打开地址并且获取里面的内容。其中avFormatContext是内容的一个上下文。

        并使用avformat_open_input打开播放源,inputPath为输入的地址,也就是音频文件,然后使用avformat_find_stream_info从获取的内容中寻找相关流。

//打开音频地址并获取里面的内容(解封装)
error = avformat_open_input(&avFormatContext, inputPath, NULL, NULL);
if (error < 0){
	LOGE("打开音频文件失败\n");
	return false;
}
if (avformat_find_stream_info(avFormatContext, NULL) < 0){
	LOGE("获取内容失败")
	return false;
}

3、寻找音频流

        我们在上面已经获取了内容,我们再从中找出相对应的音频流。

//获取音频的编码信息
AVCodecParameters *origin_par = NULL;
int mAudioStreamIdx = -1;
mAudioStreamIdx = av_find_best_stream(avFormatContext, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
if (mAudioStreamIdx < 0) {
	av_log(NULL, AV_LOG_ERROR, "Can't find audio stream in input file\n");
	return false;
}
LOGE("成功找到音频流")

4、获取并打开解码器

        如果要进行解码,那么得有解码器并打开解码器。在这一步中我加了个过滤器的相关配置,这个东西不是非必要的,所以我加了个宏ABSFILTER_ENABLE可以选择是否打开。

    // 寻找解码器 {start
    AVCodec *mAcodec = NULL;
    AVCodecContext *mAvContext = NULL;
    mAcodec = avcodec_find_decoder(origin_par->codec_id);
    mAvContext = avcodec_alloc_context3(mAcodec);
    if (!mAcodec || !mAvContext){
        return false;
    }

#if ABSFILTER_ENABLE
    //过滤器相关配置,这个与音频码流格式相关
    const AVBitStreamFilter * absFilter = NULL;
    AVBSFContext *absCtx = NULL;
    AVCodecParameters *codecpar = NULL;
    absFilter = av_bsf_get_by_name("mp3decomp");
    //过滤器分配内存
    av_bsf_alloc(absFilter, &absCtx);
    //添加解码器属性
    codecpar = avFormatContext->streams[mAudioStreamIdx]->codecpar;
    avcodec_parameters_copy(absCtx->par_in, codecpar);
    absCtx->time_base_in = avFormatContext->streams[mAudioStreamIdx]->time_base;
    //初始化过滤器上下文
    av_bsf_init(absCtx);
#endif

    // 打开解码器
    if (avcodec_open2(mAvContext, mAcodec, NULL) != 0){
        LOGE("打开失败")
        return false;
    }
    LOGE("解码器打开成功")
    // 寻找解码器 end}

5、申请AVPacket和AVFrame以及相关设置

        申请AVPacket和AVFrame,其中AVPacket的作用是:保存解码之前的数据和一些附加信息等;AVFrame的作用是:存放解码过后的数据。

    //申请AVPacket
    AVPacket *packet = (AVPacket *) av_malloc(sizeof(AVPacket));
    av_init_packet(packet);
    //申请AVFrame
    AVFrame *frame = av_frame_alloc();//分配一个AVFrame结构体,AVFrame结构体一般用于存储原始数据,指向解码后的原始帧

6、开始解码

        接下来就可以开始解码,如下是解码的核心段代码,这里同样有上面所说的过滤器的,这个可以先不关心:

{
	// 发送待解码包
	int result = avcodec_send_packet(mAvContext, packet);
	av_packet_unref(packet);
	if (result < 0){
		av_log(NULL, AV_LOG_ERROR, "Error submitting a packet for decoding\n");
		continue;
	}

	// 接收解码数据
	while (result >= 0){
		result = avcodec_receive_frame(mAvContext, frame);
		if (result == AVERROR_EOF)
			break;
		else if (result == AVERROR(EAGAIN)){
			result = 0;
			break;
		}
		else if (result < 0){
			av_log(NULL, AV_LOG_ERROR, "Error decoding frame\n");
			av_frame_unref(frame);
			break;
		}

		av_frame_unref(frame);
	}
}

7、解码并保存为PCM文件

        PCM是音频解码后的原始数据,我们将解码后的数据保存为PCM文件,用于分析。在上一步中解码后的地方加上保存为PCM文件的操作。

        另外这里有用了上面所说的过滤器的东西,我们暂时先不关心。

        完整过程如下:

while(1)
{
	int ret = av_read_frame(avFormatContext, packet);
	if (ret != 0){
		av_strerror(ret,buf,sizeof(buf));
		LOGE("--%s--\n",buf);
		av_packet_unref(packet);
		break;
	}

	if (ret >= 0 && packet->stream_index != mAudioStreamIdx){
		av_packet_unref(packet);
		continue;
	}

#if ABSFILTER_ENABLE
	if (av_bsf_send_packet(absCtx, packet) < 0){
		LOGE("av_bsf_send_packet faile \n");
		av_packet_unref(packet);
		continue;
	}
	if (av_bsf_receive_packet(absCtx, packet) < 0) {
		LOGE("av_bsf_receive_packet faile \n");
		av_packet_unref(packet);
		continue;
	}
#endif

	{
		// 发送待解码包
		int result = avcodec_send_packet(mAvContext, packet);
		av_packet_unref(packet);
		if (result < 0){
			av_log(NULL, AV_LOG_ERROR, "Error submitting a packet for decoding\n");
			continue;
		}

		// 接收解码数据
		while (result >= 0){
			result = avcodec_receive_frame(mAvContext, frame);
			if (result == AVERROR_EOF)
				break;
			else if (result == AVERROR(EAGAIN)){
				result = 0;
				break;
			}
			else if (result < 0){
				av_log(NULL, AV_LOG_ERROR, "Error decoding frame\n");
				av_frame_unref(frame);
				break;
			}

			// 写文件保存音频数据
			data_size = av_get_bytes_per_sample(mAvContext->sample_fmt);
			if (data_size < 0) {
				/* This should not occur, checking just for paranoia */
				LOGE("Failed to calculate data size\n");
				return false;
			}
			for (i = 0; i < frame->nb_samples; i++)
				for (ch = 0; ch < mAvContext->channels; ch++)
					fwrite(frame->data[ch] + data_size*i, 1, data_size, fp_PCM);

			av_frame_unref(frame);
		}
	}

}

8、收尾释放

        最后释放相关资源

    fclose(fp_PCM);
    av_frame_free(&frame);
    avcodec_close(mAvContext);
    avformat_free_context(avFormatContext);
#if ABSFILTER_ENABLE
    av_bsf_free(&absCtx);
    absCtx = NULL;
#endif

        至此,mp3格式的文件就被解码出原始数据并保存为PCM文件。

三、demo运行

         demo中指定了视频源文件是/sdcard/input.mp3,编码后的pcm文件是/sdcard/audioDecodeOut.pcm,如下代码,若要改文件,可以在此处修改:

@Override
public void run() {
	String PATH = Environment.getExternalStorageDirectory().getPath();
	//视频解码
	String input = PATH + File.separator + "input.mp3";
	String output = PATH + File.separator + "audioDecodeOut.pcm";
	decode_audio(input,output);
	Toast.makeText(MainActivity.this, "音频解码完成,请自行从手机中拉取pcm文件", Toast.LENGTH_SHORT).show();
}

        运行后截图如下:

FFmpeg音频解码流程详解及简单demo参考

        点击"START AUDIO DECODE"按钮,开始对音频文件进行解码,界面不会有什么提示,等解码完成后会弹出提示词 "音频解码完成,请自行从手机中拉取pcm文件"

FFmpeg音频解码流程详解及简单demo参考

        我们从运行log中也能看到一些信息,如下:

FFmpeg音频解码流程详解及简单demo参考

        当有--- audio decode finished ---打印出来说明已经解码完成。

        然后我们adb shell进去手机看看解码前后的文件:

FFmpeg音频解码流程详解及简单demo参考

         可以看到解码后的pcm原始数据文件比解码前是大很多的。

四、分析PCM文件

        接下来我们分析下解码后的PCM文件是否正确。

        首先我们需要先知道一下解码前的mp3文件的一些信息,比如声道数,采样率等等。这些我们可以通过FFmpeg的ffprobe来获取,这里我在我的Ubuntu电脑上通过ffmpeg命令行获取一下:

FFmpeg音频解码流程详解及简单demo参考

        红圈圈中的就是几个比较重要的信息,看到是采样率是44100,双声道,fltp格式。

        接下来使用PCM分析工具,我使用的是Audacity:

FFmpeg音频解码流程详解及简单demo参考

         打开工具,并点击导入原始数据:

FFmpeg音频解码流程详解及简单demo参考

        然后选择pcm文件,弹出格式选择的弹窗,采样率就是刚才的44100,声道是双声道也就是2声道,字节序一般是小尾端,编码是fltp,也就是选32-bit float。

FFmpeg音频解码流程详解及简单demo参考

         点击导入后,显示如下,可以看到音频数据的波形图,然后点击右上方的播放按钮播放pcm文件,若音乐听起来正常,与之前的mp3文件一致,则说明解码后的pcm数据正常。

FFmpeg音频解码流程详解及简单demo参考

         完整例子已经放到github上,如下:

https://github.com/weekend-y/FFmpeg_Android_Demo/tree/master/demo6_audioDecode文章来源地址https://www.toymoban.com/news/detail-400109.html

到了这里,关于FFmpeg音频解码流程详解及简单demo参考的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入浅出:FFmpeg 音频解码与处理AVFrame全解析

    FFmpeg 是一个开源的音视频处理软件,它包含了一系列的库和程序,用于处理音频、视频和其他多媒体数据。FFmpeg 的名字来源于 “Fast Forward MPEG”,其中 MPEG 是一种常见的音视频编码标准。 FFmpeg 项目于 2000 年由 Fabrice Bellard 启动,他是 QEMU(一种开源的计算机模拟器和虚拟机

    2024年02月04日
    浏览(112)
  • FFmpeg编解码流程解读--视频解码1

    首先我们知道ffmpeg是一个开源的音视频编解码,封装和解封装的工具。具体的下载方式这里不多赘述(感兴趣百度自行下载源码)。这里主要将编解码。ffmpeg音视频编解码依赖libavcodec。其为我们提供一套架构,其中包含了编解码器。这里主要介绍我们常用的一些API接口去处理

    2023年04月08日
    浏览(44)
  • 基于FFMpeg实现音频mp3/aac/wav解码

    编译环境:Ubuntu16.04 64位 交叉编译工具:arm-himix200-linux-gcc 我这里使用的是ffmpeg-5.1.2.tar.gz,下载地址点击下载地址。 这样,/root/ffmpeg-5.1.2/output下面就是咱们要的程序,bin目录下ffmpeg可以在开发板上运行,include下是需要的头文件,lib下是需要的静态库,share/ffmpeg/examples是一些

    2024年02月11日
    浏览(59)
  • Qt-FFmpeg开发-音频解码为PCM文件(9)

    目录 音视频/FFmpeg #Qt Qt-FFmpeg开发-使用libavcodec API的音频解码示例(MP3转pcm) 1、概述 2、实现效果 3、主要代码 4、完整源代码 更多精彩内容 👉个人内容分类汇总 👈 👉音视频开发 👈 最近研究了一下FFmpeg开发,功能实在是太强大了,网上ffmpeg3、4的文章还是很多的,但是学

    2023年04月08日
    浏览(38)
  • ExoPlayer(AndroidX Media3) 扩展ffmpeg实现音频软解码

    1.Ubuntu 20.04.4 LTS 2.AndroidNDK版本r26C 3.AndroidStudio 2023.1.1(配置好SDK和JDK 17.0.10) 4.ffmpeg6.0源码 5.ExoPlayer源码,AndroidX Media release分支版本 目前官方已废弃Exopler2,代码已经迁移到AndroidX Media,下载完成设置FFMPEG_MODULE_PATH变量 1. git clone https://github.com/androidx/media 2. cd media FFMPEG_MODULE_PATH

    2024年04月12日
    浏览(123)
  • 【FFmpeg+Qt开发】解码流程 详细分析+代码示例

    一、FFMPEG 概述 ​二、FFMPEG 解码 2.1解码流程 2.2解码示例 FFmpeg 是一套可以用来记录、转换,数字音频、视频,并能将其转化为流的开源计算机程序。 FFmpeg 采用 LGPL 或 GPL 许可证;它提供了录制、转换以及流化音视频的完整解决案;它还包含了非常先进的音频 视频编解码库

    2024年01月23日
    浏览(41)
  • 【FFmpeg】ffmpeg 命令行参数 ⑧ ( 使用 ffmpeg 转换封装格式 | 音视频编解码器参数设置 | 视频 帧率 / 码率 / 分辨率 设置 | 音频 码率 / 采样率 设置 )

    音视频 文件 从 采样 - 处理 - 得到原始数据帧队列 - 音视频编码 - 音视频包队列 - 格式封装 的过程如下 : 封装格式 参考 【音视频原理】音视频 “ 采样 - 编码 - 封装 过程 “ 和 “ 解封装 - 解码 - 播放 过程 “ 分析 ( 视频采集处理流程 | 音频采集处理流程 | 音视频文件解封装

    2024年04月17日
    浏览(85)
  • ffmpeg cuda硬件解码后处理使用opengl渲染,全硬件流程

    使用硬件解码后不要transfer到内存,使用cuda转化nv12 - bgr24 转化完毕后cuda里面存了一份bgr24 如果需要opencv gpumat直接使用cuda内存,则可以手动构造gpumat 可以使用gpumat的各种函数 ptr(0)、ptr(1)和ptr(2)分别获取了R、G、B三个通道的数据指针。 使用reinterpret_cast将uchar 指针转换为ucha

    2024年04月12日
    浏览(47)
  • ffmpeg最简单方式支持nvidia硬编解码

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 因为工作内容的需要,之前写过一篇文章关于ffmpeg支持英伟达的硬编解码,那个方法比较适合定制化的ffmpeg编译,如果你仅仅使用ffmpeg进行硬件编解码的话,其实不需要这么麻烦。 ffmpeg定制化编译支持

    2024年02月15日
    浏览(36)
  • 【FFmpeg视频播放器开发】解封装解码流程、常用API和结构体简介(一)

    在正式编写 FFmpeg 播放器前,我们需要先简单了解下所要用到的 FFmpeg 库、播放与解码流程、函数和相关结构体。 库 介绍 avcodec 音视频编解码核心库 avformat 音视频容器格式的封装和解析 avutil 核心工具库 swscal 图像格式转换的模块 swresampel 音频重采样 avfilter 音视频滤镜库 如视

    2023年04月08日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包