本文将用libavfilter来转换原始音频格式。程序输入一个原始音频文件:pcm格式,采样率48000,2声道,AV_SAMPLE_FMT_FLT格式。输出:pcm格式,采样率44100,1声道,AV_SAMPLE_FMT_S16P格式。

程序流程如下:

上面的filter都是FFmpeg内置的,设置参数,然后调用即可。所有的filter依次连接,形成filter链。

abuffer filter:filter链的开始端,用于设置输入音频数据的格式,包括声道、采样率、存储格式等。

volume filter:用于设置音量。

aformat filter:用于设置输出音频数据的格式,包括声道、采样率、存储格式等。

abuffersink filter:filter链的结束端,用于结束整个filter链。

#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>#include "libavutil/channel_layout.h"
#include "libavutil/md5.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "libavutil/samplefmt.h"#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"#define INPUT_SAMPLERATE     48000
#define INPUT_FORMAT         AV_SAMPLE_FMT_FLT
#define INPUT_CHANNEL_LAYOUT AV_CH_LAYOUT_STEREO#define OUTPUT_SAMPLERATE     44100
#define OUTPUT_FORMAT         AV_SAMPLE_FMT_S16P
#define OUTPUT_CHANNEL_LAYOUT AV_CH_LAYOUT_MONO#define VOLUME_VAL 0.90#define FRAME_SIZE 1024static int init_filter_graph(AVFilterGraph **graph, AVFilterContext **src,AVFilterContext **sink)
{AVFilterGraph *filter_graph;AVFilterContext *abuffer_ctx;const AVFilter  *abuffer;AVFilterContext *volume_ctx;const AVFilter  *volume;AVFilterContext *aformat_ctx;const AVFilter  *aformat;AVFilterContext *abuffersink_ctx;const AVFilter  *abuffersink;AVDictionary *options_dict = NULL;char options_str[1024];char ch_layout[64];int err;/* 创建filtergraph,包含所有的filter */filter_graph = avfilter_graph_alloc();if (!filter_graph) {fprintf(stderr, "Unable to create filter graph.\n");return AVERROR(ENOMEM);}/*  创建abuffer filter,用于输入数据(链的起始点) */abuffer = avfilter_get_by_name("abuffer");if (!abuffer) {fprintf(stderr, "Could not find the abuffer filter.\n");return AVERROR_FILTER_NOT_FOUND;}abuffer_ctx = avfilter_graph_alloc_filter(filter_graph, abuffer, "src");if (!abuffer_ctx) {fprintf(stderr, "Could not allocate the abuffer instance.\n");return AVERROR(ENOMEM);}/* 设置abuffer filter的参数,也就是输入音频数据的参数 */av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, INPUT_CHANNEL_LAYOUT);av_opt_set    (abuffer_ctx, "channel_layout", ch_layout,                            AV_OPT_SEARCH_CHILDREN);av_opt_set    (abuffer_ctx, "sample_fmt",     av_get_sample_fmt_name(INPUT_FORMAT), AV_OPT_SEARCH_CHILDREN);av_opt_set_q  (abuffer_ctx, "time_base",      (AVRational){ 1, INPUT_SAMPLERATE },  AV_OPT_SEARCH_CHILDREN);av_opt_set_int(abuffer_ctx, "sample_rate",    INPUT_SAMPLERATE,                     AV_OPT_SEARCH_CHILDREN);/* 用上面的参数初始化abuffer filter,因为上面设置了参数,所以第二个参数传NULL*/err = avfilter_init_str(abuffer_ctx, NULL);if (err < 0) {fprintf(stderr, "Could not initialize the abuffer filter.\n");return err;}/* 创建volume filter. */volume = avfilter_get_by_name("volume");if (!volume) {fprintf(stderr, "Could not find the volume filter.\n");return AVERROR_FILTER_NOT_FOUND;}volume_ctx = avfilter_graph_alloc_filter(filter_graph, volume, "volume");if (!volume_ctx) {fprintf(stderr, "Could not allocate the volume instance.\n");return AVERROR(ENOMEM);}/* 通过avfilter_init_dict设置volume filter */av_dict_set(&options_dict, "volume", AV_STRINGIFY(VOLUME_VAL), 0);err = avfilter_init_dict(volume_ctx, &options_dict);av_dict_free(&options_dict);if (err < 0) {fprintf(stderr, "Could not initialize the volume filter.\n");return err;}/* 创建aformat filter,用于设置想要的最终输出格式 */aformat = avfilter_get_by_name("aformat");if (!aformat) {fprintf(stderr, "Could not find the aformat filter.\n");return AVERROR_FILTER_NOT_FOUND;}aformat_ctx = avfilter_graph_alloc_filter(filter_graph, aformat, "aformat");if (!aformat_ctx) {fprintf(stderr, "Could not allocate the aformat instance.\n");return AVERROR(ENOMEM);}/* 另外一种方式设置aformat filter的参数(键值对且中间用冒号的形式)*/snprintf(options_str, sizeof(options_str),"sample_fmts=%s:sample_rates=%d:channel_layouts=0x%"PRIx64,av_get_sample_fmt_name(OUTPUT_FORMAT), OUTPUT_SAMPLERATE,(uint64_t)OUTPUT_CHANNEL_LAYOUT);err = avfilter_init_str(aformat_ctx, options_str);if (err < 0) {av_log(NULL, AV_LOG_ERROR, "Could not initialize the aformat filter.\n");return err;}/* 最后创建abuffersink filter,用于获取graph输出的最终转换好的数据 */abuffersink = avfilter_get_by_name("abuffersink");if (!abuffersink) {fprintf(stderr, "Could not find the abuffersink filter.\n");return AVERROR_FILTER_NOT_FOUND;}abuffersink_ctx = avfilter_graph_alloc_filter(filter_graph, abuffersink, "sink");if (!abuffersink_ctx) {fprintf(stderr, "Could not allocate the abuffersink instance.\n");return AVERROR(ENOMEM);}/* 不需要设置参数 */err = avfilter_init_str(abuffersink_ctx, NULL);if (err < 0) {fprintf(stderr, "Could not initialize the abuffersink instance.\n");return err;}/* 连接filters */err = avfilter_link(abuffer_ctx, 0, volume_ctx, 0);if (err >= 0)err = avfilter_link(volume_ctx, 0, aformat_ctx, 0);if (err >= 0)err = avfilter_link(aformat_ctx, 0, abuffersink_ctx, 0);if (err < 0) {fprintf(stderr, "Error connecting filters\n");return err;}/* 配置graph. */err = avfilter_graph_config(filter_graph, NULL);if (err < 0) {av_log(NULL, AV_LOG_ERROR, "Error configuring the filter graph\n");return err;}*graph = filter_graph;*src   = abuffer_ctx;*sink  = abuffersink_ctx;return 0;
}static void filter_audio(void)
{const char *in_filename = "/Users/zhw/Desktop/resource/sintel_f32le_2_48000.pcm";const char *out_filename = "/Users/zhw/Desktop/sintel_s16le_1_44100.pcm";FILE *in_file = NULL, *out_file = NULL;AVFilterGraph *graph;AVFilterContext *src, *sink;AVFrame *frame;int err;in_file = fopen(in_filename, "rb");if (!in_file) {printf("open file %s fail\n", in_filename);exit(1);}out_file = fopen(out_filename, "wb");if (!out_file) {printf("open file %s fail\n", out_filename);exit(1);}/* 创建frame,存储输入数据 */frame  = av_frame_alloc();if (!frame) {fprintf(stderr, "Error allocating the frame\n");exit(1);}/* 设置filtergraph. */err = init_filter_graph(&graph, &src, &sink);if (err < 0) {fprintf(stderr, "Unable to init filter graph:");exit(1);}while (!feof(in_file)) {//        static int frame_num = 0;/* Set up the frame properties and allocate the buffer for the data. */frame->sample_rate    = INPUT_SAMPLERATE;frame->format         = INPUT_FORMAT;frame->channel_layout = INPUT_CHANNEL_LAYOUT;frame->nb_samples     = FRAME_SIZE;
//        frame->pts            = frame_num * FRAME_SIZE;err = av_frame_get_buffer(frame, 0);if (err < 0)exit(1);int nb_channels = av_get_channel_layout_nb_channels(frame->channel_layout);int bytes_per_sample = av_get_bytes_per_sample(frame->format);//读取数据unsigned long bytes = fread(frame->data[0], 1, frame->nb_samples * nb_channels * bytes_per_sample, in_file);if (bytes < frame->nb_samples * nb_channels * bytes_per_sample) {
//            printf("*************");}//        frame_num++;//添加frame到buffer,用于转换err = av_buffersrc_add_frame(src, frame);if (err < 0) {av_frame_unref(frame);fprintf(stderr, "Error submitting the frame to the filtergraph:");exit(1);}//获取输出数据while ((err = av_buffersink_get_frame(sink, frame)) >= 0) {if (av_sample_fmt_is_planar(frame->format)) {int data_size = av_get_bytes_per_sample(frame->format);for (int i = 0; i < frame->nb_samples; i++)for (int ch = 0; ch < frame->channels; ch++)fwrite(frame->data[ch] + data_size*i, 1, data_size, out_file);}else {fwrite(frame->extended_data[0], 1, frame->linesize[0], out_file);}av_frame_unref(frame);}if (err == AVERROR(EAGAIN)) {/* 需要更多的数据 */continue;} else if (err == AVERROR_EOF) {/* 到文件尾*/break;} else if (err < 0) {/* An error occurred. */fprintf(stderr, "Error filtering the data:");exit(1);}}avfilter_graph_free(&graph);av_frame_free(&frame);printf("finish\n");}

24.FFmpeg学习笔记 - 用libavfilter转换原始音频格式1相关推荐

  1. ffmpeg学习日记612-指令-转换视频格式

    ffmpeg学习日记612-指令-转换视频格式 mkv转mp4 ffmpeg -i LostInTranslation.mkv -codec copy LostInTranslation.mp4 Li ...

  2. ffmpeg学习日记602-指令-转换视频的分辨率

    ffmpeg学习日记602-指令-转换视频的分辨率 指令如下 ffmpeg -i video_1920.mp4 -vf scale=640:360 video_640.mp4 -hide_banner

  3. Excel VBA 学习笔记13:单元格的格式

    Excel VBA 学习笔记13:单元格的格式 NumberFormat 属性 (Excel) vba excel 单元格格式设置 Excel VBA 单元格格式 python解决SNIMissing ...

  4. m4s格式转换mp3_如何将m4a无损转换mp3音频格式

    m4a是mpeg4编码标准音频文件的其中一种扩展名,一般的mpeg4音频的扩展名是mp4但在ipod苹果公为了以示区别开始推行m4a格式,仅限在苹果的iTunes和iPad中使用,所以如何将m4a无损 ...

  5. ffmpeg学习笔记

           对于每一个刚開始学习的人,刚開始接触ffmpeg时,想必会有三个问题最为关心,即ffmpeg是什么?能干什么?怎么開始学习?本人前段时间開始接触ffmpeg,在刚開始学习过程中.这三个问 ...

  6. 音乐格式如何进行转换,音频格式转换器哪个好

    经常会听到一些比较好听的歌曲,有的时候回将它们下载下来.但是并不是每首歌曲的格式都是一样的,为了方便我们对歌曲的管理,许多人都会选择将音乐的格式统一转换成某一个格式,那么怎么进行转换呢?下面小编就来教 ...

  7. 音乐格式怎么转换,音频格式转换的方法

    今天所说的是教大家如何转换音频.音乐格式.在生活中我们会听到一些比较好听的歌曲,我们经常会将这些好听的歌曲给下载下来.然而有的时候我们会惊奇地发现某些音乐的格式很奇怪,是一些自己没有见过的音频格式,而 ...

  8. 音乐格式怎么转换,音频格式转换的方法 1

    今天所说的是教大家如何转换音频.音乐格式.在生活中我们会听到一些比较好听的歌曲,我们经常会将这些好听的歌曲给下载下来.然而有的时候我们会惊奇地发现某些音乐的格式很奇怪,是一些自己没有见过的音频格式,而 ...

  9. 王佩丰 Excel 基础24讲 | 学习笔记(全)

    第一讲:认识Excel 1.简介 excel能做什么? 数据存储 → 数据处理 → 数据分析 → 数据呈现 excel界面 补充:Excel数据分析步骤 ①提出问题:明确自己需要通过数据分析解决什么问 ...

  10. FFmpeg学习笔记汇总

    第1章 FFmpeg简介 1.1 FFmpeg定义 FFmpeg既是一款音视频编解码工具,同时也是一组音视频编解码开发套件,作为编解码开发套件,它为开发者提供了丰富的音视频处理的调用接口. FFmpe ...

最新文章

  1. Nature Methods | 用深度多任务神经网络探索单细胞数据
  2. hibernate---一对一单项外键关联
  3. 矩阵理论及其应用_有限元分析ansys理论与应用视频第三课 绪论:直接法矩阵求解...
  4. RocketMQ快速入门之消息过滤器(用户自定义属性)
  5. 影视感悟专题---1、B站-魔兽世界代理及其它乱七八糟
  6. c语言指针算法分析怎么写,什么叫指针算法啊??
  7. MySQL 读写分离 部分_一个完整的mysql读写分离环境包括以下几个部分
  8. 如何在JPG或BMP图片上显示输入的订单数据内容,并在报表打印时显示出来,后台数据库是SQL SERVER 2000 ,先谢了.高分!...
  9. Azure Linux VM密钥登录
  10. 【CS229机器学习】作业 Problem Set #0 线性代数和多变量计算
  11. [算法]代码运行时间增长数量级对比 线性级别N vs 线性对数级别 NlgN
  12. 数据库表空间大小查询
  13. Java开发必备技巧
  14. 谷歌浏览器打开显示2345浏览器界面
  15. pwn刷题num45----fast fit
  16. 计算机作业毕业论文排版,计算机毕业设计论文排版格式
  17. ios 关于navigationController导航栏隐藏问题
  18. 我在写一个微信墙(一)
  19. 手机怎么投屏到电脑?手机投屏软件哪个好用
  20. java狗具有特别的接飞盘的方法_训练狗接飞盘,5个方法让你快速见成效!

热门文章

  1. 坦白从宽,牢底坐穿?留学生如何应对美警察审问~~
  2. if (resultCode == RESULT_OK) 在红米手机上resultCode返回并不是RESULT_OK
  3. mysql数据库备份还原的几种方式
  4. e900v21e 装第三方_魔百盒E900V21E-MV310芯片第三方优化刷机免拆卡刷固件下载
  5. 如何建立团队知识库管理系统,把分散信息有效整理?
  6. CentOS 8 添加中文语言包
  7. Statement cancelled due to timeout or client request报错
  8. N1完美刷入Armbian系统
  9. 思科网络实验3.5.3 vlan配置故障排除
  10. 五、完成Teigha.net对CAD文件中的Entity实体进行编辑修改功能,包括字体,样式,颜色,备注XData等属性