2023-04-30:用go语言重写ffmpeg的resampling_audio.c示例,它实现了音频重采样的功能。

news/2024/12/29 5:11:27/

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 mainimport ("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_STEREOvar dst_ch_layout ffcommon.FInt64T = libavutil.AV_CH_LAYOUT_SURROUNDvar src_rate ffcommon.FInt = 48000var dst_rate ffcommon.FInt = 44100var src_data, dst_data **ffcommon.FUint8Tvar src_nb_channels, dst_nb_channels ffcommon.FIntvar src_linesize, dst_linesize ffcommon.FIntvar src_nb_samples ffcommon.FInt = 1024var dst_nb_samples ffcommon.FIntvar max_dst_nb_samples ffcommon.FIntvar src_sample_fmt libavutil.AVSampleFormat = libavutil.AV_SAMPLE_FMT_DBLvar dst_sample_fmt libavutil.AVSampleFormat = libavutil.AV_SAMPLE_FMT_S16var dst_filename stringvar dst_file *os.Filevar dst_bufsize ffcommon.FIntvar fmt0 stringvar swr_ctx *libswresample.SwrContextvar t ffcommon.FDoubleif 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.ENOMEMgoto 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 = 0for {/* 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.FInttincr := 1.0 / float64(sample_rate)dstp := dstc := 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()
}

在这里插入图片描述


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

相关文章

mysql事务及搜索引擎

mysql事务后半部分 加快查询速度索引会自动排序&#xff0c;&#xff08;升序&#xff09; select * from t1&#xff1b;全盘扫描 where可以索引查找show create table 索引是一个排序的列表&#xff0c;包含字段值和相应行数据的物理地址 事务是一种机制&#xff0c;一个…

Spark大数据处理讲课笔记3.5 RDD持久化机制

文章目录 零、本讲学习目标一、RDD持久化&#xff08;一&#xff09;引入持久化的必要性&#xff08;二&#xff09;案例演示持久化操作1、RDD的依赖关系图2、不采用持久化操作3、采用持久化操作 二、存储级别&#xff08;一&#xff09;持久化方法的参数&#xff08;二&#x…

android log的使用

现在在分析一个android netd的问题&#xff0c;只要一开启热点&#xff0c; for (String ifname : added) {try {Log.d(TAG, "TetheredState, processMessage CMD_TETHER_CONNECTION_CHANGED, add mIfaceName " mIfaceName " ifname " ifname );mNetd.…

etcd的Watch原理

在 Kubernetes 中&#xff0c;各种各样的控制器实现了 Deployment、StatefulSet、Job 等功能强大的 Workload。控制器的核心思想是监听、比较资源实际状态与期望状态是否一致&#xff0c;若不一致则进行协调工作&#xff0c;使其最终一致。 那么当你修改一个 Deployment 的镜像…

蛋糕烘焙店小程序开发 让生活多点甜

蛋糕甜品因为较高的颜值、香甜的口感深受大众喜欢&#xff0c;当我们路过一家蛋糕烘焙店的时候&#xff0c;飘香的味道让我们流连忘返。但是互联网时代&#xff0c;各个行业都在转型&#xff0c;蛋糕烘焙店也需要由传统线下店面向线上线下结合的方式转变&#xff0c;以求摆脱区…

LeetCode 63 不同路径 II

题目&#xff1a; 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。现在考虑网格中有障碍物。那么从左…

Golang笔记:使用os.Args和flag包编写命令行界面(CLIs)

文章目录 目的os.ArgsflagFlagSet总结 目的 命令行界面&#xff08;Command-line Interfaces&#xff09;是比较常用的一种软件形式。对于大部分开发运维人员来说很多时候CLIs可能比图形界面更加方便。软件开发时也经常会有需要开发命令行界面形式软件的情况&#xff0c;使用G…

Highcharts Core Crack

Highcharts Core Crack 添加了新的“x轴交叉”和“y轴交叉”选项&#xff0c;使创建数学绘图的轴布局变得更容易。 添加了新的“series.legendSymbol”选项。 Highcharts是业界领先的JavaScript图表库。Highcharts被数以万计的开发人员和全球100家最大公司中超过80%的公司使用。…