Go notas de estudo de idioma - chame ffmpeg-api para obter reamostragem de áudio

Índice

prefácio

Implantação de ambiente

o código

Resumir


prefácio

Recentemente, estou muito interessado no processamento de áudio e vídeo golang e fiz algumas pesquisas sobre goav, uma biblioteca comum para áudio e vídeo golang. Eu escrevi um wav para a função de taxa de amostragem. Deixe-me compartilhar com você, encontrei muitas armadilhas no meio, e o processo de resolvê-las é bastante interessante.

Implantação de ambiente

O código é executado no ambiente Ubuntu e precisa usar goav, que é um pacote golang do código-fonte ffmpeg.

endereço goav: https://github.com/giorgisio/goav

O Goav é instalado da seguinte maneira

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

o código

Veja o código primeiro

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
}

Descrição do código:

1. O código não é um método de ferramenta.Se você entender a lógica, você mesmo pode modificá-lo em um método de ferramenta.

2. A biblioteca swresample no ffmpeg será usada para amostrar os dados de áudio.

3. Você pode dar uma olhada mais de perto, se quiser fazer o processamento em tempo real, também pode alterá-lo.

4. Há um parâmetro libswresample.AvSampleFormat(1) no método SwrAllocSetOpts. Por que usar 1? Isso é principalmente para selecionar a enumeração do método de representação de amostragem. Consulte a enumeração do código-fonte subjacente. Vou postá-la abaixo. Do meu lado, como o áudio é s16, escolho 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
};

Preparação de áudio, o áudio de entrada é de áudio com taxa de amostragem de 16k.

(base) xxx@hu:~/GolandProjects/MediaRelay/data$ ffmpeg -i 1.wav 
ffmpeg versão 4.2.7-0ubuntu0.1 Copyright (c) 2000-2022 os desenvolvedores FFmpeg
  construídos com gcc 9 (Ubuntu 9.4.0- 1ubuntu1~20.04.1)
  configuração: --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
  . 0
  libswscale 5. 5.100 / 5. 5.100
  libswresample 3. 5.100 / 3. 5.100
  libpostproc 55. 5.100 / 55. 5.100
Layout de canal estimado para fluxo de entrada #0.0: mono
Entrada #0, wav, de '1.wav':
  Metadados :
    data: 2020-09-28
    codificador: Lavf58.45.100
  Duração: 00:04:01,75, taxa de bits: 256 kb/s
    Fluxo nº 0:0: Áudio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, mono, s16, 256 kb/s

Implementação

informações do formato do arquivo de entrada -> AudioFormat:1,NumChannels:1,SampleRate:16000,ByteRate:32000,BlockAlign:2,BitsPerSample:16INFO: 2022/12/06 17:14:49.937547 csdn_wav_util.go:62: Criar arquivo temporário /tmp /2402235346.wav
11603961
 

áudio final

(base) xxx@hu:/tmp$ ffmpeg -i 2402235346.wav 
ffmpeg versão 4.2.7-0ubuntu0.1 Copyright (c) 2000-2022 os desenvolvedores FFmpeg
  construídos com gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1 )
  configuração: --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
  . 0
  libswscale 5. 5.100 / 5. 5.100
  libswresample 3. 5.100 / 3. 5.100
  libpostproc 55. 5.100 / 55. 5.100
Layout de canal estimado para fluxo de entrada #0.0: mono
Entrada #0, wav, de '2402235346.wav':
  Duração : 00:04:01.75, taxa de bits: 768 kb/s
    Fluxo nº 0:0: Áudio: pcm_s16le ([1][0][0][0] / 0x0001), 48000 Hz, mono, s16, 768 kb/s 

Resumir

Na verdade, no processo de escrever código, há algo que me dá uma dor de cabeça especial, ou seja, como converter o array para **uint. Se você estiver interessado, pode estudar a lógica de conversão do método ResampleByFFmpegApi2 e aprenderá muito.

compartilhar:

        Muitas vezes, nosso cansaço não é causado pelo trabalho, mas por preocupação, frustração e insatisfação. —— "A Fraqueza da Natureza Humana"

Acho que você gosta

Origin blog.csdn.net/zhiweihongyan1/article/details/128205603
Recomendado
Clasificación