2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
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的内部结构。的更多相关文章
- ffmpeg音频编码
在弄音频采集时,需要设置缓存的大小,如果只是简单的采集和直接播放PCM数据,缓存的大小一般不影响播放和保存. 但是,如果需要使用FFMpeg音频编码,这时,音频缓存的大小必须设置av_samples_ ...
- 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)
http://blog.csdn.net/leixiaohua1020/article/details/25430449 本文介绍一个最简单的基于FFMPEG的音频编码器.该编码器实现了PCM音频采样 ...
- Golang 优化之路——bitset
写在前面 开发过程中会经常处理集合这种数据结构,简单点的处理方法都是使用内置的map实现.但是如果要应对大量数据,例如,存放大量电话号码,使用map占用内存大的问题就会凸显出来.内存占用高又会带来一些 ...
- Contest2073 - 湖南多校对抗赛(2015.04.06)
Contest2073 - 湖南多校对抗赛(2015.04.06) Problem A: (More) Multiplication Time Limit: 1 Sec Memory Limit: ...
- http://www.liangxiansen.cn/2017/04/06/consul/
Consul 使用手册 | 一个梦 http://www.liangxiansen.cn/2017/04/06/consul/ 基于Consul的分布式锁实现 https://mp.weixin.qq ...
- 最简单的基于FFmpeg的编码器-纯净版(不包含libavformat)
===================================================== 最简单的基于FFmpeg的视频编码器文章列表: 最简单的基于FFMPEG的视频编码器(YUV ...
- ffmpeg 音频转换(amr2mp3)
yasm:http://yasm.tortall.net/Download.html(汇编器,新版本的ffmpeg增加了汇编代码) lame:http://lame.sourceforge.net/d ...
- ffmpeg 音频转码
大多数厂家摄像机输出的音频流格式都是PCM,有一些场合(比如讲音视频流保存成Ts流)需要将PCM格式转成AAC格式.基本的思路是先解码得到音频帧,再将音频帧编码成AAC格式.编码和解码之间需要添加一个 ...
- vmware虚拟机下ubuntu 13.04使用zeranoe脚本交叉编译ffmpeg
2013-07-01今天是建党节,习总书记指出,党的建设要以“照镜子.正衣冠.洗洗澡.治治病”为总要求.希望我们的党越来越纯洁,为人民谋福利.言归正传,每次项目中需要编译相应的ffmpeg,都很费时费 ...
- ffmpeg音频播放代码示例-avcodec_decode_audio4
一.概述 最近在学习ffmpeg解码的内容,参考了官方的教程http://dranger.com/ffmpeg/tutorial03.html,结果发现这个音频解码的教程有点问题.参考了各种博客,并同 ...
随机推荐
- windows监控web程序连接数
运行: win+R->perfmon.msc 右键,添加计数器 选择webservice中的current connection选项,再选中对应实例即可~
- VScode_Keter_自用
1.软件下载 支持win/linux/mac平台,安装有两种形式,根据个人喜好进行选择即可: 1.安装包 a.官网下载地址:https://code.visualstudio.com/ (速度慢) b ...
- bytes转化为字典
import requestsurl='https://su.ke.com/api/listtop?type=resblock&resblock_id=2311062653496924& ...
- 文本的格式化标签(粗体,斜体)和 <div>和<span>标签(都是双标签)
上一个笔记有提到各种型号的标题,为了保证文章的美观,又会有除了标题之外的东西,比如粗体,斜体,下划线,删除线和各种分隔 1加粗,<strong><strong/>或者<b ...
- gitee使用
1.github的国内跳转 github国内无法直接访问,所以直接使用gitee导入github工程 https://gitee.com/ 2.虚拟机配置ssh公钥 https://gitee ...
- DVWA-SQL Injection(SQL注入)
sql注入是典型.常见的Web漏洞之一,现在在网络中也可能存在,不过大多数为SQL盲注. 攻击者通过恶意的SQL语句来破坏SQL查询语句,达到数据库泄露的目的 LOW 审计源码 <?php // ...
- Android笔记--Application
Application生命周期 在APP运行过程中有且仅有一个Application对象贯穿整个生命周期 Application全局变量 实例化: 声明全局变量:
- Android笔记--文本显示
文本显示 设置文本内容 方式一: 在.xml文件中利用android:text属性设置文本 新创建一个.xml文件示范一下: 方式二: 在java代码中调用文本视图对象的setText方法设置文本 还 ...
- 基于 Agora SDK 实现 iOS 端的多人视频互动
视频互动直播是当前比较热门的玩法,我们经常见到有PK 连麦.直播答题.一起 KTV.电商直播.互动大班课.视频相亲等. 本文将教你如何通过声网Agora 视频 SDK 在iOS端实现一个视频直播应用. ...
- 记一次 .NET 某设备监控系统 死锁分析
一:背景 1. 讲故事 上周看了一位训练营朋友的dump,据朋友说他的程序卡死了,看完之后发现是一例经典的死锁问题,蛮有意思,这个案例算是学习 .NET高级调试 入门级的案例,这里和大家分享一下. 二 ...