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 ...
随机推荐
- [复现]2021 DASCTF X BUUOJ 五月大联动-PWN
[复现]2021 DASCTF X BUUOJ 五月大联动 由于我没ubuntu16就不复现第一个题了,直接第二个 正常的off by one from pwn import * context.os ...
- margin:auto实现盒子水平垂直居中
margin:auto为什么不垂直居中 margin:auto是具有强烈计算意味的关键字,用来计算元素对应方向上应该获得的剩余空间大小. 行内元素margin:auto; 不能水平居中在一行的中央位置 ...
- python中的反射机制
转自https://www.cnblogs.com/renjie1105/p/15909285.html python反射简介 在做程序开发中,我们常常会遇到这样的需求:需要执行对象里的某个方法,或需 ...
- OSPF故障诊断
- Windows 下TCP长连接保持连接状态TCP keepalive设置
TCP长连接建立完成后,我们通常需要检测网络的连接状态,以反馈给客户做响应的处理.通过设置TCP keepalive的属性,打开socket的keepalive属性,并设置发送底层心跳包的时间间隔.T ...
- SpringBoot整合RocketMQ案例实战
一.概念 rocketMQ是一款典型的分布式架构下的中间件产品,使用异步通信方式和发布订阅的消息传输模型,具备异步通信的优势,系统拓扑简单,上下游耦合较弱,主要应用于异步解耦,流量削峰填谷等场景 二. ...
- 如何自动化测试你的接口?—— Rest Assured
前言 不知道大家的项目是否都有对接口API进行自动化测试,反正像我们这种小公司是没有的.由于最近一直被吐槽项目质量糟糕,只能研发自己看看有什么接口测试方案.那么在本文中,我将探索如何使用 Rest A ...
- os模块的使用方法详解
os模块 os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口:即os模块提供了非常丰富的方法用来处理文件和目录. 使用的时候需要导入该模块:import os 常用方法如下: 方法名 作用 ...
- IDEA编写JSP无代码提示
网上的版本 网上的版本 网上的我试了 但是未能解决 我自己解决的方法是 File => Poject Struct=>Modules=>"+"=>找到自己系 ...
- LinkedBlockingQueue出入队实现原理
类图概述 由类图可以看出,L是单向链表实现的,有两个ReentrantLock实例用来控制元素入队和出队的原子性,takeLock用来控制只有一个线程可以从队头获取元素,putLock控制只有一个线程 ...