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重采样处理. 几 ...
随机推荐
- Jmeter之post上传文件(jmeter接口测试请求参数上传文件)
一,上传excel等普通文件 接口测试时有接口文档的话,那就对着文档写,没api文档,就自己抓包看了. 接口文档 抓包查看 步骤一:接口请求切换至文件上传(Files Upload)栏 content ...
- SQL 2019 卸载方法
一.关闭服务 1. win+r services.msc 打开服务,关闭与SQL有关的服务内容. 二.卸载应用 1.win+r control 打开控制面板---卸载程序---卸 ...
- F - Substring of Sorted String
题目链接 题解(树状数组) 我们维护两个树状数组,一个记录 \(1\sim i\) 中 \(s_i>s_{i+1}\)的数量,即逆序对数量,另一个记录 \(1\sim i\) 中 \(26\) ...
- 错误:为仓库 'appstream' 下载元数据失败 : Cannot prepare internal mirrorlist: No URLs in mirrorlist
sudo sed -i -e "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* sudo sed -i -e &qu ...
- MySQL如何指定字符集和排序规则?
在MySQL中,可以使用以下两种方式指定字符集和排序规则: 创建数据库或表时指定字符集和排序规则 在创建数据库或表时,可以使用 CHARACTER SET 和 COLLATE 选项指定字符集和排序规则 ...
- Zip Slip漏洞审计实战
前言 最近看到许少的推有说到Zip Slip这个漏洞导致的RCE,其实我在代码审计的时候确实发现有不少功能模块都是使用ZIP来解压,其实还是在真实系统中经常见到的. 于是想着好久没有写过博客了,想借着 ...
- easy-poi 一对多导出
参考博客:https://blog.csdn.net/qq_31984879/article/details/102715335
- 53.cin、cin.get()、cin.getline()、getline()、gets()等函数的用法
1.cin 用法1:最基本,也是最常用的用法,输入一个数字: #pragma warning(disable:4996) #define _CRT_SECURE_NO_WARNINGS 1 #incl ...
- 三天吃透Spring Cloud面试八股文
本文已经收录到Github仓库,该仓库包含计算机基础.Java基础.多线程.JVM.数据库.Redis.Spring.Mybatis.SpringMVC.SpringBoot.分布式.微服务.设计模式 ...
- MyBatis缓存机制[NO]
前言 MyBatis是常见的Java数据库访问层框架.在日常工作中,开发人员多数情况下是使用MyBatis的默认缓存配置,但是MyBatis缓存机制有一些不足之处,在使用中容易引起脏数据,形成一些潜在 ...