2023-04-15:ffmpeg的filter_audio.c的功能是生成一个正弦波音频,然后通过简单的滤镜链,最后输出数据的MD5校验和。请用go语言改写。

答案2023-04-15:

代码见github/moonfdd/ffmpeg-go库。

以下是通过 Go 语言重新实现 ffmpeg 的 filter_audio.c 功能的步骤:

  1. 导入必要的依赖包和定义常量和变量。

  2. 初始化 FFmpeg 库文件路径。

  3. 创建一个音频滤镜图,并将 abuffer、volume 和 aformat 滤镜连接起来。其中,abuffer 滤镜用于获取输入音频采样,volume 滤镜用于调节音频音量,aformat 滤镜用于设置输出音频格式。

  4. 创建输出音频流的 AVCodecContext 上下文,并设置相关属性。

  5. 使用 avcodec_find_encoder_by_name 函数查找 PCM S16LE 编码器,然后创建编码器的 AVCodec 上下文。

  6. 打开编码器并写入头部信息。

  7. 循环读取音频帧,将其发送到音频滤镜图进行处理。

  8. 从滤镜图中获取输出音频帧,并将其编码为 PCM S16LE 格式。

  9. 计算输出音频帧的 MD5 校验和,并将其打印到标准输出上。

  10. 释放资源,结束程序运行。

以上就是使用 Go 语言对 filter_audio.c 文件进行重新实现的步骤。

命令如下:

go run ./examples/internalexamples/filter_audio/main.go 1

go代码如下:

package main

import (
"fmt"
"math"
"os"
"strconv"
"unsafe" "github.com/moonfdd/ffmpeg-go/ffcommon"
"github.com/moonfdd/ffmpeg-go/libavfilter"
"github.com/moonfdd/ffmpeg-go/libavutil"
) func main0() (ret ffcommon.FInt) {
var md5 *libavutil.AVMD5
var graph *libavfilter.AVFilterGraph
var src, sink *libavfilter.AVFilterContext
var frame *libavutil.AVFrame
var errstr [1024]ffcommon.FUint8T
var duration ffcommon.FFloat
var err, nb_frames, i ffcommon.FInt if len(os.Args) < 2 {
fmt.Printf("Usage: %s <duration>\n", os.Args[0])
return 1
} f, err2 := strconv.ParseFloat(os.Args[1], 32)
if err2 != nil {
// handle error
return 1
}
duration = float32(f)
nb_frames = int32(float64(duration) * INPUT_SAMPLERATE / FRAME_SIZE)
if nb_frames <= 0 {
fmt.Printf("Invalid duration: %s\n", os.Args[1])
return 1
} /* Allocate the frame we will be using to store the data. */
frame = libavutil.AvFrameAlloc()
if frame == nil {
fmt.Printf("Error allocating the frame\n")
return 1
} md5 = libavutil.AvMd5Alloc()
if md5 == nil {
fmt.Printf("Error allocating the MD5 context\n")
return 1
} /* Set up the filtergraph. */
err = init_filter_graph(&graph, &src, &sink)
if err < 0 {
fmt.Printf("Unable to init filter graph:")
goto fail
} /* the main filtering loop */
for i = 0; i < nb_frames; i++ {
// /* get an input frame to be filtered */
err = get_input(frame, i)
if err < 0 {
fmt.Printf("Error generating input frame:")
goto fail
} /* Send the frame to the input of the filtergraph. */
err = src.AvBuffersrcAddFrame(frame)
if err < 0 {
frame.AvFrameUnref()
fmt.Printf("Error submitting the frame to the filtergraph:")
goto fail
} /* Get all the filtered output that is available. */
err = sink.AvBuffersinkGetFrame(frame)
for err >= 0 {
/* now do something with our filtered frame */
err = process_output(md5, frame)
if err < 0 {
fmt.Printf("Error processing the filtered frame:")
goto fail
}
frame.AvFrameUnref()
err = sink.AvBuffersinkGetFrame(frame)
} if err == -libavutil.EAGAIN {
/* Need to feed more frames in. */
continue
} else if err == libavutil.AVERROR_EOF {
/* Nothing more to do, finish. */
break
} else if err < 0 {
/* An error occurred. */
fmt.Printf("Error filtering the data:")
goto fail
}
} libavfilter.AvfilterGraphFree(&graph)
libavutil.AvFrameFree(&frame)
libavutil.AvFreep(uintptr(unsafe.Pointer(&md5))) return 0 fail:
libavutil.AvStrerror(err, (*byte)(unsafe.Pointer(&errstr)), uint64(len(errstr)))
fmt.Printf("%s\n", errstr)
return 1
} const INPUT_SAMPLERATE = 48000
const INPUT_FORMAT = libavutil.AV_SAMPLE_FMT_FLTP
const INPUT_CHANNEL_LAYOUT = libavutil.AV_CH_LAYOUT_5POINT0 const VOLUME_VAL = 0.90 func init_filter_graph(graph **libavfilter.AVFilterGraph, src **libavfilter.AVFilterContext,
sink **libavfilter.AVFilterContext) ffcommon.FInt {
var filter_graph *libavfilter.AVFilterGraph
var abuffer_ctx *libavfilter.AVFilterContext
var abuffer *libavfilter.AVFilter
var volume_ctx *libavfilter.AVFilterContext
var volume *libavfilter.AVFilter
var aformat_ctx *libavfilter.AVFilterContext
var aformat *libavfilter.AVFilter
var abuffersink_ctx *libavfilter.AVFilterContext
var abuffersink *libavfilter.AVFilter var options_dict *libavutil.AVDictionary
var options_str string
var ch_layout [64]ffcommon.FUint8T var err ffcommon.FInt /* Create a new filtergraph, which will contain all the filters. */
filter_graph = libavfilter.AvfilterGraphAlloc()
if filter_graph == nil {
fmt.Printf("Unable to create filter graph.\n")
return libavutil.ENOMEM
} /* Create the abuffer filter;
* it will be used for feeding the data into the graph. */
abuffer = libavfilter.AvfilterGetByName("abuffer")
if abuffer == nil {
fmt.Printf("Could not find the abuffer filter.\n")
return libavutil.AVERROR_FILTER_NOT_FOUND
} abuffer_ctx = filter_graph.AvfilterGraphAllocFilter(abuffer, "src")
if abuffer_ctx == nil {
fmt.Printf("Could not allocate the abuffer instance.\n")
return -libavutil.ENOMEM
} /* Set the filter options through the AVOptions API. */
libavutil.AvGetChannelLayoutString((*byte)(unsafe.Pointer(&ch_layout)), int32(len(ch_layout)), 0, INPUT_CHANNEL_LAYOUT)
libavutil.AvOptSet(uintptr(unsafe.Pointer(abuffer_ctx)), "channel_layout", ffcommon.StringFromPtr(uintptr(unsafe.Pointer(&ch_layout))), libavutil.AV_OPT_SEARCH_CHILDREN)
libavutil.AvOptSet(uintptr(unsafe.Pointer(abuffer_ctx)), "sample_fmt", libavutil.AvGetSampleFmtName(INPUT_FORMAT), libavutil.AV_OPT_SEARCH_CHILDREN)
libavutil.AvOptSetQ(uintptr(unsafe.Pointer(abuffer_ctx)), "time_base", libavutil.AVRational{1, INPUT_SAMPLERATE}, libavutil.AV_OPT_SEARCH_CHILDREN)
libavutil.AvOptSetInt(uintptr(unsafe.Pointer(abuffer_ctx)), "sample_rate", INPUT_SAMPLERATE, libavutil.AV_OPT_SEARCH_CHILDREN) /* Now initialize the filter; we pass NULL options, since we have already
* set all the options above. */
err = abuffer_ctx.AvfilterInitStr("")
if err < 0 {
fmt.Printf("Could not initialize the abuffer filter.\n")
return err
} /* Create volume filter. */
volume = libavfilter.AvfilterGetByName("volume")
if volume == nil {
fmt.Printf("Could not find the volume filter.\n")
return libavutil.AVERROR_FILTER_NOT_FOUND
} volume_ctx = filter_graph.AvfilterGraphAllocFilter(volume, "volume")
if volume_ctx == nil {
fmt.Printf("Could not allocate the volume instance.\n")
return -libavutil.ENOMEM
} /* A different way of passing the options is as key/value pairs in a
* dictionary. */
libavutil.AvDictSet(&options_dict, "volume", fmt.Sprint(VOLUME_VAL), 0)
err = volume_ctx.AvfilterInitDict(&options_dict)
libavutil.AvDictFree(&options_dict)
if err < 0 {
fmt.Printf("Could not initialize the volume filter.\n")
return err
} /* Create the aformat filter;
* it ensures that the output is of the format we want. */
aformat = libavfilter.AvfilterGetByName("aformat")
if aformat == nil {
fmt.Printf("Could not find the aformat filter.\n")
return libavutil.AVERROR_FILTER_NOT_FOUND
} aformat_ctx = filter_graph.AvfilterGraphAllocFilter(aformat, "aformat")
if aformat_ctx == nil {
fmt.Printf("Could not allocate the aformat instance.\n")
return -libavutil.ENOMEM
} /* A third way of passing the options is in a string of the form
* key1=value1:key2=value2.... */
// snprintf(options_str, sizeof(options_str),
// "sample_fmts=%s:sample_rates=%d:channel_layouts=0x%"PRIx64,
// av_get_sample_fmt_name(AV_SAMPLE_FMT_S16), 44100,
// (uint64_t)AV_CH_LAYOUT_STEREO);
options_str = fmt.Sprintf("sample_fmts=%s:sample_rates=%d:channel_layouts=0x%x",
libavutil.AvGetSampleFmtName(libavutil.AV_SAMPLE_FMT_S16), 44100,
libavutil.AV_CH_LAYOUT_STEREO)
fmt.Println(options_str)
err = aformat_ctx.AvfilterInitStr(options_str)
if err < 0 {
libavutil.AvLog(uintptr(0), libavutil.AV_LOG_ERROR, "Could not initialize the aformat filter.\n")
return err
} /* Finally create the abuffersink filter;
* it will be used to get the filtered data out of the graph. */
abuffersink = libavfilter.AvfilterGetByName("abuffersink")
if abuffersink == nil {
fmt.Printf("Could not find the abuffersink filter.\n")
return libavutil.AVERROR_FILTER_NOT_FOUND
} abuffersink_ctx = filter_graph.AvfilterGraphAllocFilter(abuffersink, "sink")
if abuffersink_ctx == nil {
fmt.Printf("Could not allocate the abuffersink instance.\n")
return -libavutil.ENOMEM
} /* This filter takes no options. */
err = abuffersink_ctx.AvfilterInitStr("")
if err < 0 {
fmt.Printf("Could not initialize the abuffersink instance.\n")
return err
} /* Connect the filters;
* in this simple case the filters just form a linear chain. */
err = abuffer_ctx.AvfilterLink(0, volume_ctx, 0)
if err >= 0 {
err = volume_ctx.AvfilterLink(0, aformat_ctx, 0)
}
if err >= 0 {
err = aformat_ctx.AvfilterLink(0, abuffersink_ctx, 0)
}
if err < 0 {
fmt.Printf("Error connecting filters\n")
return err
} /* Configure the graph. */
err = filter_graph.AvfilterGraphConfig(uintptr(0))
if err < 0 {
libavutil.AvLog(uintptr(0), libavutil.AV_LOG_ERROR, "Error configuring the filter graph\n")
return err
} *graph = filter_graph
*src = abuffer_ctx
*sink = abuffersink_ctx return 0
} /* Do something useful with the filtered data: this simple
* example just prints the MD5 checksum of each plane to stdout. */
func process_output(md5 *libavutil.AVMD5, frame *libavutil.AVFrame) ffcommon.FInt {
planar := libavutil.AvSampleFmtIsPlanar(libavutil.AVSampleFormat(frame.Format))
channels := libavutil.AvGetChannelLayoutNbChannels(frame.ChannelLayout)
planes := channels
if planar == 0 {
planes = 1
}
bps := libavutil.AvGetBytesPerSample(libavutil.AVSampleFormat(frame.Format))
plane_size := bps * frame.NbSamples
if planar == 0 {
plane_size = plane_size * channels
}
var i, j ffcommon.FInt for i = 0; i < planes; i++ {
var checksum [16]ffcommon.FUint8T md5.AvMd5Init()
ptr := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(frame.ExtendedData)) + uintptr(i*8)))
libavutil.AvMd5Sum((*byte)(unsafe.Pointer(&checksum)), (*byte)(unsafe.Pointer(ptr)), plane_size) fmt.Printf("plane %d: 0x", i)
for j = 0; j < int32(len(checksum)); j++ {
fmt.Printf("%02X", checksum[j])
}
fmt.Printf("\n")
}
fmt.Printf("\n") return 0
} const FRAME_SIZE = 1024 /* Construct a frame of audio data to be filtered;
* this simple example just synthesizes a sine wave. */
func get_input(frame *libavutil.AVFrame, frame_num ffcommon.FInt) ffcommon.FInt {
var err, i, j ffcommon.FInt // #define FRAME_SIZE 1024 /* Set up the frame properties and allocate the buffer for the data. */
frame.SampleRate = INPUT_SAMPLERATE
frame.Format = INPUT_FORMAT
frame.ChannelLayout = INPUT_CHANNEL_LAYOUT
frame.NbSamples = FRAME_SIZE
frame.Pts = int64(frame_num) * FRAME_SIZE err = frame.AvFrameGetBuffer(0)
if err < 0 {
return err
} /* Fill the data for each channel. */
for i = 0; i < 5; i++ {
// float *data = (float*)frame->extended_data[i];
ptr := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(frame.ExtendedData)) + uintptr(i*8)))
data := (*ffcommon.FFloat)(unsafe.Pointer(ptr)) for j = 0; j < frame.NbSamples; j++ {
*(*ffcommon.FFloat)(unsafe.Pointer(uintptr(unsafe.Pointer(data)) + uintptr(4*j))) = float32(math.Sin(2 * libavutil.M_PI * (float64(frame_num + j)) * float64((i+1)/FRAME_SIZE)))
}
} return 0
} func main() {
// go run ./examples/internalexamples/filter_audio/main.go 1
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-7.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-15:ffmpeg的filter_audio.c的功能是生成一个正弦波音频,然后通过简单的滤镜链,最后输出数据的MD5校验和。请用go语言改写。的更多相关文章

  1. ubuntu12.04&15.04 安装lamp(12.04为主)

    ubuntu 12.04&15.04下安装lamp环境 注意:如果是ubuntu15.04下,apache2.4.10的话,直接在/etc/apache2/apache2.conf文件的后边直 ...

  2. 新手学习FFmpeg - 通过API完成filter-complex功能

    本篇尝试通过API实现Filter Graph功能. 源码请参看 https://andy-zhangtao.github.io/ffmpeg-examples/ FFmpeg提供了很多实用且强大的滤 ...

  3. 工作记录--使用FFmpeg将一个视频文件中音频合成到另一个视频中

    由于工作需要,临时被老大吩咐去研究一个FFmpeg工具,通过linux命令行去将一个视频中的音频提取出来并合成到另一个视频中,最终的效果是要保证2个视频中的音频都在一个视频中播放. 但是本人对FFmp ...

  4. ffmpeg实现视频文件合并/截取预览视频/抽取音频/crop(裁剪)(ffmpeg4.2.2)

    一,ffmpeg的安装 请参见: https://www.cnblogs.com/architectforest/p/12807683.html 说明:刘宏缔的架构森林是一个专注架构的博客,地址:ht ...

  5. (转)Ubuntu10.04编译FFmpeg

    刚开始安装折腾了好久,很多软件包都找不到,可能是跟软件源有关,所以先说一下我的软件源: 软件源是用的中国默认的官方源http://cn.archive.ubuntu.com/ubuntu/ 一.安装编 ...

  6. 在 Ubuntu 14.04/15.04 上配置 Node JS v4.0.0

    大家好,Node.JS 4.0 发布了,这个流行的服务器端 JS 平台合并了 Node.js 和 io.js 的代码,4.0 版就是这两个项目结合的产物——现在合并为一个代码库.这次最主要的变化是 N ...

  7. ubuntu 14.04/15.10 安装基于eclipse的android app开发环境

    一开始是装了ubuntu15.10,不知道是我的x200机器太old还是iso镜像有问题,总是各种莫名的引导不起来.有时候刚刚装好的干净系统,只install了一个vim和openssh,重启,然后就 ...

  8. LeetCode 周赛 342(2023/04/23)容斥原理、计数排序、滑动窗口、子数组 GCB

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 大家好,我是小彭. 前天刚举办 2023 年力扣杯个人 SOLO 赛,昨天周赛就出了一场 Easy - Ea ...

  9. RTP、RTCP协议学习-2015.04.15

    最近做视频编解码部分,传输采用RTP协议.对学习做个记录 1.简介 实时传输协议(Real-time Transport Protocol或简写RTP)是一个网络传输协议,它是由IETF的多媒体传输工 ...

  10. FAQ-Ubuntu12.04 15.04禁止移动介质自动播放

    网上有有很多关于Ubuntu10.04关闭移动介质自动播放的方法,包括在文件管理器里面设置或者使用gconf-editor,但是从12.04开始这两种方法都不再好用了,关于移动介质的处理方法被移到了S ...

随机推荐

  1. 读书笔记<<世界是部金融史>>

    1.权力只对来源负责.权力只会对其来源负责--孟德斯鸠<论法的精神> 2.能违反的是纪律,不能违反的是规律.人自然要遵从人性规律. 3.在金融市场中有一个法则,如果市场认为一件事是真的,那 ...

  2. windows2003 DHCP服务器配置

    一.导入光驱 二.安装可选的windows组件 三.双击打开网路服务,安装DHCP/DNS服务器. 注:服务器地址要固定,因此安装时要规划好网络. 四.ip地址范围规划时要预留i出一些p地址.排除ip ...

  3. 11.3 shtctl的指定省略(harib08c)

    ps:能力有限,若有错误及纰漏欢迎指正.交流 11.3 shtctl的指定省略(harib08c) 对bootpack.h做了如下改动 struct SHEET { unsigned char *bu ...

  4. Kustomize 生产实战-注入监控 APM Agent

    Kustomize 简介 Kubernetes 原生配置管理工具, 它自定义引入了一种无需模板的方式来定制应用程序配置,从而简化了对现成应用程序的使用.目前,在kubectl中内置了,通过 apply ...

  5. 【CS231n assignment 2022】Assignment 2 - Part 2,优化器,批归一化以及层归一化

    前言 博客主页:睡晚不猿序程 首发时间:2022.7.23 最近更新时间:2022.7.23 本文由 睡晚不猿序程 原创 作者是蒻蒟本蒟,如果文章里有任何错误或者表述不清,请 tt 我,万分感谢!or ...

  6. CentOS7环境下数据库运维---主从复制、读写分离

    1.理解MySQL主从复制原理 主服务器开启binlog日志,从库生成log dump线程,将binlog日志传给从库I/O线程,从库生成俩个线程,一个是I/O线程,一个是SQL线程,I/O线程去请主 ...

  7. MapReduce Shuffle源码解读

    MapReduce Shuffle源码解读 相信很多小伙伴都背过shuffle的八股文,但一直不是很理解shuffle的过程,这次我通过源码来解读下shuffle过程,加深对shuffle的理解,但是 ...

  8. 1.HVV介绍

    HVV介绍 1.护网职责划分 红队:打点人员.攻击人员.社工人员 蓝队:监控人员.研判人员.溯源人员 2.护网需要具备的技能 红队: 外围打点能力.漏洞挖掘能力.漏洞分析能力.权限提升能力.权限维持能 ...

  9. 机器学习基础05DAY

    分类算法之k-近邻 k-近邻算法采用测量不同特征值之间的距离来进行分类 优点:精度高.对异常值不敏感.无数据输入假定 缺点:计算复杂度高.空间复杂度高 使用数据范围:数值型和标称型 一个例子弄懂k-近 ...

  10. 利用Karlibr生成April标定板图像

    1 关键的命令 rosrun kalibr kalibr_create_target_pdf --type apriltag --nx 6 --ny 6 --tsize 0.02 --tspace 0 ...