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. 关于Android开发工具的下载之ADT篇

    ADT的下载 首先可以选择下面推荐的两个网站去下载相应的安装包,网址如下: http://tools.android-studio.org/index.php/adt-bundle-plugin 或者 ...

  2. 微软出品自动化神器【Playwright+Java】系列(十二)测试框架的设计与开发

    一.前言 大家好,我是六哥! 又有好长一段时间没更文了,不是我懒,而是确实在更文上,没有以前积极了,这里是该自我检讨的. 其实不是我不积极,而是相对更文学习来说,优先级不是最高. 对我而言,目前最重要 ...

  3. 全网最详细中英文ChatGPT接口文档(三)30分钟快速入门ChatGPT——资源库

    目录 Python library(Python库) Node.js library(Node.js库) Community libraries 社区图书馆 C# / .NET Crystal Go ...

  4. protobuf 详解

    protobuf protobuf概述 protobuf简介 Protobuf是Protocol Buffers的简称,它是Google公司开发的一种数据描述语言,是一种轻便高效的结构化数据存储格式, ...

  5. Linux下学习FPGA

    声明(叠甲):鄙人水平有限,本文章仅供参考. 1.环境 推荐使用 Ubuntu20.04这是我使用多个版本中最好用的一个,相关安装教程可以自行上网搜索这不再赘述,但要补充的一点的是源推荐使用中科大的源 ...

  6. AlphaFold2中的残基刚体表示

    技术背景 在前面的这一篇博客中,比较全面的介绍了组成蛋白质的各种氨基酸的三维结构.由于每个氨基酸大小不一,在传统的蛋白质折叠预测的方案中,一般会考虑全原子方案或者是粗粒化方案.对于全原子方案而言,即时 ...

  7. 配置 RSTP

    实验1-5-2 配置 RSTP [实验名称] 配置 RSTP. [实验目的] 理解快速生成树协议 RSTP 的配置及原理. [背景描述] 某学校为了开展计算机教学和网络办公,建立了一个计算机教室和一个 ...

  8. Windows7卡在正在关机

    据我的分析,Windows系统卡在正在关机的原因很大可能性是破解过系统主题.解决方法就是还原成主题未被破解时候的状态.但是这种情况是随机性的,但是可以确定的是,只要是破解过系统主题,都有一定概率关不了 ...

  9. MySQL事务还没提交,Canal就能读到消息了?

    [问题描述] 开发有天碰到一个很奇怪的问题,他的场景是这样子的: 通过Canal来订阅MySQL的binlog, 当捕获到有数据变化时,回到数据库,反查该数据的明细,然后做进一步处理. 有一次,他碰到 ...

  10. odoo 开发入门教程系列-模型之间的关系(Relations Between Models)

    模型之间的关系(Relations Between Models) 上一章介绍了为包含基本字段的模型创建自定义视图.然而,在任何真实的业务场景中,我们都需要不止一个模型.此外,模型之间的链接是必要的. ...