Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Bagaimana untuk menggunakan bahasa Go untuk pemprosesan audio dan video?

Bagaimana untuk menggunakan bahasa Go untuk pemprosesan audio dan video?

WBOY
WBOYasal
2023-06-10 12:07:542789semak imbas

Dalam beberapa tahun kebelakangan ini, dengan perkembangan teknologi audio dan video, permintaan untuk teknologi berkaitan pemprosesan audio dan video semakin tinggi. Sebagai bahasa pengaturcaraan berprestasi tinggi, Go juga menyediakan banyak alatan dan perpustakaan yang mudah untuk memudahkan pemprosesan data audio dan video kami. Artikel ini akan memperkenalkan cara menggunakan bahasa Go untuk pemprosesan audio dan video Kandungan khusus adalah seperti berikut:

1 Cara menggunakan Pergi untuk memproses audio

Dalam bahasa Go, memproses data audio biasanya memerlukan penggunaan pengekodan audio perpustakaan Penyahkodan. Pada masa ini yang lebih biasa digunakan termasuk portaudio dan ffmpeg. Di sini kami mengambil ffmpeg sebagai contoh dan memberikan contoh kod mudah untuk membaca fail audio, menukar format dan menyimpan:

package main

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

func main() {
    // 打开输入文件
    inputCtx := avformat.AvformatAllocContext()
    if err := avformat.AvformatOpenInput(&inputCtx, "input.mp3", nil, nil); err != nil {
        log.Fatal(err)
    }
    defer avformat.AvformatCloseInput(inputCtx)

    // 查找音频流
    if err := avformat.AvformatFindStreamInfo(inputCtx, nil); err != nil {
        log.Fatal(err)
    }
    audioIndex := -1
    for i := 0; i < int(inputCtx.NbStreams()); i++ {
        codecCtx := inputCtx.Streams()[i].Codec()
        if codecCtx.CodecType() == avutil.AVMEDIA_TYPE_AUDIO {
            audioIndex = i
            break
        }
    }
    if audioIndex < 0 {
        log.Fatal("No audio stream found")
    }

    // 打开解码器
    codecCtx := inputCtx.Streams()[audioIndex].Codec()
    codec := avcodec.AvcodecFindDecoder(codecCtx.CodecId())
    if codec == nil {
        log.Fatal("Unsupported codec")
    }
    if err := codecCtx.AvcodecOpen2(codec, nil); err != nil {
        log.Fatal(err)
    }
    defer codecCtx.AvcodecClose()

    // 打开输出文件
    outputFmt := avformat.AvGuessFormat("wav", "output.wav", "")
    if outputFmt == nil {
        log.Fatal("Failed to guess output format")
    }
    outputCtx := avformat.AvformatAllocContext()
    outputCtx.SetOutputFormat(outputFmt)
    if err := avformat.AvioOpen(outputCtx.Pb(), "output.wav", avformat.AVIO_FLAG_WRITE); err != nil {
        log.Fatal(err)
    }

    // 写入输出头
    if err := avformat.AvformatWriteHeader(outputCtx, nil); err != nil {
        log.Fatal(err)
    }

    // 读取、解码和转换音频帧
    for {
        pkt := avcodec.AvPacketAlloc()
        defer avutil.AvPacketFree(pkt)
        if ret := avformat.AvReadFrame(inputCtx, pkt); ret < 0 {
            if ret == avutil.AVERROR_EOF || ret == avutil.ErrEAGAIN {
                break
            }
            log.Fatal(ret)
        }
        if pkt.StreamIndex() != audioIndex {
            continue
        }
        frame := avutil.AvFrameAlloc()
        defer avutil.AvFrameFree(frame)
        if _, gotframe, ret := codecCtx.AvcodecDecodeAudio4(pkt, frame); ret >= 0 && gotframe {
            // 转换格式
            if _, _, ret := codecCtx.AvcodecSendPacket(pkt); ret < 0 {
                log.Fatal(ret)
            }
            for {
                frame2 := avutil.AvFrameAlloc()
                if _, ret := codecCtx.AvcodecReceiveFrame(frame2); ret == avutil.AvErrorEOF {
                    break
                } else if ret < 0 {
                    log.Fatal(ret)
                }
                if _, ret := avcodec.AvAudioResample(frame2, frame, avformat.AV_SAMPLE_FMT_S16, int(codecCtx.SampleRate()), avformat.AV_SAMPLE_FMT_FLTP, int(codecCtx.SampleRate()), 0, 0); ret < 0 {
                    log.Fatal(ret)
                }

                // 写入输出帧
                if _, ret := avformat.AvInterleavedWriteFrame(outputCtx, frame); ret != nil {
                    log.Fatal(ret)
                }
            }
        }
    }

    // 写入输出尾
    if err := avformat.AvWriteTrailer(outputCtx); err != nil {
        log.Fatal(err)
    }
}

Penerangan kod:

  1. Membaca fail input

Di sini fungsi avformat.AvformatOpenInput digunakan untuk membuka fail input dan avformat.AvformatFindStreamInfo digunakan untuk mencari strim audio.

  1. Buka penyahkod

Gunakan fungsi avcodec.AvcodecFindDecoder dalam kod untuk mencari penyahkod yang disokong dan bukanya Diandaikan bahawa format pengekodan fail input adalah sah.

  1. Buka fail output

Gunakan avformat.AvGuessFormat untuk mengetahui format pengekodan fail output, kemudian gunakan fungsi avformat.AvformatAllocContext untuk mencipta konteks fail output dan buka fail.

  1. Baca, nyahkod dan tukar bingkai audio

Gunakan fungsi avformat.AvReadFrame untuk membaca bingkai daripada fail input dan semak sama ada ia tergolong dalam strim audio. Jika ya, gunakan penyahkod untuk menyahkod bingkai menjadi data audio. Kemudian gunakan fungsi avcodec.AvAudioResample untuk menukar data audio kepada kadar sampel dan format yang ditetapkan. Akhir sekali, gunakan fungsi avformat.AvInterleavedWriteFrame untuk menulis bingkai output pada fail output.

  1. Akhir sekali, tutup fail input dan output.

2. Cara menggunakan Go untuk memproses video

Memproses data video dalam bahasa Go juga memerlukan penggunaan pustaka codec video, dan anda juga boleh menggunakan pustaka alat ffmpeg. Seterusnya, contoh kod mudah untuk membaca fail video, mengekstrak bingkai dan menyimpan diberikan:

package main

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

func main() {
    // 打开输入文件
    inputCtx := avformat.AvformatAllocContext()
    if err := avformat.AvformatOpenInput(&inputCtx, "input.mp4", nil, nil); err != nil {
        panic(err)
    }
    defer avformat.AvformatCloseInput(inputCtx)

    // 查找视频流
    if err := avformat.AvformatFindStreamInfo(inputCtx, nil); err != nil {
        panic(err)
    }
    videoIndex := -1
    for i := 0; i < int(inputCtx.NbStreams()); i++ {
        codecCtx := inputCtx.Streams()[i].Codec()
        if codecCtx.CodecType() == avutil.AVMEDIA_TYPE_VIDEO {
            videoIndex = i
            break
        }
    }
    if videoIndex < 0 {
        panic("No video stream found")
    }

    // 打开解码器
    codecCtx := inputCtx.Streams()[videoIndex].Codec()
    codec := avcodec.AvcodecFindDecoder(codecCtx.CodecId())
    if codec == nil {
        panic("Unsupported codec")
    }
    if err := codecCtx.AvcodecOpen2(codec, nil); err != nil {
        panic(err)
    }
    defer codecCtx.AvcodecClose()

    // 创建输出文件
    output, err := os.Create("output.jpg")
    if err != nil {
        panic(err)
    }
    defer output.Close()

    // 提取视频帧
    packet := avutil.AvPacketAlloc()
    defer avutil.AvPacketFree(packet)
    for {
        if ret := avformat.AvReadFrame(inputCtx, packet); ret < 0 {
            if ret == avutil.AVERROR_EOF || ret == avutil.ErrEAGAIN {
                break
            }
            panic(ret)
        }
        if packet.StreamIndex() != videoIndex {
            continue
        }

        // 解码视频帧
        frame := avutil.AvFrameAlloc()
        defer avutil.AvFrameFree(frame)
        if gotframe, ret := codecCtx.AvcodecSendPacket(packet); ret >= 0 && gotframe {
            for {
                frame := avutil.AvFrameAlloc()
                if _, ret := codecCtx.AvcodecReceiveFrame(frame); ret == avutil.AvErrorEOF {
                    break
                } else if ret < 0 {
                    panic(ret)
                }

                // 写入输出文件
                img := image.NewRGBA(image.Rect(0, 0, int(frame.Width()), int(frame.Height())))
                for y := 0; y < int(frame.Height()); y++ {
                    for x := 0; x < int(frame.Width()); x++ {
                        c := frame.Data(0)[y*frame.Linesize(0)+x*3 : y*frame.Linesize(0)+x*3+3]
                        img.SetRGBA(x, y, color.RGBA{c[0], c[1], c[2], 255})
                    }
                }
                if err := jpeg.Encode(output, img, &jpeg.Options{Quality: 100}); err != nil {
                    panic(err)
                }
                break
            }
        }
    }
}

Penjelasan kod:

  1. Baca fail input

Begitu juga gunakan fungsi avformat.AvformatOpenInput untuk membuka fail input dan gunakan avformat.AvformatFindStreamInfo untuk mencari strim video.

  1. Buka penyahkod

Juga gunakan fungsi avcodec.AvcodecFindDecoder dalam kod untuk mencari penyahkod yang disokong dan membukanya Diandaikan bahawa format pengekodan input fail adalah sah.

  1. Buat fail output

Gunakan pakej os terbina dalam Go untuk mencipta fail output dan bukanya.

  1. Ekstrak bingkai video

Gunakan fungsi avformat.AvReadFrame untuk membaca bingkai daripada fail input dan semak sama ada ia tergolong dalam strim video. Jika ya, gunakan penyahkod untuk menyahkod bingkai menjadi data video. Data video kemudiannya ditukar kepada data imej (di sini ke dalam format JPEG) melalui gelung dan ditulis pada fail output.

  1. Akhir sekali, tutup fail input dan output.

Ringkasan

Artikel ini memperkenalkan cara menggunakan bahasa Go untuk memproses data audio dan video. Penghuraian dan pengekodan dan penyahkodan format ialah pautan utama dalam pemprosesan audio dan video Di sini kami menggunakan pustaka alat ffmpeg untuk memproses format audio dan video. Dalam aplikasi sebenar, operasi pemprosesan audio dan video yang lebih kompleks mungkin diperlukan, tetapi rangka kerja kod keseluruhan adalah serupa. Kami berharap kod sampel kami dapat memberikan sedikit bantuan untuk kerja pemprosesan audio dan video anda.

Atas ialah kandungan terperinci Bagaimana untuk menggunakan bahasa Go untuk pemprosesan audio dan video?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn