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. windows监控web程序连接数

    运行: win+R->perfmon.msc 右键,添加计数器 选择webservice中的current connection选项,再选中对应实例即可~

  2. VScode_Keter_自用

    1.软件下载 支持win/linux/mac平台,安装有两种形式,根据个人喜好进行选择即可: 1.安装包 a.官网下载地址:https://code.visualstudio.com/ (速度慢) b ...

  3. bytes转化为字典

    import requestsurl='https://su.ke.com/api/listtop?type=resblock&resblock_id=2311062653496924& ...

  4. 文本的格式化标签(粗体,斜体)和 <div>和<span>标签(都是双标签)

    上一个笔记有提到各种型号的标题,为了保证文章的美观,又会有除了标题之外的东西,比如粗体,斜体,下划线,删除线和各种分隔 1加粗,<strong><strong/>或者<b ...

  5. gitee使用

    1.github的国内跳转 github国内无法直接访问,所以直接使用gitee导入github工程 https://gitee.com/     2.虚拟机配置ssh公钥 https://gitee ...

  6. DVWA-SQL Injection(SQL注入)

    sql注入是典型.常见的Web漏洞之一,现在在网络中也可能存在,不过大多数为SQL盲注. 攻击者通过恶意的SQL语句来破坏SQL查询语句,达到数据库泄露的目的 LOW 审计源码 <?php // ...

  7. Android笔记--Application

    Application生命周期 在APP运行过程中有且仅有一个Application对象贯穿整个生命周期 Application全局变量 实例化: 声明全局变量:

  8. Android笔记--文本显示

    文本显示 设置文本内容 方式一: 在.xml文件中利用android:text属性设置文本 新创建一个.xml文件示范一下: 方式二: 在java代码中调用文本视图对象的setText方法设置文本 还 ...

  9. 基于 Agora SDK 实现 iOS 端的多人视频互动

    视频互动直播是当前比较热门的玩法,我们经常见到有PK 连麦.直播答题.一起 KTV.电商直播.互动大班课.视频相亲等. 本文将教你如何通过声网Agora 视频 SDK 在iOS端实现一个视频直播应用. ...

  10. 记一次 .NET 某设备监控系统 死锁分析

    一:背景 1. 讲故事 上周看了一位训练营朋友的dump,据朋友说他的程序卡死了,看完之后发现是一例经典的死锁问题,蛮有意思,这个案例算是学习 .NET高级调试 入门级的案例,这里和大家分享一下. 二 ...