2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。

答案2023-04-06:

见moonfdd/ffmpeg-go库。

这段代码是一个示例程序,用于将音频 PCM 数据编码为 MP2 格式的音频文件。下面是代码的详细步骤:

1.导入 ffmpeg-go 和 os 等 Go 库;

2.定义一些变量,包括输出文件名、音频编解码器、音频编解码上下文、音频帧、音频数据包等;

3.查找 MP2 编码器并分配音频编解码上下文;

4.配置音频编解码参数,设置音频采样率、通道数、位率等;

5.打开音频编解码器;

6.创建输出文件;

7.开始编码过程,并将编码后的音频数据写入输出文件中。

具体地,编码过程包括以下几个步骤:

1.初始化音频帧;

2.将音频 PCM 数据填充到音频帧中;

3.发送音频帧到编解码器中进行编码;

4.从编解码器中读取编码后的音频数据包;

5.将编码后的音频数据包写入输出文件中。

最后,释放内存空间并关闭文件和编码器。在该示例程序中,我们需要手动设置 FFmpeg 库的路径,以便正确加载库文件。

命令如下:

go run ./examples/internalexamples/encode_audio/main.go ./out/encode_audio.mp2

./lib/ffplay ./out/encode_audio.mp2

golang代码如下:

package main

import (
"fmt"
"math"
"os"
"unsafe" "github.com/moonfdd/ffmpeg-go/ffcommon"
"github.com/moonfdd/ffmpeg-go/libavcodec"
"github.com/moonfdd/ffmpeg-go/libavutil"
) func main0() (ret ffcommon.FInt) {
var filename string
var codec *libavcodec.AVCodec
var c *libavcodec.AVCodecContext
var frame *libavutil.AVFrame
var pkt *libavcodec.AVPacket
var i, j, k ffcommon.FInt
var f *os.File
var samples *ffcommon.FUint16T
var t, tincr ffcommon.FFloat if len(os.Args) <= 1 {
fmt.Printf("Usage: %s <output file>\n", os.Args[0])
return 0
}
filename = os.Args[1] /* find the MP2 encoder */
codec = libavcodec.AvcodecFindEncoder(libavcodec.AV_CODEC_ID_MP2)
if codec == nil {
fmt.Printf("Codec not found\n")
os.Exit(1)
} c = codec.AvcodecAllocContext3()
if c == nil {
fmt.Printf("Could not allocate audio codec context\n")
os.Exit(1)
} /* put sample parameters */
c.BitRate = 64000 /* check that the encoder supports s16 pcm input */
c.SampleFmt = libavutil.AV_SAMPLE_FMT_S16
if check_sample_fmt(codec, c.SampleFmt) == 0 {
fmt.Printf("Encoder does not support sample format %s",
libavutil.AvGetSampleFmtName(c.SampleFmt))
os.Exit(1)
} /* select other audio parameters supported by the encoder */
c.SampleRate = select_sample_rate(codec)
c.ChannelLayout = uint64(select_channel_layout(codec))
c.Channels = libavutil.AvGetChannelLayoutNbChannels(c.ChannelLayout) /* open it */
if c.AvcodecOpen2(codec, nil) < 0 {
fmt.Printf("Could not open codec\n")
os.Exit(1)
} f, _ = os.Create(filename)
if f == nil {
fmt.Printf("Could not open %s\n", filename)
os.Exit(1)
} /* packet for holding encoded output */
pkt = libavcodec.AvPacketAlloc()
if pkt == nil {
fmt.Printf("could not allocate the packet\n")
os.Exit(1)
} /* frame containing input raw audio */
frame = libavutil.AvFrameAlloc()
if frame == nil {
fmt.Printf("Could not allocate audio frame\n")
os.Exit(1)
} frame.NbSamples = c.FrameSize
frame.Format = int32(c.SampleFmt)
frame.ChannelLayout = c.ChannelLayout /* allocate the data buffers */
ret = frame.AvFrameGetBuffer(0)
if ret < 0 {
fmt.Printf("Could not allocate audio data buffers\n")
os.Exit(1)
} /* encode a single tone sound */
t = 0
tincr = float32(2 * libavutil.M_PI * 440.0 / float64(c.SampleRate))
for i = 0; i < 200; i++ {
/* make sure the frame is writable -- makes a copy if the encoder
* kept a reference internally */
ret = frame.AvFrameMakeWritable()
if ret < 0 {
os.Exit(1)
}
samples = (*ffcommon.FUint16T)(unsafe.Pointer(frame.Data[0])) for j = 0; j < c.FrameSize; j++ {
*(*ffcommon.FUint16T)(unsafe.Pointer(uintptr(unsafe.Pointer(samples)) + uintptr(2*j*2))) = ffcommon.FUint16T(math.Sin(float64(t)) * 10000) for k = 1; k < c.Channels; k++ {
*(*ffcommon.FUint16T)(unsafe.Pointer(uintptr(unsafe.Pointer(samples)) + uintptr((2*j+k)*2))) = *(*ffcommon.FUint16T)(unsafe.Pointer(uintptr(unsafe.Pointer(samples)) + uintptr(2*j*2)))
}
t += tincr
}
encode(c, frame, pkt, f)
} /* flush the encoder */
encode(c, nil, pkt, f) f.Close() libavutil.AvFrameFree(&frame)
libavcodec.AvPacketFree(&pkt)
libavcodec.AvcodecFreeContext(&c) return 0
} /* check that a given sample format is supported by the encoder */
func check_sample_fmt(codec *libavcodec.AVCodec, sample_fmt libavutil.AVSampleFormat) ffcommon.FInt {
p := codec.SampleFmts for *p != libavutil.AV_SAMPLE_FMT_NONE {
if *p == sample_fmt {
return 1
}
p = (*libavutil.AVSampleFormat)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + uintptr(8)))
}
return 0
} /* just pick the highest supported samplerate */
func select_sample_rate(codec *libavcodec.AVCodec) ffcommon.FInt {
var p *ffcommon.FInt
var best_samplerate ffcommon.FInt if codec.SupportedSamplerates == nil {
return 44100
} p = codec.SupportedSamplerates
for *p != 0 {
if best_samplerate == 0 || int32(math.Abs(float64(44100-*p))) < int32(math.Abs(float64(44100-best_samplerate))) {
best_samplerate = *p
}
p = (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + uintptr(4)))
}
return best_samplerate
} /* select layout with the highest channel count */
func select_channel_layout(codec *libavcodec.AVCodec) ffcommon.FInt { var p *ffcommon.FUint64T
var best_ch_layout ffcommon.FUint64T
var best_nb_channels ffcommon.FInt if codec.ChannelLayouts == nil {
return libavutil.AV_CH_LAYOUT_STEREO
} p = codec.ChannelLayouts
for *p != 0 {
nb_channels := libavutil.AvGetChannelLayoutNbChannels(*p) if nb_channels > best_nb_channels {
best_ch_layout = *p
best_nb_channels = nb_channels
}
p = (*uint64)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + uintptr(8)))
}
return ffcommon.FInt(best_ch_layout)
} func encode(ctx *libavcodec.AVCodecContext, frame *libavutil.AVFrame, pkt *libavcodec.AVPacket, output *os.File) {
var ret ffcommon.FInt /* send the frame for encoding */
ret = ctx.AvcodecSendFrame(frame)
if ret < 0 {
fmt.Printf("Error sending the frame to the encoder\n")
os.Exit(1)
} /* read all the available output packets (in general there may be any
* number of them */
for ret >= 0 {
ret = ctx.AvcodecReceivePacket(pkt)
if ret == -libavutil.EAGAIN || ret == libavutil.AVERROR_EOF {
return
} else if ret < 0 {
fmt.Printf("Error encoding audio frame\n")
os.Exit(1)
} output.Write(ffcommon.ByteSliceFromByteP(pkt.Data, int(pkt.Size)))
pkt.AvPacketUnref()
}
} 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-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。的更多相关文章

  1. ffmpeg音频编码

    在弄音频采集时,需要设置缓存的大小,如果只是简单的采集和直接播放PCM数据,缓存的大小一般不影响播放和保存. 但是,如果需要使用FFMpeg音频编码,这时,音频缓存的大小必须设置av_samples_ ...

  2. 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)

    http://blog.csdn.net/leixiaohua1020/article/details/25430449 本文介绍一个最简单的基于FFMPEG的音频编码器.该编码器实现了PCM音频采样 ...

  3. Golang 优化之路——bitset

    写在前面 开发过程中会经常处理集合这种数据结构,简单点的处理方法都是使用内置的map实现.但是如果要应对大量数据,例如,存放大量电话号码,使用map占用内存大的问题就会凸显出来.内存占用高又会带来一些 ...

  4. Contest2073 - 湖南多校对抗赛(2015.04.06)

    Contest2073 - 湖南多校对抗赛(2015.04.06) Problem A: (More) Multiplication Time Limit: 1 Sec  Memory Limit:  ...

  5. http://www.liangxiansen.cn/2017/04/06/consul/

    Consul 使用手册 | 一个梦 http://www.liangxiansen.cn/2017/04/06/consul/ 基于Consul的分布式锁实现 https://mp.weixin.qq ...

  6. 最简单的基于FFmpeg的编码器-纯净版(不包含libavformat)

    ===================================================== 最简单的基于FFmpeg的视频编码器文章列表: 最简单的基于FFMPEG的视频编码器(YUV ...

  7. ffmpeg 音频转换(amr2mp3)

    yasm:http://yasm.tortall.net/Download.html(汇编器,新版本的ffmpeg增加了汇编代码) lame:http://lame.sourceforge.net/d ...

  8. ffmpeg 音频转码

    大多数厂家摄像机输出的音频流格式都是PCM,有一些场合(比如讲音视频流保存成Ts流)需要将PCM格式转成AAC格式.基本的思路是先解码得到音频帧,再将音频帧编码成AAC格式.编码和解码之间需要添加一个 ...

  9. vmware虚拟机下ubuntu 13.04使用zeranoe脚本交叉编译ffmpeg

    2013-07-01今天是建党节,习总书记指出,党的建设要以“照镜子.正衣冠.洗洗澡.治治病”为总要求.希望我们的党越来越纯洁,为人民谋福利.言归正传,每次项目中需要编译相应的ffmpeg,都很费时费 ...

  10. ffmpeg音频播放代码示例-avcodec_decode_audio4

    一.概述 最近在学习ffmpeg解码的内容,参考了官方的教程http://dranger.com/ffmpeg/tutorial03.html,结果发现这个音频解码的教程有点问题.参考了各种博客,并同 ...

随机推荐

  1. JS和PHP中能转为布尔false的值的对比

    实际开发中经常会使用到JS和PHP中的变量转布尔值进行条件判断,下面对两种语言中转布尔类型结果为false的值进行对比,加深记忆和方便引用. 除了下表列出项,其它的值均转成真值true . 转布尔值后 ...

  2. Git 小技巧:忽略某些文件的更改

    *以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「ENG八戒」https://mp.weixin.qq.com/s/dp9Mwq7vf0ASF_FftBN8Ww 作为一枚合格的代码贡献 ...

  3. Zip Slip漏洞审计实战

    前言 最近看到许少的推有说到Zip Slip这个漏洞导致的RCE,其实我在代码审计的时候确实发现有不少功能模块都是使用ZIP来解压,其实还是在真实系统中经常见到的. 于是想着好久没有写过博客了,想借着 ...

  4. python内置函数len()

    len() len()函数用于返回对象(字符串.元组.列表和字典等)的长度或元素个数 len()函数的语法: len(s) 代码示例 print(len(range(10))) print(len([ ...

  5. 网络基础-OSI七层模型

    什么是OSI模型 OSI模型(或 Open Systems Interconnection Model开放系统互连模型)是网络中使用的绝对基础模型.这个关键模型提供了一个框架,规定所有联网设备将如何发 ...

  6. 工良出品:包教会,Hadoop、Hive 搭建部署简易教程

    目录 导读 Hadoop.Hive 是什么 运行环境 Java 环境 Mysql 下载 Hadoop.Hive 和 驱动 安装 Hadoop core-site.xml hdfs-site.xml m ...

  7. 使用 DeepSpeed 和 Hugging Face 🤗 Transformer 微调 FLAN-T5 XL/XXL

    Scaling Instruction-Finetuned Language Models 论文发布了 FLAN-T5 模型,它是 T5 模型的增强版.FLAN-T5 由很多各种各样的任务微调而得,因 ...

  8. Solon2 接口开发: 分布式 Api Gateway 开发预览

    建议使用专业的分布式网关产品,比如: nginx apisix [推荐] k8s ingress controller 等... 对 Solon 来讲,只有 Gateway:它调用本地接口时,则为本地 ...

  9. 11.getshell常见思路与技巧

    getshell常见思路与技巧 1.常规打点思路 信息收集: 绕开CDN找到所有靶标的真实IP 找到所有目标真实的C段 对所有的C段进行基础服务器的探测,端口的扫描.识别 对所有目标的子域名进行收集 ...

  10. 9.SSRF和XML

    SSRF和XML 目录 SSRF和XML SSRF介绍 SSRF漏洞挖掘 SSRF漏洞利用 内网探测: 常见端口探测: 协议探测: file协议敏感文件: XML介绍 DTD定义 DTD作用 XXE介 ...