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文件,FFmpeg版本为4.4.2-0 代码如下: #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,问题描述2,解决方式2.1,Render Props2.2,HOC 3,使用场景 1,问题描述 当使用组件时,标签中的内容,会被当做 props.children 来渲染: 子组件: import…...
STM32 定时器问题
stm32通用定时器中断问题 STM32 定时器有时一开启就进中断的问题 /// STM32 TIM1高级定时器RCR重复计数器的理解 /// /// /// /// /// /// /// ///...

CSS学习笔记目录
CSS学习笔记之基础教程(一) CSS学习笔记之基础教程(二) CSS学习笔记之中级教程(一) CSS学习笔记之中级教程(二) CSS学习笔记之中级教程(三) CSS学习笔记之高级…...

随笔-我在武汉一周了
做梦一样,已经来武汉一周了,回顾一下这几天,还真是有意思。 周一坐了四个小时的高铁到了武汉站,照着指示牌打了个出租车。司机大姐开得很快,瞅了眼,最快速度到了110,差点把我晃晕。一下车就感觉…...
Python 爬虫零基础:探索网络数据的神秘世界
Python 爬虫零基础:探索网络数据的神秘世界 在数字化时代,网络数据如同无尽的宝藏,等待着我们去发掘。Python爬虫,作为获取这些数据的重要工具,正逐渐走进越来越多人的视野。对于零基础的学习者来说,如何入…...
微信小程序的view的属性值和用法
在微信小程序中,view 是一个基础的视图组件,用于承载其他视图组件或者展示文本、图片等内容。view 组件具有多种属性,用于控制其行为和样式。以下是一些常用的 view 属性及其用法: class / style: 控制视图的样式,可以…...
Python优化、异常处理与性能提升技巧
Python作为一种高效的编程语言,其灵活性和强大的功能使得它成为了许多开发者的首选。在日常的编程实践中,掌握一些高效的Python技巧可以极大地提升开发效率和代码质量。本文将介绍五个关于Python使用技巧,帮助你更加熟练地运用Python解决问题…...

Flink状态State | 大数据技术
⭐简单说两句⭐ ✨ 正在努力的小叮当~ 💖 超级爱分享,分享各种有趣干货! 👩💻 提供:模拟面试 | 简历诊断 | 独家简历模板 🌈 感谢关注,关注了你就是我的超级粉丝啦! &a…...
go语言方法之方法值和方法表达式
我们经常选择一个方法,并且在同一个表达式里执行,比如常见的p.Distance()形式,实际上 将其分成两步来执行也是可能的。p.Distance叫作“选择器”,选择器会返回一个方法"值"->一 个将方法(Point.Distance)绑定到特定接…...

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

24、Linux网络端口
Linux网络端口 1、查看网络接口信息ifconfig ens33 eth0 文件 ifconfig 当前设备正在工作的网卡,启动的设备。 ifconfig -a 查看所有的网络设备。 ifconfig ens33 查看指定网卡设备。 ifconfig ens33 up/down 对指定网卡设备进行开关 基于物理网卡设备虚拟的…...
Mysql全文搜索和LIKE搜索有什么区别
全文搜索和LIKE的区别 性能:在大数据集上,全文搜索通常比LIKE查询更快,因为它使用了专门的索引结构。 功能:全文搜索提供了更丰富的查询功能,如多个关键词的搜索、自然语言搜索、布尔搜索等。而LIKE通常只支持简单的…...

elementplu父级页面怎么使用封装子组件原组件的方法
一、使用原因: 封装了el-table,表格中有多选,父级要根据指定状态,让其选择不上,需要用到elementplus中table原方法toggleRowSelection 附加小知识点:(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),拥有私有属性:宽度(width)、高度(height), 定义公有成员函数: 初始化函数:void init(int w, int h) 更改宽度的函数:set_w(int w) 更改高度的函数:set_h(int h) 输出该矩形的周长和面积函数:void show()...

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

笔试训练2
牛客.单词搜索 刚开始我就想是搜索,但是不清楚bfs还是dfs更好,我尝试了bfs但是队列存东西,没有我想象的那么好写,所以我决定试试dfs import java.util.*;public class Solution {static int m 0;static int n 0;static int […...
构建坚不可摧的Web安全防线:深入剖析二阶注入与全面防御策略
引言 在数字化时代,数据安全是企业和个人最为关注的问题之一。网络攻击手段层出不穷,其中SQL注入攻击尤为狡猾,它允许攻击者通过Web应用的漏洞对数据库进行非法操作。更隐蔽的是二阶注入攻击,它不仅威胁当前操作,还能…...

(4) qml动态元素
文章目录 概述注意 动画元素变化的策略Animation on 变化behavior on⽤standalone animation注意 缓冲曲线(Easing Curves)动画分组 概述 这⼀章介绍如何控制属性值的变化,通过动画的⽅式在⼀段时间内来改变属性值。这项技术是建⽴⼀个现代化…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...