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

FFmpeg PCM编码为AAC

使用FFmpeg库把PCM文件编码为AAC文件,FFmpeg版本为4.4.2-0

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/mem.h>
#include <libavutil/samplefmt.h>
#include <libswresample/swresample.h>int main(int argc, char *argv[])
{int ret = -1;int64_t pts = 0;const char *input_file = argv[1];const char *output_file = argv[2];FILE *input_pcm = NULL;AVFormatContext *format_context = NULL;AVCodecContext *codec_context = NULL;AVStream *stream = NULL;AVCodec *codec = NULL;AVFrame *frame = NULL;AVPacket *packet = NULL;struct SwrContext *swr_ctx = NULL;enum AVSampleFormat in_sample_fmt = AV_SAMPLE_FMT_S16; // 输入pcm文件的采样格式int in_sample_rate = 44100;                            // 输入pcm文件的采样率uint64_t in_channel_layout = AV_CH_LAYOUT_STEREO;      // 输入pcm文件的声道布局if (argc < 3){fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);return -1;}input_pcm = fopen(input_file, "rb");if (!input_pcm){fprintf(stderr, "Could not open input file %s\n", input_file);goto end;}// 分配输出格式上下文avformat_alloc_output_context2(&format_context, NULL, NULL, output_file);if (!format_context){fprintf(stderr, "Could not allocate output format context\n");goto end;}// 查找编码器, 这里使用ffmpeg内置的aac编码器,// 如果需要使用其他编码器, 可以使用 avcodec_find_encoder_by_name 按名称查找codec = avcodec_find_encoder(AV_CODEC_ID_AAC);if (!codec){fprintf(stderr, "Codec not found\n");goto end;}// 创建新的音频流stream = avformat_new_stream(format_context, NULL);if (!stream){fprintf(stderr, "Could not allocate stream\n");goto end;}// 分配编码器上下文codec_context = avcodec_alloc_context3(codec);if (!codec_context){fprintf(stderr, "Could not allocate codec context\n");goto end;}/* 设置编码器参数 */// 编码器IDcodec_context->codec_id = AV_CODEC_ID_AAC;// 媒体类型codec_context->codec_type = AVMEDIA_TYPE_AUDIO;// 设置编码器接收的输入音频样本的采样格式,这里设置为内置aac编码器支持的采样格式,// 不同的编码器支持的采样格式可能不同。codec_context->sample_fmt = AV_SAMPLE_FMT_FLTP;// 设置采样率codec_context->sample_rate = in_sample_rate;// 设置声道布局codec_context->channel_layout = in_channel_layout;// 设置声道数codec_context->channels = av_get_channel_layout_nb_channels(codec_context->channel_layout);// 设置比特率codec_context->bit_rate = 128000;// 设置AAC的profilecodec_context->profile = FF_PROFILE_AAC_LOW;// 打开编码器if (avcodec_open2(codec_context, codec, NULL) < 0){fprintf(stderr, "Could not open codec\n");goto end;}// 将编码器参数复制到流int result = avcodec_parameters_from_context(stream->codecpar, codec_context);if (result < 0){fprintf(stderr, "Could not copy codec parameters\n");goto end;}// 打开输出文件if (!(format_context->oformat->flags & AVFMT_NOFILE)) // 检查输出格式是否需要文件存储{result = avio_open(&format_context->pb, output_file, AVIO_FLAG_WRITE);if (result < 0){fprintf(stderr, "Could not open output file %s\n", output_file);goto end;}}// 写文件头result = avformat_write_header(format_context, NULL);if (result < 0){fprintf(stderr, "Error occurred when opening output file\n");goto end;}frame = av_frame_alloc();packet = av_packet_alloc();if (!frame || !packet){fprintf(stderr, "Could not allocate frame or packet\n");goto end;}// 设置帧参数frame->nb_samples = codec_context->frame_size; // 一帧音频数据的采样个数,AAC编码器的frame_size默认为1024frame->format = codec_context->sample_fmt;frame->channel_layout = codec_context->channel_layout;// 分配帧数据缓冲区result = av_frame_get_buffer(frame, 0);if (result < 0){fprintf(stderr, "Could not allocate audio data buffers\n");goto end;}// 初始化重采样上下文swr_ctx = swr_alloc_set_opts(NULL,codec_context->channel_layout, codec_context->sample_fmt, codec_context->sample_rate,codec_context->channel_layout, in_sample_fmt, codec_context->sample_rate,0, NULL);if (!swr_ctx || swr_init(swr_ctx) < 0){fprintf(stderr, "Could not allocate resampler context\n");goto end;}// 计算每帧音频数据的大小 = 采样个数 * 采样格式大小 * 声道数int fsize = frame->nb_samples * av_get_bytes_per_sample(in_sample_fmt) * codec_context->channels;// 分配缓冲区uint8_t *input_buffer = (uint8_t *)av_malloc(fsize);if (!input_buffer){fprintf(stderr, "Could not allocate input buffer\n");goto end;}// 编码循环while (1){// 读取PCM数据到缓冲区result = fread(input_buffer, 1, fsize, input_pcm);if (result <= 0){break;}// 处理不足一帧的情况,不足一帧的数据用0填充if (result < fsize){memset(input_buffer + result, 0, fsize - result);}// 重采样result = swr_convert(swr_ctx, frame->data, frame->nb_samples,(const uint8_t **)&input_buffer, frame->nb_samples);if (result < 0){fprintf(stderr, "Error while converting\n");goto end;}frame->pts = pts;pts += frame->nb_samples; // 计算下一帧的pts,每个帧的时间戳应该是前一个帧的时间戳加上该帧的样本数// 发送帧到编码器result = avcodec_send_frame(codec_context, frame);if (result < 0){fprintf(stderr, "Error sending frame to codec\n");goto end;}// 接收编码后的数据包while (result >= 0){result = avcodec_receive_packet(codec_context, packet);if (result == AVERROR(EAGAIN) || result == AVERROR_EOF){break;}else if (result < 0){fprintf(stderr, "avcodec_receive_packet failed (errmsg '%s')\n", av_err2str(result));goto end;}packet->stream_index = stream->index;// 将时间戳从编码器时间基转换到流时间基av_packet_rescale_ts(packet, codec_context->time_base, stream->time_base);// 写数据包到输出文件result = av_interleaved_write_frame(format_context, packet);if (result < 0){fprintf(stderr, "Error writing audio packet\n");av_packet_unref(packet);goto end;}av_packet_unref(packet);}}av_free(input_buffer);// 发送NULL帧到编码器,刷新编码器内部缓冲区result = avcodec_send_frame(codec_context, NULL);while (result >= 0){result = avcodec_receive_packet(codec_context, packet);if (result == AVERROR_EOF){break;}else if (result < 0){fprintf(stderr, "avcodec_receive_packet failed (errmsg '%s')\n", av_err2str(result));goto end;}packet->stream_index = stream->index;av_packet_rescale_ts(packet, codec_context->time_base, stream->time_base);result = av_interleaved_write_frame(format_context, packet);if (result < 0){fprintf(stderr, "Error writing audio packet\n");av_packet_unref(packet);goto end;}av_packet_unref(packet);}// 写文件尾av_write_trailer(format_context);ret = 0;end:if (frame)av_frame_free(&frame);if (packet)av_packet_free(&packet);if (codec_context)avcodec_free_context(&codec_context);if (format_context)avformat_free_context(format_context);if (swr_ctx)swr_free(&swr_ctx);if (input_pcm)fclose(input_pcm);return ret;
}

相关文章:

FFmpeg PCM编码为AAC

使用FFmpeg库把PCM文件编码为AAC文件&#xff0c;FFmpeg版本为4.4.2-0 代码如下&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <…...

React@16.x(16)Render Props

目录 1&#xff0c;问题描述2&#xff0c;解决方式2.1&#xff0c;Render Props2.2&#xff0c;HOC 3&#xff0c;使用场景 1&#xff0c;问题描述 当使用组件时&#xff0c;标签中的内容&#xff0c;会被当做 props.children 来渲染&#xff1a; 子组件&#xff1a; import…...

STM32 定时器问题

stm32通用定时器中断问题 STM32 定时器有时一开启就进中断的问题 /// STM32 TIM1高级定时器RCR重复计数器的理解 /// /// /// /// /// /// /// ///...

CSS学习笔记目录

CSS学习笔记之基础教程&#xff08;一&#xff09; CSS学习笔记之基础教程&#xff08;二&#xff09; CSS学习笔记之中级教程&#xff08;一&#xff09; CSS学习笔记之中级教程&#xff08;二&#xff09; CSS学习笔记之中级教程&#xff08;三&#xff09; CSS学习笔记之高级…...

随笔-我在武汉一周了

做梦一样&#xff0c;已经来武汉一周了&#xff0c;回顾一下这几天&#xff0c;还真是有意思。 周一坐了四个小时的高铁到了武汉站&#xff0c;照着指示牌打了个出租车。司机大姐开得很快&#xff0c;瞅了眼&#xff0c;最快速度到了110&#xff0c;差点把我晃晕。一下车就感觉…...

Python 爬虫零基础:探索网络数据的神秘世界

Python 爬虫零基础&#xff1a;探索网络数据的神秘世界 在数字化时代&#xff0c;网络数据如同无尽的宝藏&#xff0c;等待着我们去发掘。Python爬虫&#xff0c;作为获取这些数据的重要工具&#xff0c;正逐渐走进越来越多人的视野。对于零基础的学习者来说&#xff0c;如何入…...

微信小程序的view的属性值和用法

在微信小程序中&#xff0c;view 是一个基础的视图组件&#xff0c;用于承载其他视图组件或者展示文本、图片等内容。view 组件具有多种属性&#xff0c;用于控制其行为和样式。以下是一些常用的 view 属性及其用法&#xff1a; class / style: 控制视图的样式&#xff0c;可以…...

Python优化、异常处理与性能提升技巧

Python作为一种高效的编程语言&#xff0c;其灵活性和强大的功能使得它成为了许多开发者的首选。在日常的编程实践中&#xff0c;掌握一些高效的Python技巧可以极大地提升开发效率和代码质量。本文将介绍五个关于Python使用技巧&#xff0c;帮助你更加熟练地运用Python解决问题…...

Flink状态State | 大数据技术

⭐简单说两句⭐ ✨ 正在努力的小叮当~ &#x1f496; 超级爱分享&#xff0c;分享各种有趣干货&#xff01; &#x1f469;‍&#x1f4bb; 提供&#xff1a;模拟面试 | 简历诊断 | 独家简历模板 &#x1f308; 感谢关注&#xff0c;关注了你就是我的超级粉丝啦&#xff01; &a…...

go语言方法之方法值和方法表达式

我们经常选择一个方法&#xff0c;并且在同一个表达式里执行&#xff0c;比如常见的p.Distance()形式&#xff0c;实际上 将其分成两步来执行也是可能的。p.Distance叫作“选择器”&#xff0c;选择器会返回一个方法"值"->一 个将方法(Point.Distance)绑定到特定接…...

TDMQ CKafka 版弹性存储能力重磅上线!

导语 自 2024年5月起&#xff0c;TDMQ CKafka 专业版支持弹性存储能力&#xff0c;这种产品形态下&#xff0c;存储可按需使用、按量付费&#xff0c;一方面降低消费即删除、存储使用波动大场景下的存储成本&#xff0c;另一方面存储空间理论上无穷大。 TDMQ CKafka 版产品能…...

24、Linux网络端口

Linux网络端口 1、查看网络接口信息ifconfig ens33 eth0 文件 ifconfig 当前设备正在工作的网卡&#xff0c;启动的设备。 ifconfig -a 查看所有的网络设备。 ifconfig ens33 查看指定网卡设备。 ifconfig ens33 up/down 对指定网卡设备进行开关 基于物理网卡设备虚拟的…...

Mysql全文搜索和LIKE搜索有什么区别

全文搜索和LIKE的区别 性能&#xff1a;在大数据集上&#xff0c;全文搜索通常比LIKE查询更快&#xff0c;因为它使用了专门的索引结构。 功能&#xff1a;全文搜索提供了更丰富的查询功能&#xff0c;如多个关键词的搜索、自然语言搜索、布尔搜索等。而LIKE通常只支持简单的…...

elementplu父级页面怎么使用封装子组件原组件的方法

一、使用原因&#xff1a; 封装了el-table&#xff0c;表格中有多选&#xff0c;父级要根据指定状态&#xff0c;让其选择不上&#xff0c;需要用到elementplus中table原方法toggleRowSelection 附加小知识点&#xff1a;&#xff08;el-tree刷新树后之前选中的保持高亮setCurr…...

el-date-picker选择开始日期的近半年

<el-date-pickerv-model"form[val.key]":type"val.datePickerType || daterange":clearable"val.clearable && true"range-separator"~"start-placeholder"开始日期"end-placeholder"结束日期"style&q…...

C++

封装一个矩形类(Rect)&#xff0c;拥有私有属性:宽度(width)、高度(height)&#xff0c; 定义公有成员函数: 初始化函数:void init(int w, int h) 更改宽度的函数:set_w(int w) 更改高度的函数:set_h(int h) 输出该矩形的周长和面积函数:void show()...

nginx源码阅读理解 [持续更新,建议关注]

文章目录 前述一、nginx 进程模型基本流程二、源码里的小点1.对字符串操作都进行了原生实现2.配置文件解析也是原生实现待续 前述 通过对 nginx 的了解和代码简单阅读&#xff0c;发现这个C代码的中间件确实存在过人之处&#xff0c;使用场景特别多&#xff0c;插件模块很丰富…...

笔试训练2

牛客.单词搜索 刚开始我就想是搜索&#xff0c;但是不清楚bfs还是dfs更好&#xff0c;我尝试了bfs但是队列存东西&#xff0c;没有我想象的那么好写&#xff0c;所以我决定试试dfs import java.util.*;public class Solution {static int m 0;static int n 0;static int […...

构建坚不可摧的Web安全防线:深入剖析二阶注入与全面防御策略

引言 在数字化时代&#xff0c;数据安全是企业和个人最为关注的问题之一。网络攻击手段层出不穷&#xff0c;其中SQL注入攻击尤为狡猾&#xff0c;它允许攻击者通过Web应用的漏洞对数据库进行非法操作。更隐蔽的是二阶注入攻击&#xff0c;它不仅威胁当前操作&#xff0c;还能…...

(4) qml动态元素

文章目录 概述注意 动画元素变化的策略Animation on 变化behavior on⽤standalone animation注意 缓冲曲线&#xff08;Easing Curves&#xff09;动画分组 概述 这⼀章介绍如何控制属性值的变化&#xff0c;通过动画的⽅式在⼀段时间内来改变属性值。这项技术是建⽴⼀个现代化…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...