Heim  >  Artikel  >  Backend-Entwicklung  >  Golang und FFmpeg: So erreichen Sie eine Reduzierung des Audiorauschens und eine Reparatur von Verzerrungen

Golang und FFmpeg: So erreichen Sie eine Reduzierung des Audiorauschens und eine Reparatur von Verzerrungen

PHPz
PHPzOriginal
2023-09-27 09:37:021032Durchsuche

Golang与FFmpeg: 如何实现音频降噪和失真修复

Golang und FFmpeg: So erreichen Sie Audio-Rauschunterdrückung und Verzerrungsreparatur

Einführung:
Im Bereich der Audioverarbeitung sind Rauschunterdrückung und Verzerrungsreparatur zwei sehr wichtige Aufgaben. Die Rauschunterdrückung kann Rauschen im Audio entfernen, die Klangqualität verbessern und den Ton klarer machen; während die Verzerrungsreparatur durch die Übertragung oder Aufnahme verursachte Verzerrungen reparieren kann, sodass der Ton seine ursprüngliche Klangqualität wiederherstellen kann. In diesem Artikel wird anhand konkreter Codebeispiele erläutert, wie Sie mit Golang- und FFmpeg-Bibliotheken die Reduzierung von Audiorauschen und die Reparatur von Verzerrungen implementieren.

1. FFmpeg installieren und konfigurieren

Zuerst müssen wir die FFmpeg-Bibliothek installieren und die Umgebung konfigurieren. Auf Linux-Systemen können Sie Paketverwaltungstools für die Installation verwenden, wie zum Beispiel:

$ sudo apt-get install ffmpeg

Auf Windows-Systemen können Sie das Installationspaket zur Installation von der offiziellen Website von FFmpeg herunterladen.

Nachdem die Installation abgeschlossen ist, müssen wir die FFmpeg-Bibliothek in Golang einführen. Sie können das Paketverwaltungstool von Go verwenden, um es zu installieren, z. B.:

$ go get github.com/giorgisio/goav/avformat
$ go get github.com/giorgisio/goav/avutil

Dann fügen Sie die FFmpeg-Bibliothek in den Code ein:

import (
    "github.com/giorgisio/goav/avformat"
    "github.com/giorgisio/goav/avutil"
)

2. Implementierung der Audio-Rauschunterdrückung

Eine Audio-Rauschunterdrückung kann durch Entfernen der Rauschkomponente erreicht werden im Spektrum. In FFmpeg können wir den Denoise-Audiofilter zur Rauschunterdrückung verwenden.

Der spezifische Code lautet wie folgt:

func denoise(inputFile string, outputFile string) error {
    inputFormat := avformat.AvFindInputFormat("wav")
    avformat.AvRegisterAll()

    // 打开输入文件
    inputContext := avformat.AvformatAllocContext()
    if avformat.AvformatOpenInput(&inputContext, inputFile, inputFormat, nil) != 0 {
        return fmt.Errorf("failed to open input file")
    }
    defer avformat.AvformatCloseInput(&inputContext)

    // 打开输出文件
    outputContext := avformat.AvformatAllocContext()
    if avformat.AvformatAllocOutputContext2(&outputContext, nil, "wav", outputFile) != 0 {
        return fmt.Errorf("failed to create output context")
    }
    defer avformat.AvformatFreeContext(outputContext)
    
    // 寻找音频流
    if avformat.AvformatFindStreamInfo(inputContext, nil) < 0 {
        return fmt.Errorf("failed to find stream info")
    }

    audioStreamIndex := -1
    for i := 0; i < len(inputContext.Streams); i++ {
        if inputContext.Streams[i].CodecParameters.GetCodecType() == avformat.AVMEDIA_TYPE_AUDIO {
            audioStreamIndex = i
            break
        }
    }

    if audioStreamIndex == -1 {
        return fmt.Errorf("failed to find audio stream")
    }

    audioStream := inputContext.Streams[audioStreamIndex]
    codecParameters := audioStream.CodecParameters

    // 初始化解码器
    decoder := avformat.AvcodecFindDecoder(codecParameters.GetCodecId())
    if decoder == nil {
        return fmt.Errorf("failed to find decoder")
    }
    
    codecContext := avformat.AvcodecAllocContext3(decoder)
    if codecContext == nil {
        return fmt.Errorf("failed to allocate codec context")
    }

    if avformat.AvcodecParametersToContext(codecContext, codecParameters) < 0 {
        return fmt.Errorf("failed to copy codec parameters")
    }

    if avformat.AvcodecOpen2(codecContext, decoder, nil) < 0 {
        return fmt.Errorf("failed to open decoder")
    }

    // 初始化音频处理滤镜
    filters := fmt.Sprintf("anullsrc=cl=stereo|cr=44100,ade noise" +
        "=all_mode=0:amount=0.8,f=format=s16p:samplerate=44100" +
        ":sample_fmts=s16", codecParameters.SampleRate)

    audioFilterGraph := avutil.AvfilterGraphAlloc()

    if avutil.AvfilterGraphParse2(audioFilterGraph, filters, nil) < 0 {
        return fmt.Errorf("failed to parse filter graph")
    }

    // 初始化音频转换器
    audioConvertContext := avutil.AvAudioResampleInit(codecContext.Channels,
        codecContext.SampleRate, codecParameters.SampleRate,
        codecParameters.Channels, avutil.SampleFormat(codecParameters.Format),  
        avutil.SampleFormat(avutil.AV_SAMPLE_FMT_S16), 0, 0, nil)

    if audioConvertContext == nil {
        return fmt.Errorf("failed to init audio resampler")
    }

    // 初始化输出编码器
    outputCodec := avformat.AvcodecFindEncoder(avformat.CodecId(codecParameters.GetCodecId()))
    if outputCodec == nil {
        return fmt.Errorf("failed to find output encoder")
    }

    outputCodecContext := avformat.AvcodecAllocContext3(outputCodec)
    if outputCodecContext == nil {
        return fmt.Errorf("failed to allocate output codec context")
    }

    outputCodecContext.SampleRate = codecParameters.SampleRate
    outputCodecContext.Channels = codecParameters.Channels
    outputCodecContext.SampleFmt = avutil.AV_SAMPLE_FMT_S16
    outputCodecContext.BitRate = codecParameters.BitRate

    if avformat.AvcodecOpen2(outputCodecContext, outputCodec, nil) < 0 {
        return fmt.Errorf("failed to open output encoder")
    }

    // 初始化输出流
    outputStream := outputContext.AvformatNewStream(outputCodec)
    if outputStream == nil {
        return fmt.Errorf("failed to create output stream")
    }
    outputStream.CodecParameters = codecParameters

    // 写入输出文件头
    if avformat.AvformatWriteHeader(outputContext, nil) < 0 {
        return fmt.Errorf("failed to write output header")
    }

    // 音频流降噪并写入输出文件
    packet := avformat.AvPacketAlloc()
    for avformat.AvReadFrame(inputContext, packet) >= 0 {
        if packet.StreamIndex == audioStreamIndex {
            // 解码音频帧
            frame := avutil.AvFrameAlloc()
            if avformat.AvcodecSendPacket(codecContext, packet) == 0 {
                for avformat.AvcodecReceiveFrame(codecContext, frame) >= 0 {
                    // 音频降噪
                    avutil.AvBuffersrcAddFrameFlags(audioFilterGraph.GetInputs()[0], frame, 0)
                    for avutil.AvBuffersinkGetFrame(audioFilterGraph.GetOutputs()[0].GetFilterContext(), frame) >= 0 {
                        // 音频转换
                        avutil.AvAudioResampleConvert(audioConvertContext, &frame.Data, frame.GetExtendedData(), 
                            frame.GetNbSamples(), frame.Channels, frame.Format, frame.SampleRate, 0)

                        // 编码音频
                        if avformat.AvcodecSendFrame(outputCodecContext, frame) == 0 {
                            for avformat.AvcodecReceivePacket(outputCodecContext, packet) >= 0 {
                                packet.StreamIndex = outputStream.Index
                                avformat.AvpacketRescaleTs(packet, codecContext.TimeBase, outputStream.TimeBase)
                                avformat.AvInterleavedWriteFrame(outputContext, packet)
                                avformat.AvPacketUnref(packet)
                            }
                        }
                    }
                }
            }
            avutil.AvFrameFree(&frame)
        }
        avformat.AvPacketUnref(packet)
    }

    // 写入输出文件尾
    avformat.AvWriteTrailer(outputContext)

    return nil
}

3. Implementierung der Reparatur von Audioverzerrungen

Die Reparatur von Audioverzerrungen kann durch einige Algorithmen die ursprüngliche Klangqualität wiederherstellen. In FFmpeg können wir Audiofilter verwenden, die die Tonhöhe reparieren, um eine Verzerrungsreparatur zu erreichen.

Der spezifische Code lautet wie folgt:

func distort(inputFile string, outputFile string) error {
    inputFormat := avformat.AvFindInputFormat("wav")
    avformat.AvRegisterAll()

    // 打开输入文件
    inputContext := avformat.AvformatAllocContext()
    if avformat.AvformatOpenInput(&inputContext, inputFile, inputFormat, nil) != 0 {
        return fmt.Errorf("failed to open input file")
    }
    defer avformat.AvformatCloseInput(&inputContext)

    // 打开输出文件
    outputContext := avformat.AvformatAllocContext()
    if avformat.AvformatAllocOutputContext2(&outputContext, nil, "wav", outputFile) != 0 {
        return fmt.Errorf("failed to create output context")
    }
    defer avformat.AvformatFreeContext(outputContext)
    
    // 寻找音频流
    if avformat.AvformatFindStreamInfo(inputContext, nil) < 0 {
        return fmt.Errorf("failed to find stream info")
    }

    audioStreamIndex := -1
    for i := 0; i < len(inputContext.Streams); i++ {
        if inputContext.Streams[i].CodecParameters.GetCodecType() == avformat.AVMEDIA_TYPE_AUDIO {
            audioStreamIndex = i
            break
        }
    }

    if audioStreamIndex == -1 {
        return fmt.Errorf("failed to find audio stream")
    }

    audioStream := inputContext.Streams[audioStreamIndex]
    codecParameters := audioStream.CodecParameters

    // 初始化解码器
    decoder := avformat.AvcodecFindDecoder(codecParameters.GetCodecId())
    if decoder == nil {
        return fmt.Errorf("failed to find decoder")
    }
    
    codecContext := avformat.AvcodecAllocContext3(decoder)
    if codecContext == nil {
        return fmt.Errorf("failed to allocate codec context")
    }

    if avformat.AvcodecParametersToContext(codecContext, codecParameters) < 0 {
        return fmt.Errorf("failed to copy codec parameters")
    }

    if avformat.AvcodecOpen2(codecContext, decoder, nil) < 0 {
        return fmt.Errorf("failed to open decoder")
    }

    // 初始化音频处理滤镜
    filters := fmt.Sprintf("asetrate=44100,aresample=44100,atempo=1")

    audioFilterGraph := avutil.AvfilterGraphAlloc()

    if avutil.AvfilterGraphParse2(audioFilterGraph, filters, nil) < 0 {
        return fmt.Errorf("failed to parse filter graph")
    }

    // 初始化输出编码器
    outputCodec := avformat.AvcodecFindEncoder(avformat.CodecId(codecParameters.GetCodecId()))
    if outputCodec == nil {
        return fmt.Errorf("failed to find output encoder")
    }

    outputCodecContext := avformat.AvcodecAllocContext3(outputCodec)
    if outputCodecContext == nil {
        return fmt.Errorf("failed to allocate output codec context")
    }

    outputCodecContext.SampleRate = codecParameters.SampleRate
    outputCodecContext.Channels = codecParameters.Channels
    outputCodecContext.SampleFmt = avutil.AV_SAMPLE_FMT_S16
    outputCodecContext.BitRate = codecParameters.BitRate

    if avformat.AvcodecOpen2(outputCodecContext, outputCodec, nil) < 0 {
        return fmt.Errorf("failed to open output encoder")
    }

    // 初始化输出流
    outputStream := outputContext.AvformatNewStream(outputCodec)
    if outputStream == nil {
        return fmt.Errorf("failed to create output stream")
    }
    outputStream.CodecParameters = codecParameters

    // 写入输出文件头
    if avformat.AvformatWriteHeader(outputContext, nil) < 0 {
        return fmt.Errorf("failed to write output header")
    }

    // 音频流失真修复并写入输出文件
    packet := avformat.AvPacketAlloc()
    for avformat.AvReadFrame(inputContext, packet) >= 0 {
        if packet.StreamIndex == audioStreamIndex {
            // 解码音频帧
            frame := avutil.AvFrameAlloc()
            if avformat.AvcodecSendPacket(codecContext, packet) == 0 {
                for avformat.AvcodecReceiveFrame(codecContext, frame) >= 0 {
                    // 音频失真修复
                    avutil.AvBuffersrcAddFrameFlags(audioFilterGraph.GetInputs()[0], frame, 0)
                    for avutil.AvBuffersinkGetFrame(audioFilterGraph.GetOutputs()[0].GetFilterContext(), frame) >= 0 {
                        // 编码音频
                        if avformat.AvcodecSendFrame(outputCodecContext, frame) == 0 {
                            for avformat.AvcodecReceivePacket(outputCodecContext, packet) >= 0 {
                                packet.StreamIndex = outputStream.Index
                                avformat.AvpacketRescaleTs(packet, codecContext.TimeBase, outputStream.TimeBase)
                                avformat.AvInterleavedWriteFrame(outputContext, packet)
                                avformat.AvPacketUnref(packet)
                            }
                        }
                    }
                }
            }
            avutil.AvFrameFree(&frame)
        }
        avformat.AvPacketUnref(packet)
    }

    // 写入输出文件尾
    avformat.AvWriteTrailer(outputContext)

    return nil
}

Zusammenfassung:

Durch die Verwendung der Golang-Sprache und der FFmpeg-Bibliothek können wir problemlos Funktionen zur Reduzierung von Audiorauschen und zur Reparatur von Verzerrungen implementieren. Im Hinblick auf die Rauschunterdrückung verwenden wir Denoise-Audiofilter, um Rauschen zu entfernen; im Hinblick auf die Reparatur von Verzerrungen verwenden wir Audiofilter, die die Tonhöhe reparieren, um die ursprüngliche Klangqualität des Audios wiederherzustellen. Bei den oben genannten Beispielen handelt es sich um konkrete Codebeispiele. Ich hoffe, sie sind hilfreich für Sie.

Das obige ist der detaillierte Inhalt vonGolang und FFmpeg: So erreichen Sie eine Reduzierung des Audiorauschens und eine Reparatur von Verzerrungen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn