目录

前言

环境部署

代码

总结


前言

最近对golang处理音视频很感兴趣,对golang音视频常用库goav进行了一番研究。自己写了一个wav转采样率的功能。给大家分享一下,中间遇到了不少坑,解决的过程中还是蛮有意思的。

环境部署

代码运行在Ubuntu环境上,需要使用到goav,goav是对ffmpeg源码的golang封装。

goav地址:https://github.com/giorgisio/goav

goav安装如下

sudo apt-get -y install autoconf automake build-essential libass-dev libfreetype6-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texi2html zlib1g-devsudo apt install -y libavdevice-dev libavfilter-dev libswscale-dev libavcodec-dev libavformat-dev libswresample-dev libavutil-devsudo apt-get install yasmexport FFMPEG_ROOT=$HOME/ffmpeg
export CGO_LDFLAGS="-L$FFMPEG_ROOT/lib/ -lavcodec -lavformat -lavutil -lswscale -lswresample -lavdevice -lavfilter"
export CGO_CFLAGS="-I$FFMPEG_ROOT/include"
export LD_LIBRARY_PATH=$HOME/ffmpeg/lib
``` ```
go get github.com/xueqing/goav

代码

先看代码

package main//#include<stdlib.h>
import "C"
import ("flag""fmt""github.com/google/logger""github.com/xueqing/ffmpeg-demo/logutil""github.com/xueqing/goav/libswresample""github.com/youpy/go-wav""io""os""reflect""unsafe"
)func main() {var (inputUrl      string = "./data/1.wav"inNumChannels int64  = 1inSampleRate  int    = 16000//inBitsPerSample  uint16                    = 16outNumChannels   int64                     = 1outSampleRate    int                       = 48000outBitsPerSample uint16                    = 16swr              *libswresample.SwrContext = libswresample.SwrAlloc())flag.Parse()logutil.Init(true, false, "resample.log")defer logutil.Close()swr.SwrAllocSetOpts(outNumChannels,libswresample.AvSampleFormat(1),outSampleRate,inNumChannels,libswresample.AvSampleFormat(1),inSampleRate,0,0)swr.SwrInit()defer swr.SwrClose()_inputFile, err := os.Open(inputUrl)if err != nil {logger.Errorf("open input file error(%v)", err)return}defer _inputFile.Close()_reader := wav.NewReader(_inputFile)format, err := _reader.Format()if err != nil {logger.Errorf("input file format error(%v)", err)return}fmt.Printf("input file format info -> AudioFormat:%v,NumChannels:%v,SampleRate:%v,ByteRate:%v,BlockAlign:%v,BitsPerSample:%v", int(format.AudioFormat), format.NumChannels, format.SampleRate, format.ByteRate, format.BlockAlign, format.BitsPerSample)_tempFile, err := os.CreateTemp("", "*.wav")if err != nil {logger.Errorf("create temp file error(%v)", err)return}logger.Infof("Create tempFile %v", _tempFile.Name())defer func() {_tempFile.Close()}()_samples := []wav.Sample{}n := 4096for {spls, err := _reader.ReadSamples(uint32(n))if err == io.EOF {break}_samples = append(_samples, spls...)}_result := ResampleByFFmpegApi2(swr, _samples)_writer := wav.NewWriter(_tempFile, uint32(len(_result)), uint16(outNumChannels), uint32(outSampleRate), outBitsPerSample)err4 := _writer.WriteSamples(_result)if err4 != nil {logger.Errorf("write file error(%v)", err4)err = err4return}
}func ResampleByFFmpegApi2(swr *libswresample.SwrContext, samples []wav.Sample) []wav.Sample {var (_inArr  **uint8_outArr **uint8_inptr  []uint16_outptr []uint16)_inArr = (**uint8)(C.malloc(C.sizeof_int))defer C.free(unsafe.Pointer(_inArr))_inptr = make([]uint16, len(samples))_outArr = (**uint8)(C.malloc(C.sizeof_int))defer C.free(unsafe.Pointer(_outArr))_outptr = make([]uint16, len(samples)*3)//fmt.Println(unsafe.Sizeof(uint16(0)))for i, v := range samples {_inptr[i] = uint16(v.Values[0])}*_inArr = (*uint8)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&_inptr)).Data))*_outArr = (*uint8)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&_outptr)).Data))ret := swr.SwrConvert(_outArr, len(samples)*3, _inArr, len(samples))if ret > 0 {fmt.Println(ret)}_result := make([]wav.Sample, ret)for i := 0; i < ret; i++ {_result[i] = wav.Sample{[2]int{int(_outptr[i]), 0}}}return _result
}

代码说明:

1、代码不是个工具方法,如果看懂逻辑的话,可以自行修改成工具方法。

2、里面会用到ffmpeg里面swresample库,对音频数据进行冲采样。

3、可以细看一下,如果你想作实时处理也是可以改的。

4、其中SwrAllocSetOpts方法中有个参数libswresample.AvSampleFormat(1),为什么取1,这里主要是选择采样表示方式的枚举,参考底层源码枚举,我发在下面。我这边因为音频是s16的,所以选择1。

enum AVSampleFormat {AV_SAMPLE_FMT_NONE = -1,AV_SAMPLE_FMT_U8,          ///< unsigned 8 bitsAV_SAMPLE_FMT_S16,         ///< signed 16 bitsAV_SAMPLE_FMT_S32,         ///< signed 32 bitsAV_SAMPLE_FMT_FLT,         ///< floatAV_SAMPLE_FMT_DBL,         ///< doubleAV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planarAV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planarAV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planarAV_SAMPLE_FMT_FLTP,        ///< float, planarAV_SAMPLE_FMT_DBLP,        ///< double, planarAV_SAMPLE_FMT_S64,         ///< signed 64 bitsAV_SAMPLE_FMT_S64P,        ///< signed 64 bits, planarAV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};

音频准备,输入音频为16k采样率音频。

(base) xxx@hu:~/GolandProjects/MediaRelay/data$ ffmpeg -i 1.wav 
ffmpeg version 4.2.7-0ubuntu0.1 Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
  configuration: --prefix=/usr --extra-version=0ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
Guessed Channel Layout for Input Stream #0.0 : mono
Input #0, wav, from '1.wav':
  Metadata:
    date            : 2020-09-28
    encoder         : Lavf58.45.100
  Duration: 00:04:01.75, bitrate: 256 kb/s
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, mono, s16, 256 kb/s

执行情况

input file format info -> AudioFormat:1,NumChannels:1,SampleRate:16000,ByteRate:32000,BlockAlign:2,BitsPerSample:16INFO : 2022/12/06 17:14:49.937547 csdn_wav_util.go:62: Create tempFile /tmp/2402235346.wav
11603961

最终音频

(base) xxx@hu:/tmp$ ffmpeg -i 2402235346.wav 
ffmpeg version 4.2.7-0ubuntu0.1 Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
  configuration: --prefix=/usr --extra-version=0ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
Guessed Channel Layout for Input Stream #0.0 : mono
Input #0, wav, from '2402235346.wav':
  Duration: 00:04:01.75, bitrate: 768 kb/s
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 48000 Hz, mono, s16, 768 kb/s

总结

其实在写代码过程中,有个让我特别头疼的东西,就是怎么把数组转为**uint。如果大家有兴趣可以研究一下ResampleByFFmpegApi2方法的转换逻辑,会学到不少东西。

分享:

我们的疲劳往往不是由工作引起的,而是由于忧烦、挫折和不满等。——《人性的弱点》

Go语学习笔记 - 调用ffmpeg-api实现音频重采样相关推荐

  1. x%3e=y%3e=z的c语言表达式,我的C语学习笔记-C语言教程(三).doc

    我的C语学习笔记- C语言教程(三) C语言教程---第一章: C语言概论 C语言教程---第二章: 数据类型.运算符.表达式 C语言教程---第三章: C语言程序设计初步 C语言教程---第四章: ...

  2. c语言第七章函数笔记,我的C语学习笔记-C语言教程(七).doc

    我的C语学习笔记- C语言教程(七) C语言教程---第一章: C语言概论 C语言教程---第二章: 数据类型.运算符.表达式 C语言教程---第三章: C语言程序设计初步 C语言教程---第四章: ...

  3. NDK学习笔记:FFmpeg解压MP34提取音频PCM(swrContext、swr_alloc_set_opts)

    NDK学习笔记:FFmpeg解压MP34提取音频PCM 承接 FFmpeg解压MP4提取视频YUV ,这次我们需要提取的是音频原始数据PCM.代码流程大同小异,主要区别就是AVFrame->PC ...

  4. NDK学习笔记:FFmpeg音视频同步3(你追我赶,升级ffmpeg/libyuv支持neon)

    NDK学习笔记:FFmpeg音视频同步3 本篇内容说多不多,但如果要说得明明白白的,可能就有点难度了.所以我决定把我的调试过程日志都呈现出来,方便大家理解.继上一篇文末,我们学习到了什么是DTS/PT ...

  5. Redis学习笔记 - 数据类型与API(1)Key

    Redis学习笔记 - 数据类型与API(1)Key Key相关命令 1. 常用命令 命令 含义 时间复杂度 keys 查找所有符合给定模式 pattern 的 key O(N), N 为数据库中 k ...

  6. Go语学习笔记 - gorm使用 - gorm处理错误 Web框架Gin(十)

    学习笔记,写到哪是哪. 接着上一篇文章:Go语学习笔记 - gorm使用 - 原生sql.命名参数.Rows.ToSQL | Web框架Gin(九)_的博客-CSDN博客 目前gorm对数据库的一些操 ...

  7. Go语学习笔记 - websocket gorilla(附测试代码) | 从零开始Go语言

    目录 项目结构 消息结构 服务端代码 定义客户端行为 服务启动 测试代码 总结 学习笔记,写到哪是哪. websocket也是常用的协议了,在上一篇中主要测试使用了一下grpc. 下面我会把代码贴出来 ...

  8. Go语学习笔记 - 增加时间工具 | Web框架Gin(五)

    学习笔记,写到哪是哪. 接着上一篇的文章:Go语学习笔记 - 跨域配置.全局异常捕获 | Web框架Gin(四)_剑客阿良_ALiang的博客-CSDN博客_gin全局异常捕获 在上一篇中已经将一些基 ...

  9. ffmpeg api解码音频,得到pcm数据

    ffmpeg api解码音频,得到pcm数据,程序如下: extern "C" { #include "libavutil/avutil.h" #include ...

最新文章

  1. 一套就够了!室内+室外激光SLAM关键算法讲解与工程实现(源码和数据开源)...
  2. python_bomb----函数高级特性(生成器)
  3. 线程池 java 新建方式_Java线程池的四种创建方式
  4. C++类的成员变量和成员函数
  5. 零基础如何学习Java,这里分享一些技巧心得
  6. 《软件工艺师:专业、务实、自豪》一2.8 小结
  7. bzoj4152 The Captain (dijkstra)
  8. 前端对div连线_《前端图形学从入门到放弃》003 三维世界
  9. azure linux 多磁盘 lvm,EVE-NG扩展磁盘空间(扩展LVM卷)
  10. vue-axios interceptors
  11. php ado 建立注册,如何注册ADO与DAO [Access软件网]
  12. C语言pop_back用法,【C语言】单链表的所有操作的实现(包括PopBack、PushBack、PopFront、PushFront、Insert)...
  13. python中unique函数_Pandas Series.unique()用法介绍
  14. 不加群提取群成员_QQ群引流推广怎么做
  15. HTML制作简单的个人简历网页
  16. 软通动力华为外包_软通动力外包到百度?
  17. Arduino测试一块5路非自锁开关量输入模块ardunio中断编程示例
  18. 机器字长、存储字长、存储单元的个数、存储容量
  19. 【python批量插入图片到一个pdf中】
  20. 6个自学python必看网站

热门文章

  1. set name utd8_ml utd 8机器学习数据的最新生命
  2. win7 蓝牙4.0 ble驱动_恩智浦发布行业领先的2x2 Wi-Fi 6 +蓝牙解决方案,彻底改变游戏、音频、工业和物联网市场...
  3. Leetcode 129求根节点到叶节点数字之和、104二叉树的最大深度、8字符串转换整数(atoi)、82删除排序链表中的重复元素II、204二分查找、94二叉树的中序遍历、144二叉树的前序遍历
  4. python求两个数的最大公约数穷举法_五十九、如何求N个数的最大公约数和最小公倍数...
  5. STVD汇编开发stm8
  6. Python代码中的三大常见“愚形”,你中招了吗?
  7. 深富策略:锂电光伏崛起 成长赛道再度回归
  8. 数字孪生 应急管理可视化决策系统
  9. 29岁vivo员工吐槽:整理出这份8万字Java性能优化实战解析
  10. 吴恩达机器学习神经网络 8-1非线性假设