2023-04-30:用go语言重写ffmpeg的resampling_audio.c示例,它实现了音频重采样的功能。
2023-04-30:用go语言重写ffmpeg的resampling_audio.c示例,它实现了音频重采样的功能。
答案2023-04-30:
resampling_audio.c 是 FFmpeg 中的一个源文件,其主要功能是实现音频重采样。
音频重采样是指将一段音频数据从一个采样率、声道数或样本格式转换为另一种采样率、声道数或样本格式。在实际应用中,不同的设备和系统可能需要不同的音频格式,因此进行音频重采样是非常常见的操作。
resampling_audio.c 中实现了多种音频重采样算法,包括最近邻插值法、线性插值法、升采样过滤器、降采样过滤器等等。这些算法可以针对不同的输入和输出音频格式进行选择,以达到最佳效果。
使用 resampling_audio.c 可以方便地完成音频重采样操作,并在保证音质的同时提高处理效率。因此,它是 FFmpeg 中非常重要的一个模块。
代码见github/moonfdd/ffmpeg-go库。
这段代码是一个使用 FFmpeg 中的 libswresample 库进行音频重采样的示例程序。大体过程如下:
--1. 初始化输入和输出音频参数,包括声道数、采样率、样本格式等。
--3. 创建 libswresample 的上下文(SwrContext)。
--5. 通过 AvOptSetXXX 函数设置输入输出参数。
--7. 调用 SwrInit 函数初始化 resampler 上下文。
--9. 申请输入和输出音频数据缓冲区。
--11. 循环读取输入音频数据,重采样并保存为输出音频数据。每次循环中:
----a. 填充源音频数据缓冲区(即生成或从文件中读取音频数据)。
----b. 计算重采样后的目标音频数据大小。
----c. 申请足够的输出音频数据缓冲区空间。
----d. 调用 SwrConvert 函数将源音频数据转换为目标音频数据。
----e. 将重采样后的目标音频数据写入输出文件。
--13. 释放资源并退出程序。
需要注意的是,在实际使用中需要根据具体情况调整输入输出音频参数以及重采样算法等设置。
命令如下:
go run ./examples/internalexamples/resampling_audio/main.go ./out/res.aac
./lib/ffplay -f s16le -channel_layout 7 -channels 3 -ar 44100 ./out/res.aac
golang代码如下:
package main
import (
"fmt"
"math"
"os"
"unsafe"
"github.com/moonfdd/ffmpeg-go/ffcommon"
"github.com/moonfdd/ffmpeg-go/libavutil"
"github.com/moonfdd/ffmpeg-go/libswresample"
)
func main0() (ret ffcommon.FInt) {
var src_ch_layout ffcommon.FInt64T = libavutil.AV_CH_LAYOUT_STEREO
var dst_ch_layout ffcommon.FInt64T = libavutil.AV_CH_LAYOUT_SURROUND
var src_rate ffcommon.FInt = 48000
var dst_rate ffcommon.FInt = 44100
var src_data, dst_data **ffcommon.FUint8T
var src_nb_channels, dst_nb_channels ffcommon.FInt
var src_linesize, dst_linesize ffcommon.FInt
var src_nb_samples ffcommon.FInt = 1024
var dst_nb_samples ffcommon.FInt
var max_dst_nb_samples ffcommon.FInt
var src_sample_fmt libavutil.AVSampleFormat = libavutil.AV_SAMPLE_FMT_DBL
var dst_sample_fmt libavutil.AVSampleFormat = libavutil.AV_SAMPLE_FMT_S16
var dst_filename string
var dst_file *os.File
var dst_bufsize ffcommon.FInt
var fmt0 string
var swr_ctx *libswresample.SwrContext
var t ffcommon.FDouble
if len(os.Args) != 2 {
fmt.Printf("Usage: %s output_file\nAPI example program to show how to resample an audio stream with libswresample.\nThis program generates a series of audio frames, resamples them to a specified output format and rate and saves them to an output file named output_file.\n",
os.Args[0])
os.Exit(1)
}
dst_filename = os.Args[1]
dst_file, _ = os.Create(dst_filename)
if dst_file == nil {
fmt.Printf("Could not open destination file %s\n", dst_filename)
os.Exit(1)
}
/* create resampler context */
swr_ctx = libswresample.SwrAlloc()
if swr_ctx == nil {
fmt.Printf("Could not allocate resampler context\n")
ret = -libavutil.ENOMEM
goto end
}
/* set options */
libavutil.AvOptSetInt(uintptr(unsafe.Pointer(swr_ctx)), "in_channel_layout", src_ch_layout, 0)
libavutil.AvOptSetInt(uintptr(unsafe.Pointer(swr_ctx)), "in_sample_rate", int64(src_rate), 0)
libavutil.AvOptSetSampleFmt(uintptr(unsafe.Pointer(swr_ctx)), "in_sample_fmt", src_sample_fmt, 0)
libavutil.AvOptSetInt(uintptr(unsafe.Pointer(swr_ctx)), "out_channel_layout", dst_ch_layout, 0)
libavutil.AvOptSetInt(uintptr(unsafe.Pointer(swr_ctx)), "out_sample_rate", int64(src_rate), 0)
libavutil.AvOptSetSampleFmt(uintptr(unsafe.Pointer(swr_ctx)), "out_sample_fmt", dst_sample_fmt, 0)
/* initialize the resampling context */
ret = swr_ctx.SwrInit()
if ret < 0 {
fmt.Printf("Failed to initialize the resampling context\n")
goto end
}
/* allocate source and destination samples buffers */
src_nb_channels = libavutil.AvGetChannelLayoutNbChannels(uint64(src_ch_layout))
ret = libavutil.AvSamplesAllocArrayAndSamples(&src_data, &src_linesize, src_nb_channels,
src_nb_samples, src_sample_fmt, 0)
if ret < 0 {
fmt.Printf("Could not allocate source samples\n")
goto end
}
/* compute the number of converted samples: buffering is avoided
* ensuring that the output buffer will contain at least all the
* converted input samples */
dst_nb_samples = int32(libavutil.AvRescaleRnd(int64(src_nb_samples), int64(dst_rate), int64(src_rate), libavutil.AV_ROUND_UP))
max_dst_nb_samples = dst_nb_samples
/* buffer is going to be directly written to a rawaudio file, no alignment */
dst_nb_channels = libavutil.AvGetChannelLayoutNbChannels(uint64(dst_ch_layout))
ret = libavutil.AvSamplesAllocArrayAndSamples(&dst_data, &dst_linesize, dst_nb_channels,
dst_nb_samples, dst_sample_fmt, 0)
if ret < 0 {
fmt.Printf("Could not allocate destination samples\n")
goto end
}
t = 0
for {
/* generate synthetic audio */
fill_samples((*float64)(unsafe.Pointer(*src_data)), src_nb_samples, src_nb_channels, src_rate, &t)
/* compute destination number of samples */
dst_nb_samples = int32(libavutil.AvRescaleRnd(swr_ctx.SwrGetDelay(int64(src_rate))+
int64(src_nb_samples), int64(dst_rate), int64(src_rate), libavutil.AV_ROUND_UP))
if dst_nb_samples > max_dst_nb_samples {
libavutil.AvFreep(uintptr(unsafe.Pointer(dst_data)))
ret = libavutil.AvSamplesAlloc(dst_data, &dst_linesize, dst_nb_channels,
dst_nb_samples, dst_sample_fmt, 1)
if ret < 0 {
break
}
max_dst_nb_samples = dst_nb_samples
}
/* convert to destination format */
ret = swr_ctx.SwrConvert(dst_data, dst_nb_samples, src_data, src_nb_samples)
if ret < 0 {
fmt.Printf("Error while converting\n")
goto end
}
dst_bufsize = libavutil.AvSamplesGetBufferSize(&dst_linesize, dst_nb_channels,
ret, dst_sample_fmt, 1)
if dst_bufsize < 0 {
fmt.Printf("Could not get sample buffer size\n")
goto end
}
fmt.Printf("t:%f in:%d out:%d\n", t, src_nb_samples, ret)
dst_file.Write(ffcommon.ByteSliceFromByteP(*dst_data, int(dst_bufsize)))
if t < 10 {
} else {
break
}
}
ret = get_format_from_sample_fmt(&fmt0, dst_sample_fmt)
if ret < 0 {
goto end
}
fmt.Printf("Resampling succeeded. Play the output file with the command:\nffplay -f %s -channel_layout %d -channels %d -ar %d %s\n",
fmt0, dst_ch_layout, dst_nb_channels, dst_rate, dst_filename)
end:
dst_file.Close()
if src_data != nil {
libavutil.AvFreep(uintptr(unsafe.Pointer(src_data)))
}
libavutil.AvFreep(uintptr(unsafe.Pointer(&src_data)))
if dst_data != nil {
libavutil.AvFreep(uintptr(unsafe.Pointer(dst_data)))
}
libavutil.AvFreep(uintptr(unsafe.Pointer(&dst_data)))
libswresample.SwrFree(&swr_ctx)
if ret < 0 {
return 1
} else {
return 0
}
}
func get_format_from_sample_fmt(fmt0 *string, sample_fmt libavutil.AVSampleFormat) (ret ffcommon.FInt) {
switch sample_fmt {
case libavutil.AV_SAMPLE_FMT_U8:
*fmt0 = "u8"
case libavutil.AV_SAMPLE_FMT_S16:
*fmt0 = "s16le"
case libavutil.AV_SAMPLE_FMT_S32:
*fmt0 = "s32le"
case libavutil.AV_SAMPLE_FMT_FLT:
*fmt0 = "f32le"
case libavutil.AV_SAMPLE_FMT_DBL:
*fmt0 = "f64le"
default:
fmt.Printf("sample format %s is not supported as output format\n",
libavutil.AvGetSampleFmtName(sample_fmt))
ret = -1
}
return
}
/**
* Fill dst buffer with nb_samples, generated starting from t.
*/
func fill_samples(dst *ffcommon.FDouble, nb_samples, nb_channels, sample_rate ffcommon.FInt, t *ffcommon.FDouble) {
var i, j ffcommon.FInt
tincr := 1.0 / float64(sample_rate)
dstp := dst
c := 2 * libavutil.M_PI * 440.0
/* generate sin tone with 440Hz frequency and duplicated channels */
for i = 0; i < nb_samples; i++ {
*dstp = math.Sin(c * *t)
for j = 1; j < nb_channels; j++ {
*(*float64)(unsafe.Pointer(uintptr(unsafe.Pointer(dstp)) + uintptr(8*j))) = *dstp
}
dstp = (*ffcommon.FDouble)(unsafe.Pointer(uintptr(unsafe.Pointer(dstp)) + uintptr(8*nb_channels)))
*t += tincr
}
}
func main() {
os.Setenv("Path", os.Getenv("Path")+";./lib")
ffcommon.SetAvutilPath("./lib/avutil-56.dll")
ffcommon.SetAvcodecPath("./lib/avcodec-58.dll")
ffcommon.SetAvdevicePath("./lib/avdevice-58.dll")
ffcommon.SetAvfilterPath("./lib/avfilter-56.dll")
ffcommon.SetAvformatPath("./lib/avformat-58.dll")
ffcommon.SetAvpostprocPath("./lib/postproc-55.dll")
ffcommon.SetAvswresamplePath("./lib/swresample-3.dll")
ffcommon.SetAvswscalePath("./lib/swscale-5.dll")
genDir := "./out"
_, err := os.Stat(genDir)
if err != nil {
if os.IsNotExist(err) {
os.Mkdir(genDir, 0777) // Everyone can read write and execute
}
}
main0()
}

2023-04-30:用go语言重写ffmpeg的resampling_audio.c示例,它实现了音频重采样的功能。的更多相关文章
- Understand:高效代码静态分析神器详解(一) | 墨香博客 http://www.codemx.cn/2016/04/30/Understand01/
Understand:高效代码静态分析神器详解(一) | 墨香博客 http://www.codemx.cn/2016/04/30/Understand01/ ===== 之前用Windows系统,一 ...
- Ubuntu 12.04上安装R语言
Ubuntu 12.04上安装R语言 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ R的安装 sudo gedit /etc/apt/sources. ...
- new Date('2014/04/30') 和 new Date('2014-04-30') 的区别
new Date('2014/04/30') Wed Apr 30 2014 00:00:00 GMT+0800 (中国标准时间) new Date('2014-04-30'); Wed Apr 30 ...
- 记一次接口调试错误: {"timestamp":"2019-09-11T03:04:30.036+0000","status":500,"error":"Internal Server Error","message":"Could not write JSON: Object is null; nested exception is com.fasterxml.jackson
接口测试中用postman测试返回是正常的,但是使用其他人去调用就出错了,找了半天,才想起来使用了nginx,用于端口的代理转发.然后根据错误信息发现json格式的某个字段为null,结合日志中的报文 ...
- Ubuntu 18.04 安装配置 go 语言
Ubuntu 18.04 安装配置 go 语言 1.下载 下载 jdk 到 Downloands 文件夹下 cd 进入 /usr/local, 创建 go 文件夹, 然后 cd 进这个文件夹 cd / ...
- 最简单的基于FFmpeg的libswscale的示例(YUV转RGB)
===================================================== 最简单的基于FFmpeg的libswscale的示例系列文章列表: 最简单的基于FFmpeg ...
- Unity 利用FFmpeg实现录屏、直播推流、音频视频格式转换、剪裁等功能
目录 一.FFmpeg简介. 二.FFmpeg常用参数及命令. 三.FFmpeg在Unity 3D中的使用. 1.FFmpeg 录屏. 2.FFmpeg 推流. 3.FFmpeg 其他功能简述. 一. ...
- 最简单的基于FFmpeg的libswscale的示例附件:测试图片生成工具
===================================================== 最简单的基于FFmpeg的libswscale的示例系列文章列表: 最简单的基于FFmpeg ...
- FFmpeg进行视频帧提取&音频重采样-Process.waitFor()引发的阻塞超时
由于产品需要对视频做一系列的解析操作,利用FFmpeg命令来完成视频的音频提取.第一帧提取作为封面图片.音频重采样.字幕压缩等功能: 前一篇文章已经记录了FFmpeg在JAVA中的使用-音频提取&am ...
- FFMpeg笔记(三) 音频处理基本概念及音频重采样
Android放音的采样率固定为44.1KHz,录音的采样率固定为8KHz,因此底层的音频设备驱动需要设置好这两个固定的采样率.如果上层传过来的采样率不符的话,需要进行resample重采样处理. 几 ...
随机推荐
- vs2019配置boost库(转载)
网址:https://blog.csdn.net/qq_42214953/article/details/105087015 关于途中的执行文件,可以使用b2.exe,不用跟着教程走. 如果本来就有b ...
- 服务器中VirtualBox子网访问
本人常用的虚拟机软件是VirtualBox,由于笔记本性能,磁盘存储大下限制,以及VirtualBox客户机无法在多个设备间直接方便的使用等原因,我把几个虚拟的系统全部移动到便携式服务器中. 移动之后 ...
- day1 第一个程序“Hello world!”
程序运行机制 源程序(.java文件)->java编译器->字节码(.class文件)->类装载器->字节码校验器->解释器->操作系统平台Java源码后缀名:.j ...
- Swagger-ApiOperation-value属性
1.value属性设置 @ApiOperation(value="${province}.getUsers", notes="描述") Documentatio ...
- windows下配置JDK教程
1.思路: 首先要确定所要用的应用可以兼容哪个版本jdk,然后开始下载对应的版本,最后安装,配置环境变量,测试,部署完成. 2.jdk下载地址: 如果下载全新的jdk可以直接百度jdk官网下载 如果需 ...
- 提供离线chrome谷歌浏览器插件crx的网站有
crx4:http://www.crx4.com/ 极简插件:https://chrome.zzzmh.cn/index 扩展迷:https://www.extfans.com/ 浏览器插件下载中心: ...
- Python基础教程:字典
字典 = {'键1':'值1','键2':'值2','键3':'值3',...} animal_dict = {'Cow':'Milk','Chicken':'egg'} 字典由键值对构成,这种键值对 ...
- 打开CMD方式
打开CMD的方式 win+r 输入cmd 常用的Dos命令 1.#盘符切换2.#查看当前文件目录下的所有文件 dir3.#切换目录 cd change directory4.#cd .. 返回上级5. ...
- 【手搓模型】亲手实现 Vision Transformer
前言 博客主页:睡晚不猿序程 首发时间:2023.3.17,首发于博客园 最近更新时间:2023.3.17 本文由 睡晚不猿序程 原创 作者是蒻蒟本蒟,如果文章里有任何错误或者表述不清,请 tt 我, ...
- 90 条简单实用的 Python 编程技巧,建议收藏
编码原则 建议 1:理解 Pythonic 概念 -- 详见 Python 中的<Python 之禅> 建议 2:编写 Pythonic 代码 避免不规范代码,比如只用大小写区分变量.使用 ...