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重采样处理. 几 ...
随机推荐
- docker学习随笔
总结自https://zhuanlan.zhihu.com/p/187505981 Linux内核提供了Namespace技术来隔离PID/IPC/网络资源等,还提供了Control Group(cg ...
- SSRF Server-Side Request Forgery(服务器端请求伪造)
什么是SSRF? 犹如其名,SSRF(Server-Side Request Forgery)服务端请求伪造,攻击者可以控制服务器返回的页面,借用服务器的权限访问无权限的页面. 这是一个允许恶意用户导 ...
- Spring--依赖注入:setter注入和构造器注入
依赖注入:描述了在容器中建立Bean于Bean之间依赖关系的过程 setter注入 在本来已经在service里面引用了bean的相关方法的基础上,再引用之前已经写过的userDao的对象,即在ser ...
- MySQL Mock大量数据做查询响应测试
上个迭代版本发布后,生产环境业务同事反馈仓配订单查询的页面加载时间过长. 因为页面原来是有的,这次开发是在原来基础上改的,因此没有额外做性能.测试环境只调用接口请求了少量数据去验证功能.在对比该迭代添 ...
- salesforce零基础学习(一百二十七)Custom Metadata Type 篇二
本篇参考: salesforce零基础学习(一百一十一)custom metadata type数据获取方式更新 https://developer.salesforce.com/docs/atlas ...
- 使用 Agora SDK 开发 React Native 视频通话App
在 React Native 的应用中,从头开始添加视频通话功能是很复杂的.要保证低延迟.负载平衡,还要注意管理用户事件状态,非常繁琐.除此之外,还必须保证跨平台的兼容性. 当然有个简单的方法可以做到 ...
- BootstrapBlazor + FreeSql ORM 实战 Table 表格组件维护多表数据 - OneToOne
OneToOne 垂直扩展表字段是很常见的方法, 主表存商品资料, 分表存每个客户对应商品的备注和个性化的价格等等, 本文使用Blazor一步步实现这个简单的需求. 1. 基于实战 10分钟编写数据库 ...
- springboot实现验证码功能
实现验证码功能 先在utils包下创建一个ValidateImageCodeUtils.class package com.wfszmg.demo.utils; import javax.imagei ...
- 【JVM盲点补漏系列】「并发编程的难题和挑战」深入理解JMM及JVM内存模型知识体系
并发编程的难题和挑战 在并发编程的技术领域中,对于我们而言的难题主要有两个: 多线程之间如何进行通信和线程之间如何同步,通信是指线程之间以何种机制来交换信息. 多线程的线程通信机制 在命令式编程中,线 ...
- react中的虚拟DOM,jsx,diff算法。让代码更高效
在react中当你的状态发生改变时,并不是所有组件的内容销毁再重建,能复用的就复用 react 组件其实 就是按照层级划分的 找到两棵任意的树之间最小的修改是一个复杂度为 O(n^3) 的问题. 你可 ...