当前位置: 首页 > news >正文

FFmpeg音视频开发知识点(二)

系列文章目录

FFmpeg音视频开发知识点(一)


文章目录

  • 系列文章目录
  • 前言
  • 一、AAC音频编码
    • 1. ffmpeg编译第三方的libfdk_aac
    • 2. S16重采样FLTP
  • 二、AAC音频解码
  • 总结


前言

该篇讲解一下,音频编解码中的难点,以及开发过程中遇到问题,有不对的地方,欢迎大佬指正


一、AAC音频编码

在开发音频编解码AAC,我使用QAudioInput进行采样,但是采样格式只有S16(有符号16位)最接近AAC的采样,我看了下安卓采样的样本长度也是16(PS:需要和安卓终端通话),于是查找并打开编码器

	AVCodec* pCodec = avcodec_find_encoder(AV_CODEC_ID_AAC);if (pCodec == nullptr){//...省略return;}AVCodecContext* pCodecCtx = avcodec_alloc_context3(pCodec);if(pCodecCtx == NULL){//...省略return;}pCodecCtx->codec_id = pCodec->id;pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;//...省略int iRet = avcodec_open2(pCodecCtx, pCodec, NULL);if (iRet < 0){//...省略return;}

但是会报错(忘了是查找还是打开编码器报错了🤣),后面一查,ffmpeg本身自带的aac并不支持AV_SAMPLE_FMT_S16的,有两种方式可以编码S16音频采样

1. ffmpeg编译第三方的libfdk_aac

编译libfdk_aac可以参考我这篇文章:Linux部分开源库编译,附上我的ffmepg编译的configure配置命令,具体如下:

sudo ./configure \
--prefix=/home/lzy/Project/new_project/libH323Stack_src_1.2.0/bin4 \
--extra-cflags="-I/home/lzy/Project/bin/include -Wall -fPIC" \	#第三方库的头文件路径
--extra-ldflags="-L/home/lzy/Project/bin/lib -ldl" \			#第三方库的所在路径
--disable-static \
--enable-shared \
--disable-debug \
--disable-doc \
--disable-ffplay \
--disable-ffprobe \
--disable-symver \
--enable-small \
--enable-gpl \
--enable-nonfree \
--enable-libfdk-aac \
--enable-libx264 \
--enable-libx265 \
--enable-openssl \
--enable-hardcoded-tables \
--enable-avresample \
--enable-decoder=h264 \
--enable-decoder=hevc \
--enable-decoder=mjpeg \
--enable-decoder=aac \
--enable-encoder=libx264 \
--enable-encoder=libx265 \
--enable-encoder=libfdk_aac \
--enable-encoder=mjpeg \
--enable-encoder=pcm_s16le \
--enable-decoder=pcm_s16le \
--enable-protocol=file \
--enable-protocol=rtp \
--enable-protocol=tcp \
--enable-protocol=udp \
--enable-demuxer=mp3 \
--enable-demuxer=wav \
--enable-demuxer=mpegts \
--enable-demuxer=mov \
--enable-demuxer=flv \
--enable-bsf=h264_mp4toannexb \
--enable-bsf=hevc_mp4toannexb \
--enable-bsf=aac_adtstoasc

编译之后,就可以打开AV_SAMPLE_FMT_S16采样格式的编码器了,具体如下:

    AVCodec* pCodec = avcodec_find_encoder_by_name("libfdk_aac");if (pCodec == nullptr){//...省略return;}//...省略

最后,附上一个比较关键的部分,就是将S16的音频采样数据,赋值给AVFrame,之前参数不对也折腾了很久

	// 创建输入帧AVFrame* pS16AudioFrame = av_frame_alloc();if (pS16AudioFrame == nullptr){//...省略return;}// frame缓冲区中的样本帧数量(由ctx->frame_size决定)pS16AudioFrame->nb_samples = pCodecCtx->frame_size;// 音频采样格式pS16AudioFrame->format = pCodecCtx->sample_fmt;// 声道布局pS16AudioFrame->channel_layout = pCodecCtx->channel_layout;pS16AudioFrame->channels = pCodecCtx->channels;// 采样率pS16AudioFrame->sample_rate = pCodecCtx->sample_rate;// 利用nb_samples、format、channel_layout创建frame的数据缓冲区int iRet = av_frame_get_buffer(pS16AudioFrame, 0);if (iRet < 0){//...省略return;}//...省略// 将读取到的PCM数据填充到frame去,但要注意格式的匹配, 是planar还是packed都要区分清楚iRet = av_samples_fill_arrays(pS16AudioFrame->data, pS16AudioFrame->linesize,stFrame.pFrame, pS16AudioFrame->channels,pCodecCtx->frame_size, pCodecCtx->sample_fmt, 0);if (iRet < 0){//...省略return;}

2. S16重采样FLTP

	// 创建音频转换上下文SwrContext* pSwrCtx = swr_alloc_set_opts(NULL, pCodecCtx->channel_layout, AV_SAMPLE_FMT_FLTP, pCodecCtx->sample_rate,pCodecCtx->channel_layout, AV_SAMPLE_FMT_S16, pCodecCtx->sample_rate, 0, NULL);if (pSwrCtx == nullptr){printf("无法分配音频转换上下文\n");return;}// 初始化音频转换上下文if (swr_init(pSwrCtx) < 0){printf("音频转换上下文初始化失败\n");return;}// 进行音频转换AVFrame* pFltpAudioFrame = av_frame_alloc();if (pCodec == nullptr){//...省略return;}pFltpAudioFrame->format = pCodecCtx->sample_fmt;pFltpAudioFrame->channel_layout = AV_CH_LAYOUT_STEREO;pFltpAudioFrame->sample_rate = pCodecCtx->sample_rate;pFltpAudioFrame->nb_samples = 1024; //一帧音频一通道的采样数量int iRet = av_frame_get_buffer(pFltpAudioFrame, 0); //给pcm分配存储空间if (iRet < 0){//...省略return;}//...省略PCM复制给AVFrame// 执行音频转换iRet = swr_convert_frame(pSwrCtx, pFltpAudioFrame, pS16AudioFrame);if(iRet < 0){//...省略return;}

二、AAC音频解码

音频编码完成后,发送给安卓端,能够正常播放音频;现在开始解码安卓发过来的AAC音频,原本以为很快就能解决,结果发现调用avcodec_receive_frame函数一直返回-11,也就是说没有能获取到解码后的完整的一帧数据,我打印了一下返回值,发现一次都没成功;由于我发送S16的编码数据给安卓能够正常播放,且安卓采样也是S16(但是走的硬编解码);让我一度认为,安卓发过来的音频编码数据的采样格式是S16,直到我一次偶然的尝试,将

AVCodec* pCodec = avcodec_find_decoder_by_name("libfdk_aac");
// ...省略
AVCodecContext* pCodecCtx = avcodec_alloc_context3(pCodec);
// ...省略
pCodecCtx->request_sample_fmt = AV_SAMPLE_FMT_S16;

改为

AVCodec* pCodec = avcodec_find_decoder(AV_CODEC_ID_AAC);
// ...省略
AVCodecContext* pCodecCtx = avcodec_alloc_context3(pCodec);
// ...省略
pCodecCtx->request_sample_fmt = AV_SAMPLE_FMT_FLTP;

结果发现解码成功了,…,附上FLTP重采样S16代码,其实和S16重采样FLTP差不多

// 创建音频转换上下文SwrContext* pSwrCtx = swr_alloc_set_opts(NULL, pCodecCtx->channel_layout, AV_SAMPLE_FMT_S16, pCodecCtx->sample_rate,pCodecCtx->channel_layout, AV_SAMPLE_FMT_FLTP, pCodecCtx->sample_rate, 0, NULL);if (pSwrCtx == nullptr){printf("无法分配音频转换上下文\n");return;}// 初始化音频转换上下文if (swr_init(pSwrCtx) < 0){printf("音频转换上下文初始化失败\n");return;}// 进行音频转换AVFrame* pS16AudioFrame = av_frame_alloc();if (NULL == pS16AudioFrame ){printf("av_frame_alloc failed!\n");return ;}pS16AudioFrame->format = AV_SAMPLE_FMT_S16;pS16AudioFrame->channel_layout = AV_CH_LAYOUT_STEREO;pS16AudioFrame->sample_rate = pCodecCtx->sample_rate;pS16AudioFrame->nb_samples = 1024; //一帧音频一通道的采样数量iRet = av_frame_get_buffer(pS16AudioFrame, 0); //给pcm分配存储空间if(iRet < 0){//...省略return;}// 分配一帧空间,存放解码后的一帧数据AVFrame* pAudioFrame = av_frame_alloc();//...省略// 执行音频转换iRet = swr_convert_frame(pSwrCtx, pS16AudioFrame, pAudioFrame);//...省略

总结

音频编解码相对来说比较简单,就AAC稍微复杂一点,如果编解码失败,大概分两种情况:
1)编解码上下文参数不对
2)传给编解码器的数据不对
另外,每个函数的返回值也要判断一下,这样出现异常,也能迅速定位所在位置

相关文章:

FFmpeg音视频开发知识点(二)

系列文章目录 FFmpeg音视频开发知识点&#xff08;一&#xff09; 文章目录 系列文章目录前言一、AAC音频编码1. ffmpeg编译第三方的libfdk_aac2. S16重采样FLTP 二、AAC音频解码总结 前言 该篇讲解一下&#xff0c;音频编解码中的难点&#xff0c;以及开发过程中遇到问题&am…...

【Java可执行命令】(十)JAR文件签名工具 jarsigner:通过数字签名及验证保证代码信任与安全,深入解析 Java的 jarsigner命令~

Java可执行命令之jarsigner 1️⃣ 概念2️⃣ 优势和缺点3️⃣ 使用3.1 语法3.1.1 可选参数&#xff1a;jarsigner -keystore < url>3.1.2 可选参数&#xff1a;jarsigner -storepass <口令>3.1.3 可选参数&#xff1a;jarsigner -keypass <口令>3.1.4 可选参…...

c#调用c++ dll,Release版本内存访问错误

最近遇到个比较经典的案例&#xff0c;在c#中调用yara进行文件检测&#xff0c;yara是c编写的一个非常强大库&#xff0c;github有个大佬用c#对其进行了封装&#xff0c;使其能在跨平台下&#xff0c;只需编译yara的so或dll就能直接跑。但总是在Release版本下时不时就崩溃&…...

内网安全:Cobalt Strike 与 MSF 联动( 会话 相互转移 )

内网安全&#xff1a;Cobalt Strike 与 MSF 联动&#xff08; 会话 相互转移 &#xff09; 在渗透中&#xff0c;有时候 Cobalt Strike 会话可能会受限制&#xff0c;所以我们需要把 Cobalt Strike 会话转移到 MSF 上进行后面的渗透。也有的时候会话在 MSF 上&#xff0c;但是…...

性能测试讲解超详细Jmeter

目录 什么是性能 性能测试的目的 功能测试和性能测试 基准测试 负载测试 稳定性测试 压力测试 并发测试 总结 性能测试指标 响应时间 并发数 吞吐量 点击数 错误率 资源使用率 总结 性能测试流程 性能测试需求分析 性能测试计划和方案 ​编辑性能测试用例​编辑 性…...

微服务 – Spring Cloud – Nacos 配置中心

微服务 – Spring Cloud – Nacos 配置中心 文章目录 微服务 – Spring Cloud – Nacos 配置中心打开nacos面板新建配置引入依赖配置文件启动类业务类打开nacos面板新建配置 Data ID: nacos-config-client-dev.yaml Group: DEV-CLOUD2023 config:info: config info lalalal …...

超细,设计一个“完美“的测试用例,用户登录模块实例...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 好的测试用例一定…...

【C#】文件拖拽,获取文件路径

系列文章 【C#】编号生成器&#xff08;定义单号规则、固定字符、流水号、业务单号&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129129787 【C#】日期范围生成器&#xff08;开始日期、结束日期&#xff09; 本文链接&#xff1a;h…...

SAP PI/PO初步了解 2023.07.03

SAP PI/PO 是SAP 提供的一种集成中间件解决方案&#xff0c;用于在组织内部或不同组织之间实现系统的无缝通信和数据交换。它使企业能够以统一高效的方式集成各种应用和系统&#xff0c;无论这些系统的技术平台或数据格式如何。 以下是关于SAP PI/PO的简要概述&#xff1a; 1…...

Java中生产者消费者模型

在Java中&#xff0c;生产者消费者模型是一种常见的多线程编程模型&#xff0c;用于解决生产者和消费者之间的数据交互问题。 简介 生产者&#xff08;Producer&#xff09;负责生成数据&#xff0c;并将数据放入共享的缓冲区&#xff08;队列&#xff09;中。消费者&#xf…...

测试Hyperledger Fabric环境

首先进入fabric-samples目录中的first-networked 子目录 cd fabric-samples/first-network 在first-network目录下有一个自动化脚本byfn.sh,可以使用-help参数查看相应的可 用命令&#xff0c;在命令提示符中输入如下命令&#xff1a; ./byfn.sh --help命令执行成功后&#…...

ClickHouse查询sql长度超超过最大限制

ClickHouse查询sql长度超超过最大限制 Max query size exceeded ClickHouse exception, message: Code: 62. DB::Exception: Syntax error: failed at position 262102 (‘fwm00ud6a3ynu0kaxr.ya0eyemkbzdvrxkhwgchccll’) (line 10406, col 17): fwm00ud6a3ynu0kaxr.ya0eyemk…...

【Axure教程】拖动调整行高列宽的表格

表格是在系统软件中非常常用的工具。表格通常由行和列组成&#xff0c;用于以结构化的方式显示和组织数据。它们在各种场景中都有广泛的应用&#xff0c;包括数据分析、数据录入、报表生成、项目管理和数据可视化等领域。 今天作者就教大家如何在Axure里制作一个能通过鼠标拖动…...

中间件-netty(1)

netty 前言篇 文章目录 一、IO基础篇1.概念1.1 阻塞(Block)和非阻塞(Non-Block)1.2 同步(Synchronization)和异步(Asynchronous)1.3 BIO 与 NIO 对比1.3.1 面向流与面向缓冲1.3.2 阻塞与非阻塞1.3.3 选择器的问世 2.NIO 和 BIO 如何影响应用程序的设计2.1 API调用2.2 数据处理2…...

【方法】想把PDF文档转换成PPT,如何操作?

很多小伙伴在工作中&#xff0c;会使用PDF或者PPT来展示内容。那如果需要把PDF转换成PPT&#xff0c;要如何操作呢&#xff1f; 我们知道&#xff0c;PPT转换成PDF很容易操作&#xff0c;只需通过PPT的【导出】选项&#xff0c;就可以直接转换成PDF&#xff1b;还可以通过“另…...

Linux--设置目录或文件的默认权限:umask权限掩码

目录起始权限是从777&#xff0c;普通文件起始权限从666 为何我们创建一个目录或文件&#xff0c;默认权限是你所看到的样子&#xff1f; 因为凡是在umask中出现的权限&#xff0c;都不应该在最终权限中出现&#xff01; 最终权限起始权限&&#xff08;~umask&#xff09…...

C++实现websocket单server单client全双工通信(基于boost!!!)

自身环境&#xff1a;ubuntu18.04gcc7.5.0boost1.7,3 环境配置 gcc或者g一般都有&#xff0c;这里主要介绍一下boost的配置方法   执行如下代码&#xff1a; wget https://boostorg.jfrog.io/artifactory/main/release/1.73.0/source/boost_1_73_0.tar.bz2 --no-check-cert…...

好用的网址5

搜番神器&#xff1a;https://trace.moe/ Online converter&#xff1a;Online converter - convert video, images, audio and documents for free 格式转换 GIF Explode&#xff1a;https://gif-explode.com/ SongDonkey&#xff1a;SongDonkey - AI Online Audio Split…...

做项目去实习到底做的什么?

300万字&#xff01;全网最全大数据学习面试社区等你来&#xff01; 今天是手机编辑的文章&#xff0c;说说做项目/实习这回事。 我之前发过一些视频&#xff0c;讲校招四要素的&#xff0c;其中一个很重要的部分就是实习。 对社招同学来说&#xff0c;就简单了&#xff0c;面试…...

VSC++: 验证身份证

缘由https://ask.csdn.net/questions/1082358 void 验证身份证() {//缘由https://ask.csdn.net/questions/1082358int 权重[] { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 }, 个 0, j 0, a 0, he 0;char M[] "10X98765432", 身份号[100][20]{};//…...

机器学习-方差和偏差理论

机器学习-方差和偏差理论 关于机器学习方差和偏差的内容其实很重要&#xff0c;这个方差和偏差可以帮助我们去分析&#xff0c;模型的泛化能力和过拟合的程度。 下面我们先给存储方差和偏差的公式&#xff1a; 注意&#xff0c;下式当中&#xff0c; f ( x ; D ) 表示在数据集…...

力扣 669. 修剪二叉搜索树

题目来源&#xff1a;https://leetcode.cn/problems/trim-a-binary-search-tree/description/ C题解1&#xff1a;递归法。当前节点为空时返回空&#xff0c;不为空时对其值进行分类讨论。以low为例&#xff0c;当前节点值等于low时&#xff0c;意味着其左子树都要丢弃&#xf…...

ChatGPT在多轮对话中的表现如何?

ChatGPT是一个非常强大的自然语言处理模型&#xff0c;它可以生成高质量的自然语言文本&#xff0c;并且在多轮对话中也有很好的表现。以下是关于ChatGPT在多轮对话中表现的详细介绍&#xff1a; 上下文感知 ChatGPT可以通过上下文感知来理解当前对话的语境和主题。在多轮对话…...

C++ 虚函数 (virtual function) 介绍

文章目录 1. 什么是虚函数2. 虚函数与非虚函数的区别3. 派生类中的虚函数4. 构造/析构函数可以是虚函数吗&#xff1f;5. 纯虚函数5.1 纯虚函数的定义5.1 纯虚函数的特定 1. 什么是虚函数 C 对象有三大特性&#xff1a;继承、封装、多态&#xff1b;虚函数就是实现多态的一种方…...

写给小白的ChatGPT和AI原理

前言 随着ChatGPT等生成式AI的大火&#xff0c;很多开发者都对AI感兴趣。笔者是一名应用层的开发工程师&#xff0c;想必很多类似的开发者都对AI这块不太了解&#xff0c;故而从自己的理解&#xff0c;写一篇給小白的AI入门文章&#xff0c;希望可以帮助到大家。 这是GPT对本…...

多元回归预测 | Matlab基于麻雀算法(SSA)优化混合核极限学习机HKELM回归预测, SSA-HKELM数据回归预测,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab基于麻雀算法(SSA)优化混合核极限学习机HKELM回归预测, SSA-HKELM数据回归预测,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 …...

High Performance Visual Tracking with Siamese Region Proposal Network(SiamRPN)

High Performance Visual Tracking with Siamese Region Proposal Network&#xff08;SiamRPN&#xff0c;CVPR2018&#xff09; 主要贡献&#xff1a; 提出了SiamRPN跟踪器&#xff0c;首次将端到端的离线训练方式&#xff0c;应用到了大尺度的图像跟踪任务上在在线跟踪过程…...

【Vue3 生态】VueRouter 路由核心知识点

1. 动态路由 1.1 动态路由匹配 路由分为静态路由和动态路由。上面讲过的类似 ‘/login’ 这样写死的就是静态路由。 动态路由通过在路径中使用一个动态字段&#xff08;简称&#xff1a;路径参数&#xff09;&#xff0c;来将不同的信息映射到同一个组件中。 如&#xff1a…...

SpringCloud-Nacos配置管理

文章目录 Nacos配置管理统一配置管理在nacos中添加配置文件从微服务拉取配置 配置热更新方式一方式二 配置共享1&#xff09;添加一个环境共享配置2&#xff09;在user-service中读取共享配置3&#xff09;运行两个UserApplication&#xff0c;使用不同的profile3&#xff09;运…...

物流智能分拣管理

电子商务的兴起&#xff0c;实体消费和虚拟消费结合的方式加快商品流通速度。计算机硬件和软件结合&#xff0c;改变了现代社会的工作和生活。线上和线下的消费方式这种消费观念新颖&#xff0c;受到很多年轻消费者的青睐。不同的时期有不同的经济运行机制&#xff0c;电子是一…...