当前位置: 首页 > article >正文

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()
}

在这里插入图片描述


http://www.kler.cn/a/15738.html

相关文章:

  • 动态规划-完全背包问题——322.零钱兑换
  • 8.C++面向对象5(实现一个较为完善的日期类)
  • 华为Ensp模拟器配置RIP路由协议
  • 营销手段的变革:开源 AI 智能名片与 S2B2C 商城小程序在新趋势下的机遇与挑战
  • eBPF on Go
  • 高级数据结构——hash表与布隆过滤器
  • 在全志V851S开发板上使用SSH配置步骤分析
  • 前端小白是如何利用chatgt用一周时间从做一款微信小程序的
  • 【MATLAB数据处理实用案例详解(15)】——利用BP神经网络实现个人信贷信用评估
  • 零基础想成为黑客,只需要四步
  • CF662C Binary Table
  • nvm安装使用详解,附gnvm介绍
  • 史上最全的接口测试,吐血整理从零到接口自动化实战...
  • 1992-2022年31省人均gdp/各省人均地区生产总值
  • @PostConstruct注解和@PreDestroy注解
  • 【AI生产力工具】Upscale.media:用AI技术提升照片质量,让你的作品更出色
  • 【LeetCode股票买卖系列:121. 买卖股票的最佳时机 | 一次遍历 | 暴力递归=>记忆化搜索=>动态规划】
  • 系统集成项目管理工程师 笔记(第19章:项目收尾管理)
  • 【5G RRC】RSRP、RSRQ以及SINR含义、计算过程详细介绍
  • 如何在Linkedin领英上找客户
  • VsCode镜像下载(国内镜像源,高速秒下)
  • 博世中国创新软件开发中心 BCSC
  • vue生命周期代码示范--Vue基本介绍--MVVM-示意图--数据渲染--事件绑定--修饰符--组件化--和全部代码示范
  • Python高级函数1:使用 map()、reduce()、filter()、zip() 和 enumerate() 简化代码
  • 【云台】开源版本SimpleBGC的电机驱动与控制方式
  • iVX开发中整理的常见问题与回答(三)