使用FFMPEG进行音频重采样

news/2024/11/7 3:35:40/

准备

1. ffmpeg 4.4

2. sdl2

3.一段原始的音频PCM数据

重采样流程

1.设置输入音频参数和输出音频参数

2.根据设置的参数初始化SwrContent上下文

3.创建一个输入buffer, 根据输入的音频参数(采样率,通道数,样本位深度)申请空间,填入默认数据,用于存储输入音频数据

4.创建一个输出buffer, 根据输出的音频参数(采样率,通道数,样本位深度)申请空间,填入默认数据,用于存储重采样后的数据

5.读取PCM数据,每次读取的大小等于输入buffer的大小

6.进行重采样swr_convert

7.将输出的buffer拷贝到SDL2音频回调缓冲区中播放,或者直接写入文件,使用ffplay进行测试,也可以封装成Frame送到音频编码器中(如aac),进行编码后保存。

关键代码

设置重采样参数并初始化SWr_Content结构


struct SwrContext* swr_ctx;swr_ctx = swr_alloc_set_opts(nullptr,AV_CH_LAYOUT_MONO, //输出通道AV_SAMPLE_FMT_S16, //输出样本格式44100, //输出采样率AV_CH_LAYOUT_STEREO,  //输入通道AV_SAMPLE_FMT_FLT,  //输入样本格式44100, //输入采样率0, nullptr); swr_init(swr_ctx);

输入/输出buffer 创建

	//输入数据bufferuint8_t** pcm_buffer;int src_linesize;int src_nb_channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);int ret = av_samples_alloc_array_and_samples(&pcm_buffer, &src_linesize, src_nb_channels, frame_nb_samples, AV_SAMPLE_FMT_FLT, 0);if (ret < 0) {fprintf(stderr, "Could not allocate source samples\n");	}//输出数据bufferuint8_t** out_buffer;int dst_linesize;int dst_nb_channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_MONO);ret = av_samples_alloc_array_and_samples(&out_buffer, &dst_linesize, dst_nb_channels, frame_nb_samples, AV_SAMPLE_FMT_S16, 0);if (ret < 0) {fprintf(stderr, "Could not allocate source samples\n");}

读文件并进行重采样

readcount = fread((char *)pcm_buffer[0], 1, src_linesize, fp);data_count += readcount;
printf("   Now Playing %10d KBytes data.  %d \n", data_count / 1024, readcount);swr_convert(swr_ctx, out_buffer, frame_nb_samples, (const uint8_t**)pcm_buffer, frame_nb_samples);

源码分享

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include "sdl.h"extern "C"
{#include <libavutil/opt.h>#include <libavutil/channel_layout.h>#include <libavutil/samplefmt.h>#include <libswresample/swresample.h>
}static  Uint32  audio_len;
static  Uint8* audio_pos;
int frame_nb_samples = 1024; //一帧数据样本数
struct SwrContext* swr_ctx;void  fill_audio_pcm(void* udata, Uint8* stream, int len) 
{SDL_memset(stream, 0, len);if (audio_len == 0)return;len = (len > audio_len ? audio_len : len);SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);audio_pos += len;audio_len -= len;
}int main(int argc, char* argv[])
{if (SDL_Init(SDL_INIT_AUDIO || SDL_INIT_TIMER)){printf("SDL init error\n");return -1;}swr_ctx = swr_alloc_set_opts(nullptr,AV_CH_LAYOUT_MONO, //输出通道AV_SAMPLE_FMT_S16, //输出样本格式44100, //输出采样率AV_CH_LAYOUT_STEREO,  //输入通道AV_SAMPLE_FMT_FLT,  //输入样本格式44100, //输入采样率0, nullptr); swr_init(swr_ctx);//SDL_AudioSpecSDL_AudioSpec wanted_spec;wanted_spec.freq = 44100;wanted_spec.format = AUDIO_F32; //AUDIO_S16LSB; //AUDIO_F32;wanted_spec.channels = 2;wanted_spec.silence = 0;wanted_spec.samples = frame_nb_samples;wanted_spec.callback = fill_audio_pcm;if (SDL_OpenAudio(&wanted_spec, NULL) < 0) {printf("can't open audio.\n");return -1;}//PlaySDL_PauseAudio(0);//输入数据bufferuint8_t** pcm_buffer;int src_linesize;int src_nb_channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);int ret = av_samples_alloc_array_and_samples(&pcm_buffer, &src_linesize, src_nb_channels, frame_nb_samples, AV_SAMPLE_FMT_FLT, 0);if (ret < 0) {fprintf(stderr, "Could not allocate source samples\n");	}//输出数据bufferuint8_t** out_buffer;int dst_linesize;int dst_nb_channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_MONO);ret = av_samples_alloc_array_and_samples(&out_buffer, &dst_linesize, dst_nb_channels, frame_nb_samples, AV_SAMPLE_FMT_S16, 0);if (ret < 0) {fprintf(stderr, "Could not allocate source samples\n");}FILE* fp = nullptr;fopen_s(&fp, "D:/工程/音视频分析/source/f32le.pcm", "rb+");if (fp == NULL) {printf("cannot open this file\n");return -1;}int readcount = -1;int data_count = 0;while (!feof(fp)) {readcount = fread((char *)pcm_buffer[0], 1, src_linesize, fp);data_count += readcount;printf("   Now Playing %10d KBytes data.  %d \n", data_count / 1024, readcount);swr_convert(swr_ctx, out_buffer, frame_nb_samples, (const uint8_t**)pcm_buffer, frame_nb_samples);//Set audio buffer (PCM data)audio_len = dst_linesize; audio_pos =  (Uint8*)out_buffer[0]; //(Uint8*)pcm_buffer[0];while (audio_len > 0)SDL_Delay(1);}if (pcm_buffer)av_freep(&pcm_buffer[0]);av_freep(&pcm_buffer);if (out_buffer)av_freep(&out_buffer[0]);av_freep(&out_buffer);swr_free(&swr_ctx);fclose(fp);SDL_Quit();return 0;
}


http://www.ppmy.cn/news/74477.html

相关文章

Vm2沙箱逃逸漏洞复现(CVE-2023-32314)

0x01 产品简介 Node.js Node.js 是一个基于 V8 引擎的开源、跨平台的 JavaScript 运行环境&#xff0c;它可以在多个操作系统上运行&#xff0c;包括 Windows、macOS 和 Linux 等。Node.js 提供了一个运行在服务器端的 JavaScript 环境&#xff0c;使得开发者可以编写并发的、…

【Atlas200】华为AIPP配置文件使用

目录 AIPP介绍图像处理顺序例子&#xff1a;YUV420SP_U8转BGR格式归一化配置对应公式crop及padding功能配置生效AIPP转换模板 AIPP介绍 华为的AIPP&#xff08;AI Preprocessing&#xff09;是一种面向AI应用的图像预处理技术&#xff0c;旨在提高AI应用的效率和精度。AIPP支持…

【C++学习第十一讲】C++数据类型

文章目录 一、编程语言中的数据类型1.1 整型&#xff08;Integer&#xff09;1.2 浮点型&#xff08;Floating-Point&#xff09;1.3 字符型&#xff08;Character&#xff09;1.4 布尔型&#xff08;Boolean&#xff09;1.5 数组&#xff08;Array&#xff09;1.6 字符串&…

LeetCode 1373. Maximum Sum BST in Binary Tree【DFS,二叉搜索树】困难

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

Qt学习-QMap、QString

1、容器的概念 用于存储给定的数据类型的值&#xff0c;它是模板类&#xff0c;更具提供T的不同存储不同数据。 连续容器&#xff1a;QVector<T>,QLinkedList<T>,QList<T> 关联容器&#xff1a;QMap<K,T>,QHash<K,T> 2、Qt提供两个关联容器类…

(转载)MATLAB智能算法30个案例分析(2)——基于遗传算法和非线性规划的函数寻优算法

以下内容大部分来源于《MATLAB智能算法30个案例分析》&#xff0c;仅为学习交流所用。 1 理论基础 1.1 非线性规划 非线性规划是20世纪50年代形成的一门新兴学科。1951年库恩和塔克发表的关于最优性条件(后来称为库恩塔克条件)的论文是非线性规划诞生的标志。非线性规划研究…

Mybatis是什么?Mybatis中动态sql常用标签有哪些?

Mybatis是什么&#xff1f; Mybatis是一种开源的Java持久层框架&#xff0c;它可以将SQL语句和Java代码进行分离&#xff0c;使得开发人员可以更加专注于业务逻辑的实现。与Hibernate等ORM框架不同的是&#xff0c;Mybatis使用XML或注解的方式来描述SQL语句&#xff0c;这种方式…

服务(第二十六篇)redis的主从复制、哨兵、集群

主从复制&#xff1a; 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(Master)&#xff0c;后者称为从节点(Slave)&#xff1b;数据的复制是单向的&#xff0c;只能由主节点到从节点。 原理&#xff1a; 主从关系确定…