目次
序文
最近、golang による音声と動画の処理に非常に興味を持っており、goav という音声と動画の共通ライブラリである goav について調査しました。サンプルレート関数へのwavを書きました。途中で多くの落とし穴に遭遇しましたが、それらを解決するプロセスは非常に興味深いものです。
環境のデプロイ
このコードは Ubuntu 環境で実行され、ffmpeg ソース コードの golang パッケージである goav を使用する必要があります。
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-dev
sudo apt install -y libavdevice-dev libavfilter-dev libswscale-dev libavcodec-dev libavformat-dev libswresample-dev libavutil-dev
sudo apt-get install yasm
export 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 = 1
inSampleRate int = 16000
//inBitsPerSample uint16 = 16
outNumChannels int64 = 1
outSampleRate int = 48000
outBitsPerSample uint16 = 16
swr *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 := 4096
for {
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 = err4
return
}
}
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 bits
AV_SAMPLE_FMT_S16, ///< signed 16 bits
AV_SAMPLE_FMT_S32, ///< signed 32 bits
AV_SAMPLE_FMT_FLT, ///< float
AV_SAMPLE_FMT_DBL, ///< double
AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar
AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
AV_SAMPLE_FMT_FLTP, ///< float, planar
AV_SAMPLE_FMT_DBLP, ///< double, planar
AV_SAMPLE_FMT_S64, ///< signed 64 bits
AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar
AV_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 バージョン 4.2.7-0ubuntu0.1 Copyright (c) 2000-2022 the FFmpeg developers
built with gcc 9 (Ubuntu 9.4.0- 1ubuntu1~20.04.1)
設定: --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.40.0sample
4.100 . 0
libswscale 5. 5.100 / 5. 5.100
libswresample 3. 5.100 / 3. 5.100
libpostproc 55. 5.100 / 55. 5.100
入力ストリーム #0.0 の推定チャネル レイアウト: mono
入力 #0、wav、「1.wav」から:
メタデータ:
日付: 2020-09-28
エンコーダー: Lavf58.45.100
期間: 00:04:01.75、ビットレート: 256 kb/s
ストリーム #0:0: オーディオ: pcm_s16le ([1][0][0][0] / 0x0001)、16000 Hz、モノラル、s16、256 kb/s
実装
入力ファイル形式情報 -> AudioFormat:1,NumChannels:1,SampleRate:16000,ByteRate:32000,BlockAlign:2,BitsPerSample:16INFO : 2022/12/06 17:14:49.937547 csdn_wav_util.go:62: tempFile /tmp を作成/2402235346.wav
11603961
最終的なオーディオ
(base) xxx@hu:/tmp$ ffmpeg -i 2402235346.wav
ffmpeg バージョン 4.2.7-0ubuntu0.1 Copyright (c) 2000-2022
gcc 9 でビルドされた FFmpeg 開発者 (Ubuntu 9.4.0-1ubuntu1~20.04.1 )
設定: --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.40.0sample
4.100 . 0
libswscale 5. 5.100 / 5. 5.100
libswresample 3. 5.100 / 3. 5.100
libpostproc 55. 5.100 / 55. 5.100
入力ストリーム #0.0 の推定チャネル レイアウト: mono
入力 #0、wav、「2402235346.wav」から:
デュレーション: 00:04:01.75、ビットレート: 768 kb/s
ストリーム #0:0: オーディオ: pcm_s16le ([1][0][0][0] / 0x0001)、48000 Hz、モノラル、s16、768 kb/s
要約する
実際、コードを書いている過程で特に頭を悩ませることがあります。それは、配列を **uint に変換する方法です。興味のある方は、ResampleByFFmpegApi2 メソッドの変換ロジックを勉強すると、とても勉強になります。
共有:
私たちの疲労は、多くの場合、仕事が原因ではなく、心配、フラストレーション、不満によって引き起こされます。——「人間性の弱さ」