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

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

时间:2023-04-30 22:55:41浏览次数:36  
标签:libavutil 04 示例 dst 30 samples ffcommon src nb

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

在这里插入图片描述

标签:libavutil,04,示例,dst,30,samples,ffcommon,src,nb
From: https://www.cnblogs.com/waitmoon/p/17365914.html

相关文章

  • 每日总结2023-04-30
    今天学习了kotlin中的点击时间loginButton.setOnClickListener{//loginButton为botton名valauthSuccessful:Boolean=viewModel.authenticate(usernameEditText.text.toString(),passwordEditText.text.toString())if(authSucces......
  • flower in 4.30
    有人要求我日更鲜花就来更新了。大概是没人看的吧?彁这个字确实是可以打出来的。我放歌的心路历程大多数时候取决于我当时的精神状态,然后在比较符合的里边找几个应该能放出来的(指带人声的)。比如说比较魔怔的时候就放个脑力)不得不说写这个是有好处的,最起码可以保证语言组织能力不......
  • 《聪明》2023.4.30
    Inaworldgoneshallow在这逐渐流于肤浅的世界里Inaworldgonelean在这缓慢倾斜的宇宙洪流中Sometimesthere'sthingsamancannotknow有些事有时候是人们无法得知的Gearswon'tturnandtheleaveswon'tgrow齿轮无法转动,树叶停止生长——《StayAlive》José......
  • C/C++《程序设计基础II》[2023-04-30]
    C/C++《程序设计基础II》[2023-04-30]2022级计算机专业《程序设计基础II》小组项目作业作业要求:1.分小组完成,2-4人一组(每个题目后面有人数要求,见附件1);2.任课老师按小组分配任务;3.作业时长为1周;4.提交内容为:WORD文档,内容包括:题目内容、算法分析、代码实现(要求加注释)、运行结......
  • 2023-4-30 #52.75 如果再次试着踏上 那条轨迹不可改变的结局
    Ptz2022SummerDay4IvanKazmenkoContest3B:若\(n\)为奇数,我们只需取补集;否则我们保留\(n\)是否存在,并将\(2\cdotsn\)取反(std做法:插入删除\(1\))。D:信息量只有\(2^{70}\)级别,将值域分为\(70\)块,每个块分别决定是否保留所有数,一个块期望会有比较多的数,被失真后仍......
  • oop题目集04-06总结性blog
    oop题目集04*菜单计价程序-3*有重复的数据*去掉重复的数据*单词统计与排序*面向对象编程(封装性)*GPS测绘中度分秒转换*判断两个日期的先后,计算间隔天数、周数 oop题目集05*正则表达式训练-QQ号校验 * 字符串训练-字符排序*正则表达式训练-验证码校验* 正则表达式......
  • 04、安全管理
    一、安全管理功能从广义上讲,安全管理功能需要在高级负责人的指导下建立、实施和监控信息安全程序(InformationSecurityProgram)。安全管理涉及多个层次,不同级别的管理利用各类专家的专业知识、权威和资源为整体安全计划做出贡献。首席信息安全官(CISO):全面负责企业的信息安全程序,......
  • OOP训练集04-06总结(22201237-周琪)
    一、前言  在本次Blog必须分析题目集4的7-1、题目集5的7-5、7-6,题目集6的7-1,而这四道题目都是比较难的题目,除这四道题之外的题目,还会再总结几道踩坑较多、难度相对较低的题目。关于此次Blog需要总结的题目集的难度,总体来说还是比较大的,相较于之前的题目集,难度提升了很多,在之......
  • COMP30023远程调用程序
    COMP30023Project2RemoteProcedureCallOutdate:28April2023Duedate:Nolaterthan3pmFriday19May,2023AESTWeight:15%ofthefinalmark1ProjectOverviewRemoteProcedureCall(RPC)isacrucialtechnologyindistributedcomputingthatenablessof......
  • 义中常规赛430题解
    T1二分一个删除的数字个数然后考虑删除的数字肯定是从大到小来的,所以预处理一个降序的数组,这样能知道二分的数字个数所对应的数字。在原数组上跑最大子段和,如果碰到大于二分位置的数字就删了。最终成绩26分,因为对于二分的个数mid,原数组中a[mid]不止1个的话,无法判断哪些该删,哪......