2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。
2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。
答案2023-03-12:
用github/moonfdd/ffmpeg-go库。
命令如下:
go run ./examples/a15.audio_decode_mp32pcm/main.go
代码参考了15:mp3音频解码为pcm,代码用golang编写。如下:
package main
import (
"fmt"
"os"
"os/exec"
"unsafe"
"github.com/moonfdd/ffmpeg-go/ffcommon"
"github.com/moonfdd/ffmpeg-go/libavcodec"
"github.com/moonfdd/ffmpeg-go/libavformat"
"github.com/moonfdd/ffmpeg-go/libavutil"
)
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
}
}
inVFileName := "./out/test.mp3"
outFileName := "./out/test.pcm"
// ./lib/ffmpeg -i ./resources/big_buck_bunny.mp4 -acodec libmp3lame -vn ./out/test.mp3
//是否存在mp3文件
_, err = os.Stat(inVFileName)
if err != nil {
if os.IsNotExist(err) {
fmt.Println("create mp3 file")
exec.Command("./lib/ffmpeg", "-i", "./resources/big_buck_bunny.mp4", "-acodec", "libmp3lame", "-vn", inVFileName, "-y").CombinedOutput()
}
}
os.Remove(outFileName)
f, err := os.OpenFile(outFileName, os.O_CREATE|os.O_RDWR, 0777)
if err != nil {
fmt.Println("open file failed,err:", err)
return
}
fmtCtx := libavformat.AvformatAllocContext()
var codecCtx *libavcodec.AVCodecContext
pkt := libavcodec.AvPacketAlloc()
frame := libavutil.AvFrameAlloc()
aStreamIndex := -1
for {
if libavformat.AvformatOpenInput(&fmtCtx, inVFileName, nil, nil) < 0 {
fmt.Printf("Cannot open input file.\n")
break
}
if fmtCtx.AvformatFindStreamInfo(nil) < 0 {
fmt.Printf("Cannot find stream info in input file.\n")
break
}
fmtCtx.AvDumpFormat(0, inVFileName, 0)
//查找视频流在文件中的位置
for i := uint32(0); i < fmtCtx.NbStreams; i++ {
if fmtCtx.GetStream(i).Codecpar.CodecType == libavutil.AVMEDIA_TYPE_AUDIO {
aStreamIndex = int(i)
break
}
}
if aStreamIndex == -1 {
fmt.Printf("Cannot find audio stream.\n")
return
}
aCodecPara := fmtCtx.GetStream(uint32(aStreamIndex)).Codecpar
codec := libavcodec.AvcodecFindDecoder(aCodecPara.CodecId)
if codec == nil {
fmt.Printf("Cannot find any codec for audio.\n")
return
}
codecCtx = codec.AvcodecAllocContext3()
if codecCtx.AvcodecParametersToContext(aCodecPara) < 0 {
fmt.Printf("Cannot alloc codec context.\n")
return
}
codecCtx.PktTimebase = fmtCtx.GetStream(uint32(aStreamIndex)).TimeBase
if codecCtx.AvcodecOpen2(codec, nil) < 0 {
fmt.Printf("Cannot open audio codec.\n")
return
}
for (fmtCtx.AvReadFrame(pkt)) >= 0 {
if pkt.StreamIndex == uint32(aStreamIndex) {
if codecCtx.AvcodecSendPacket(pkt) >= 0 {
for codecCtx.AvcodecReceiveFrame(frame) >= 0 {
/*
Planar(平面),其数据格式排列方式为 (特别记住,该处是以点nb_samples采样点来交错,不是以字节交错):
LLLLLLRRRRRRLLLLLLRRRRRRLLLLLLRRRRRRL...(每个LLLLLLRRRRRR为一个音频帧)
而不带P的数据格式(即交错排列)排列方式为:
LRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL...(每个LR为一个音频样本)
*/
if libavutil.AvSampleFmtIsPlanar(codecCtx.SampleFmt) != 0 {
numBytes := libavutil.AvGetBytesPerSample(codecCtx.SampleFmt)
//pcm播放时是LRLRLR格式,所以要交错保存数据
bytes := []byte{}
for i := int32(0); i < frame.NbSamples; i++ {
for ch := int32(0); ch < codecCtx.Channels; ch++ {
ptr := uintptr(unsafe.Pointer(uintptr(unsafe.Pointer(frame.Data[ch])) + uintptr(numBytes*i)))
for k := int32(0); k < numBytes; k++ {
bytes = append(bytes, *(*byte)(unsafe.Pointer(ptr)))
ptr++
}
}
}
f.Write(bytes)
}
}
}
}
pkt.AvPacketUnref()
}
break
}
libavutil.AvFrameFree(&frame)
libavcodec.AvPacketFree(&pkt)
codecCtx.AvcodecClose()
libavcodec.AvcodecFreeContext(&codecCtx)
fmtCtx.AvformatFreeContext()
f.Close()
fmt.Println("-----------------------------------------")
// ./lib/ffplay -ar 22050 -ac 2 -f f32le -i ./out/test.pcm
_, err = exec.Command("./lib/ffplay.exe", "-ar", "22050", "-ac", "2", "-f", "f32le", "-i", "./out/test.pcm").Output()
if err != nil {
fmt.Println("play err = ", err)
}
}

2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。的更多相关文章
- HTML5 audio 如何实现播放多个MP3音频
<audio>标签是HTML5中的新标签,定义声音用于嵌入音频内容,比如音乐或其他音频流.用的比较多音频格式是.mp3. <audio>标签常用属性如下表 属性 值 描述 au ...
- FFmpeg 裁剪——音频解码
配置ffmpeg,只留下某些音频的配置: ./configure --enable-shared --disable-yasm --enable-memalign-hack --enable-gpl ...
- EasyDarwin开源音频解码项目EasyAudioDecoder:EasyPlayer Android音频解码库(第二部分,封装解码器接口)
上一节我们讲了如何基于ffmpeg-Android工程编译安卓上的支持音频的ffmpeg静态库:http://blog.csdn.net/xiejiashu/article/details/52524 ...
- Python 爬取所有51VOA网站的Learn a words文本及mp3音频
Python 爬取所有51VOA网站的Learn a words文本及mp3音频 #!/usr/bin/env python # -*- coding: utf-8 -*- #Python 爬取所有5 ...
- 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)
http://blog.csdn.net/leixiaohua1020/article/details/25430449 本文介绍一个最简单的基于FFMPEG的音频编码器.该编码器实现了PCM音频采样 ...
- MP3 编码解码 附完整c代码
近期一直不间断学习音频处理,一直也没想着要去碰音频编解码相关. 主要是觉得没什么实际的作用和意义. 不管视频编解码,图像编解码,音频编解码,都有很多组织基金在推动. 当然,在一些特定的情景下,需要用起 ...
- EasyDarwin开源音频解码项目EasyAudioDecoder:基于ffmpeg的安卓音频(AAC、G726)解码库(第一部分,ffmpeg-android的编译)
ffmpeg是一套开源的,完整的流媒体解决方案.基于它可以很轻松构建一些强大的应用程序.对于流媒体这个行业,ffmpeg就像圣经一样的存在.为了表达敬意,在这里把ffmpeg官网的一段简介搬过来,ff ...
- ffmpeg学习笔记-音频解码
在之前的文章已经初步对视频解码有个初步的认识了,接下来来看一看音频解码 音频解码步骤 音频解码与视频解码一样,有者固有的步骤,只要按照步骤来,就能顺利的解码音频 以上是ffmpeg的解码流程图,可以看 ...
- html5 录制mp3音频,支持采样率和比特率设置
13年的时候做过html5录音,一个问题是保存的wav格式文件很大,当初用了一个迂回的方式,上传到服务器后调用 lame 编码器转换,但由于文件大,上传较慢.不得不说,前端技术发展真是日新月异,有人实 ...
- FFmpeg - 音频解码过程
1. 注册所有解码器 av_register_all(); 2. Codec & CodecContext AVCodec* codec = avcodec_find_decoder(CODE ...
随机推荐
- python print 一个进度条
import time scale=100 print("执行开始".center(scale+28,'-')) start = time.perf_counter() for i ...
- python去除前中后多处空格的方法
x=" asdf ada都 是 年 费 sdf sf " print("".join(x.split())) 测试全角半角空格都没有了
- https传输流程(加密方式、证书、传输安全)
http的缺点 http的数据是明文传输 如果用明文传输 很容易被第三方获取到传输的数据 因此我们一般要在网络传输过程中对数据进行加密 常见的加密方式 对称加密 秘钥key 待加密数据data a和b ...
- windows下创建虚拟环境
创建虚拟环境依赖以下两个模块 virtualenv 和virtualenvwrapper-win 1.下载 2.修改环境变量,增加一条 WORKON_HOME:路径 3. 同步配置 去向Pytho ...
- VS工具显示小技巧,显示内联参数
工具---选项---文本编辑器---C#---高级---在显示内联参数名称提示前面打勾. 则可以在代码中看到参数提示信息.
- python创建线程传参误区记录
创建线程可以使用threading模块中的Thread子类: 其中Thread子类允许的参数如下: (self, group=None, target=None, name=None, args=() ...
- 陈大好:持续创造小而美的产品丨独立开发者 x 开放麦
本文内容来自RTE NG-Lab 计划中「独立开发者 x 开放麦」活动分享,分享嘉宾独立开发者 @陈大好. 本次活动中,来自 W2solo 独立开发者社区的管理员 @Eric Woo 也以<独立 ...
- 2PC(两阶段提交)【XA 与 Seata方案】
更多内容,前往 IT-BLOG 一.概述 2PC(two phase commit protocol,2PC)即两阶段提交协议,是将整个事务流程分为两个阶段,准备阶段(Prepare phase).提 ...
- Neo4j常用操作——Cypher查询语言
1. 删除数据库中以往的图,确保一个空白的环境进行操作: MATCH (n) DETACH DELETE n # 要想删除数据库的话直接删除文件即可 2. 创建一个人物节点: CREATE (n:Pe ...
- 更优雅的OrientDB Java API
OrientDB API v1.0.0(OrientDB 3.x) Gitee OrientDB介绍 OrientDB是一个开源的NoSQL数据库管理系统,同时也是一款高性能的图数据库,支持ACID事 ...