ホームページ バックエンド開発 Golang Golang と FFmpeg: ビデオ フレームのインターセプトとスケーリングを実装する方法

Golang と FFmpeg: ビデオ フレームのインターセプトとスケーリングを実装する方法

Sep 27, 2023 am 09:34 AM
ビデオ 成し遂げる golanggolang ffmpegffmpeg

Golang与FFmpeg: 如何实现视频帧截取和缩放

Golang と FFmpeg: ビデオ フレームのインターセプトとスケーリングを実装する方法、具体的なコード例が必要です


概要:

ビデオ処理の需要が高まるにつれて、人々はビデオ処理用のプログラミング言語として Golang を使用する人が増えています。 FFmpeg は、業界で最も人気のあるオープンソース マルチメディア処理フレームワークとして、オーディオ データとビデオ データを処理するための豊富な機能を提供します。この記事では、Golang を使用して FFmpeg を呼び出し、ビデオ フレームのインターセプトおよびスケーリング機能を実装する方法と、対応するコード例を紹介します。

前提条件:

開始する前に、FFmpeg がマシンにインストールされ、正しい環境変数が構成されていることを確認する必要があります。

ビデオ フレーム インターセプト:

まず、ビデオ フレーム インターセプトの実装方法を見てみましょう。 FFmpeg では、「avformat」モジュールを使用してビデオ ファイルを読み取り、「avcodec」モジュールを使用してビデオ フレームをデコードできます。以下は簡単なサンプル コードです。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>package main import ( &quot;fmt&quot; &quot;log&quot; &quot;github.com/giorgisio/goav/avcodec&quot; &quot;github.com/giorgisio/goav/avformat&quot; ) func main() { // 打开视频文件 formatContext := avformat.AvformatAllocContext() if err := avformat.AvformatOpenInput(&amp;formatContext, &quot;/path/to/video.mp4&quot;, nil, nil); err != nil { log.Fatal(&quot;无法打开视频文件:&quot;, err) } defer avformat.AvformatFreeContext(formatContext) // 查找视频流 if err := formatContext.AvformatFindStreamInfo(nil); err != nil { log.Fatal(&quot;无法查找视频流:&quot;, err) } var videoStreamIndex int32 = -1 for i, stream := range formatContext.Streams() { if stream.CodecParameters().CodecType() == avformat.AVMEDIA_TYPE_VIDEO { videoStreamIndex = int32(i) break } } if videoStreamIndex == -1 { log.Fatal(&quot;找不到视频流&quot;) } // 找到视频解码器 videoDecoder := avcodec.AvcodecFindDecoder(avcodec.CodecId(formatContext.Streams()[videoStreamIndex].CodecParameters().CodecId())) if videoDecoder == nil { log.Fatal(&quot;无法找到视频解码器&quot;) } // 打开解码器上下文 videoCodecContext := avcodec.AvcodecAllocContext3(videoDecoder) if err := avcodec.AvcodecParametersToContext(videoCodecContext, formatContext.Streams()[videoStreamIndex].CodecParameters()); err != nil { log.Fatal(&quot;无法打开解码器上下文:&quot;, err) } if err := videoCodecContext.AvcodecOpen2(videoDecoder, nil); err != nil { log.Fatal(&quot;无法打开解码器:&quot;, err) } defer avcodec.AvcodecFreeContext(videoCodecContext) // 读取视频帧 packet := avcodec.AvPacketAlloc() defer avcodec.AvPacketFree(packet) for formatContext.AvReadFrame(packet) &gt;= 0 { if packet.StreamIndex() == videoStreamIndex { frame := avutil.AvFrameAlloc() defer avutil.AvFrameFree(frame) if err := videoCodecContext.AvcodecSendPacket(packet); err == nil { for videoCodecContext.AvcodecReceiveFrame(frame) == nil { // 处理视频帧 fmt.Printf(&quot;视频帧:%d &quot;, frame.Pts()) } } } } }</pre><div class="contentsignin">ログイン後にコピー</div></div> 上記のコードでは、まず avformat.AvformatAllocContext() を使用してフォーマット コンテキスト オブジェクトを割り当て、次に avformat.AvformatOpenInput( ) ビデオ ファイルが開かれました。次に、avformat.AvformatFindStreamInfo() を使用してビデオ ストリームを検索し、

avformat.AVMEDIA_TYPE_VIDEO

を使用してそれがビデオ ストリームであるかどうかを判断します。 次に、avcodec.AvcodecFindDecoder() を使用して適切なデコーダを見つけ、avcodec.AvcodecParametersToContext()

avcodec.AvcodecOpen2( )# を使用します。 ##デコーダ コンテキストを開きました。

最後に、formatContext.AvReadFrame() を使用してビデオ フレームを読み取り、videoCodecContext.AvcodecReceiveFrame()

で各フレームを処理します。この例では、各フレームの PTS 値を単純に出力します。


ビデオ スケーリング:

次に、ビデオ フレーム スケーリングを実現する方法を見てみましょう。 FFmpeg では、「swscale」モジュールを使用してビデオ フレームをスケーリングできます。以下は簡単なサンプル コードです。

package main

import (
    "fmt"
    "image"
    "log"
    "os"

    "github.com/giorgisio/goav/avcodec"
    "github.com/giorgisio/goav/avformat"
    "github.com/giorgisio/goav/swscale"
    "github.com/nfnt/resize"
)

func main() {
    // 打开视频文件
    formatContext := avformat.AvformatAllocContext()
    if err := avformat.AvformatOpenInput(&formatContext, "/path/to/video.mp4", nil, nil); err != nil {
        log.Fatal("无法打开视频文件:", err)
    }
    defer avformat.AvformatFreeContext(formatContext)

    // 查找视频流
    if err := formatContext.AvformatFindStreamInfo(nil); err != nil {
        log.Fatal("无法查找视频流:", err)
    }

    var videoStreamIndex int32 = -1
    for i, stream := range formatContext.Streams() {
        if stream.CodecParameters().CodecType() == avformat.AVMEDIA_TYPE_VIDEO {
            videoStreamIndex = int32(i)
            break
        }
    }

    if videoStreamIndex == -1 {
        log.Fatal("找不到视频流")
    }

    // 找到视频解码器
    videoDecoder := avcodec.AvcodecFindDecoder(avcodec.CodecId(formatContext.Streams()[videoStreamIndex].CodecParameters().CodecId()))
    if videoDecoder == nil {
        log.Fatal("无法找到视频解码器")
    }

    // 打开解码器上下文
    videoCodecContext := avcodec.AvcodecAllocContext3(videoDecoder)
    if err := avcodec.AvcodecParametersToContext(videoCodecContext, formatContext.Streams()[videoStreamIndex].CodecParameters()); err != nil {
        log.Fatal("无法打开解码器上下文:", err)
    }

    if err := videoCodecContext.AvcodecOpen2(videoDecoder, nil); err != nil {
        log.Fatal("无法打开解码器:", err)
    }
    defer avcodec.AvcodecFreeContext(videoCodecContext)

    // 创建视频缩放上下文
    swscaleContext := swscale.SwsGetContext(
        videoCodecContext.Width(), videoCodecContext.Height(), videoCodecContext.PixFmt(),
        videoCodecContext.Width()/2, videoCodecContext.Height()/2, avcodec.AV_PIX_FMT_RGB24,
        0, nil, nil, nil,
    )
    defer swscale.SwsFreeContext(swscaleContext)

    // 创建输出视频文件
    outfile, err := os.Create("/path/to/output.mp4")
    if err != nil {
        log.Fatal("无法创建输出视频文件:", err)
    }
    defer outfile.Close()

    // 创建视频编码器
    videoEncoder := avcodec.AvcodecFindEncoder(avcodec.AV_CODEC_ID_MPEG4)
    if videoEncoder == nil {
        log.Fatal("无法找到视频编码器")
    }

    // 创建编码器上下文
    videoCodecCtx := avcodec.AvcodecAllocContext3(videoEncoder)
    videoCodecCtx.SetBitRate(400000)
    videoCodecCtx.SetWidth(videoCodecContext.Width() / 2)
    videoCodecCtx.SetHeight(videoCodecContext.Height() / 2)
    videoCodecCtx.SetTimeBase(avformat.AVR{Num: 1, Den: 25})
    videoCodecCtx.SetPixFmt(avcodec.AV_PIX_FMT_YUV420P)

    // 打开编码器上下文
    if err := videoCodecCtx.AvcodecOpen2(videoEncoder, nil); err != nil {
        log.Fatal("无法打开编码器上下文:", err)
    }
    defer avcodec.AvcodecFreeContext(videoCodecCtx)

    // 写入视频文件头
    formatContext.SetOutput(outfile)
    if err := formatContext.AvformatWriteHeader(nil); err != nil {
        log.Fatal("无法写入视频文件头:", err)
    }
    defer formatContext.AvformatFreeOutputContext()

    // 准备编码帧和缩放帧
    encodeFrame := avutil.AvFrameAlloc()
    defer avutil.AvFrameFree(encodeFrame)

    encodeFrame.SetWidth(videoCodecCtx.Width())
    encodeFrame.SetHeight(videoCodecCtx.Height())
    encodeFrame.SetFormat(int32(videoCodecCtx.PixFmt()))

    frameSize := avcodec.AvpixelAvImageGetBufferSize(avcodec.AV_PIX_FMT_RGB24, videoCodecCtx.Width()/2, videoCodecCtx.Height()/2, 1)
    encodeFrameBuffer := avutil.AvMalloc(frameSize)
    defer avutil.AvFree(encodeFrameBuffer)

    encodeFrame.AvpixelAvImageFillArrays(encodeFrameBuffer, 1)

    for formatContext.AvReadFrame(packet) >= 0 {
        if packet.StreamIndex() == videoStreamIndex {
            frame := avutil.AvFrameAlloc()
            defer avutil.AvFrameFree(frame)

            if err := videoCodecContext.AvcodecSendPacket(packet); err != nil {
                log.Fatal("无法发送视频包:", err)
            }

            for videoCodecContext.AvcodecReceiveFrame(frame) == nil {
                // 缩放视频帧
                swscale.SwsScale(
                    swscaleContext,
                    frame.Data(), frame.Linesize(),
                    0, frame.Height(),
                    encodeFrame.Data(), encodeFrame.Linesize(),
                )

                // 编码视频帧
                encodeFrame.SetPts(frame.Pts())
                packet := avcodec.AvPacketAlloc()
                if err := avcodec.AvcodecSendFrame(videoCodecCtx, encodeFrame); err != nil {
                    log.Fatal("无法发送编码帧:", err)
                }

                if err := avcodec.AvcodecReceivePacket(videoCodecCtx, packet); err != nil {
                    log.Fatal("无法接收编码包:", err)
                }
                defer avcodec.AvPacketFree(packet)

                // 写入编码后的帧到文件
                if err := formatContext.AvWriteFrame(packet); err != nil {
                    log.Fatal("无法写入帧到文件:", err)
                }
            }
        }
    }

    // 写入视频文件尾
    if err := formatContext.AvWriteTrailer(); err != nil {
        log.Fatal("无法写入视频文件尾:", err)
    }
}
ログイン後にコピー
上記のコードでは、入力が元のビデオ フレームのサイズで、出力がスケーリングされたビデオであるビデオ スケーリング コンテキスト swscaleContext を作成します。フレームのサイズ。また、元のビデオ フレームの半分のサイズの新しいエンコーダ コンテキスト videoCodecCtx

を作成し、それを YUV420P ピクセル形式に設定します。

ビデオの各フレームを読み取った後、swscale.SwsScale()

関数を使用して指定されたサイズにスケーリングし、スケーリングされたビデオ フレームをエンコーダー Encode に送信します。次に、エンコードされたフレームを出力ビデオ ファイルに書き込みます。


概要:

Golang と FFmpeg を組み合わせることで、開発者に強力なビデオ処理ツールが提供されます。この記事では、Golang を使用して FFmpeg を呼び出し、ビデオ フレームのインターセプトおよびスケーリング機能を実装する方法を紹介し、対応するコード例を示します。これらの例が、Golang と FFmpeg を使用してビデオ データを処理する方法をより深く理解するのに役立つことを願っています。 ###

以上がGolang と FFmpeg: ビデオ フレームのインターセプトとスケーリングを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

他人の動画をDouyinに投稿することは侵害になりますか?侵害せずにビデオを編集するにはどうすればよいですか? 他人の動画をDouyinに投稿することは侵害になりますか?侵害せずにビデオを編集するにはどうすればよいですか? Mar 21, 2024 pm 05:57 PM

ショートビデオプラットフォームの台頭により、Douyinはみんなの日常生活に欠かせないものになりました。 TikTokでは世界中の面白い動画を見ることができます。他人のビデオを投稿することを好む人もいますが、「Douyin は他人のビデオを投稿することを侵害しているのでしょうか?」という疑問が生じます。この記事では、この問題について説明し、著作権を侵害せずに動画を編集する方法と、著作権侵害の問題を回避する方法について説明します。 1.Douyin による他人の動画の投稿は侵害ですか?私の国の著作権法の規定によれば、著作権者の著作物を著作権者の許可なく無断で使用することは侵害となります。したがって、オリジナルの作者または著作権所有者の許可なしに他人のビデオをDouyinに投稿することは侵害となります。 2. 著作権を侵害せずにビデオを編集するにはどうすればよいですか? 1. パブリックドメインまたはライセンスされたコンテンツの使用: パブリック

Douyin に動画を投稿して収益を得るにはどうすればよいですか?初心者はどうやってDouyinでお金を稼ぐことができますか? Douyin に動画を投稿して収益を得るにはどうすればよいですか?初心者はどうやってDouyinでお金を稼ぐことができますか? Mar 21, 2024 pm 08:17 PM

全国的なショートビデオプラットフォームであるDouyinは、自由な時間にさまざまな興味深く斬新なショートビデオを楽しむことができるだけでなく、自分自身を示し、自分の価値観を実現するステージも提供します。では、Douyin に動画を投稿してお金を稼ぐにはどうすればよいでしょうか?この記事ではこの質問に詳しく答え、TikTokでより多くのお金を稼ぐのに役立ちます。 1.Douyin に動画を投稿してお金を稼ぐにはどうすればよいですか?動画を投稿し、Douyin で一定の​​再生回数を獲得すると、広告共有プランに参加できるようになります。この収入方法はDouyinユーザーにとって最も馴染みのある方法の1つであり、多くのクリエイターにとって主な収入源でもあります。 Douyin は、アカウントの重み、動画コンテンツ、視聴者のフィードバックなどのさまざまな要素に基づいて、広告共有の機会を提供するかどうかを決定します。 TikTok プラットフォームでは、視聴者がギフトを送ったり、

小紅書ビデオ作品を公開するにはどうすればよいですか?動画を投稿する際に注意すべきことは何ですか? 小紅書ビデオ作品を公開するにはどうすればよいですか?動画を投稿する際に注意すべきことは何ですか? Mar 23, 2024 pm 08:50 PM

短編ビデオ プラットフォームの台頭により、Xiaohongshu は多くの人々が自分の生活を共有し、自分自身を表現し、トラフィックを獲得するためのプラットフォームになりました。このプラットフォームでは、ビデオ作品の公開が非常に人気のある交流方法です。では、小紅書ビデオ作品を公開するにはどうすればよいでしょうか? 1.小紅書ビデオ作品を公開するにはどうすればよいですか?まず、共有できるビデオ コンテンツがあることを確認します。携帯電話やその他のカメラ機器を使用して撮影することもできますが、画質と音声の明瞭さには注意する必要があります。 2.ビデオを編集する:作品をより魅力的にするために、ビデオを編集できます。 Douyin、Kuaishou などのプロ仕様のビデオ編集ソフトウェアを使用して、フィルター、音楽、字幕、その他の要素を追加できます。 3. 表紙を選択する: 表紙はユーザーのクリックを誘致するための鍵です。ユーザーのクリックを誘致するために、表紙には鮮明で興味深い写真を選択してください。

Huawei 携帯電話にデュアル WeChat ログインを実装するにはどうすればよいですか? Huawei 携帯電話にデュアル WeChat ログインを実装するにはどうすればよいですか? Mar 24, 2024 am 11:27 AM

Huawei 携帯電話にデュアル WeChat ログインを実装するにはどうすればよいですか?ソーシャルメディアの台頭により、WeChatは人々の日常生活に欠かせないコミュニケーションツールの1つになりました。ただし、多くの人は、同じ携帯電話で同時に複数の WeChat アカウントにログインするという問題に遭遇する可能性があります。 Huawei 社の携帯電話ユーザーにとって、WeChat の二重ログインを実現することは難しくありませんが、この記事では Huawei 社の携帯電話で WeChat の二重ログインを実現する方法を紹介します。まず第一に、ファーウェイの携帯電話に付属するEMUIシステムは、デュアルアプリケーションを開くという非常に便利な機能を提供します。アプリケーションのデュアルオープン機能により、ユーザーは同時に

画質を圧縮せずにWeiboに動画を投稿する方法_画質を圧縮せずにWeiboに動画を投稿する方法 画質を圧縮せずにWeiboに動画を投稿する方法_画質を圧縮せずにWeiboに動画を投稿する方法 Mar 30, 2024 pm 12:26 PM

1. まず携帯電話で Weibo を開き、右下隅の [Me] をクリックします (図を参照)。 2. 次に、右上隅の [歯車] をクリックして設定を開きます (図を参照)。 3. 次に、[一般設定] を見つけて開きます (図を参照)。 4. 次に、[Video Follow] オプションを入力します (図を参照)。 5. 次に、[ビデオアップロード解像度]設定を開きます(図を参照)。 6. 最後に、圧縮を避けるために [オリジナルの画質] を選択します (図を参照)。

PHP プログラミング ガイド: フィボナッチ数列を実装する方法 PHP プログラミング ガイド: フィボナッチ数列を実装する方法 Mar 20, 2024 pm 04:54 PM

プログラミング言語 PHP は、さまざまなプログラミング ロジックやアルゴリズムをサポートできる、Web 開発用の強力なツールです。その中でも、フィボナッチ数列の実装は、一般的で古典的なプログラミングの問題です。この記事では、PHP プログラミング言語を使用してフィボナッチ数列を実装する方法を、具体的なコード例を添付して紹介します。フィボナッチ数列は、次のように定義される数学的数列です。数列の最初と 2 番目の要素は 1 で、3 番目の要素以降、各要素の値は前の 2 つの要素の合計に等しくなります。シーケンスの最初のいくつかの要素

音声なしのエッジブラウザ Web ビデオを共有するための 2 つのソリューション 音声なしのエッジブラウザ Web ビデオを共有するための 2 つのソリューション Mar 14, 2024 pm 02:22 PM

多くのユーザーはブラウザで動画を視聴することを好みますが、Edge ブラウザで Web 動画を視聴するときに音が出ない場合は、どうすれば問題を解決できますか?この問題は難しいことではありません. 次に、Edge ブラウザの Web 動画で音が出ない問題を解決する方法を説明します。 Edge ブラウザの Web ビデオに音声がありませんか?方法 1: 1. まず、Edge ブラウザの上部タブを確認します。 2. タブの左側に「サウンドボタン」がありますので、ミュートになっていないことを確認してください。方法 2: 1. サウンドがミュートされていないことが確認された場合は、サウンド設定に問題がある可能性があります。 2. 右下隅にあるサウンドデバイスを右クリックし、「ボリュームシンセサイザーを開く」を選択します。 3. 開く

Douyin 15 秒は短すぎるので延長したいのですが、どうすれば延長できますか? 15秒を超えるビデオを作成するにはどうすればよいですか? Douyin 15 秒は短すぎるので延長したいのですが、どうすれば延長できますか? 15秒を超えるビデオを作成するにはどうすればよいですか? Mar 22, 2024 pm 08:11 PM

Douyin の人気により、このプラットフォームで自分の人生、才能、創造性を共有したい人が増えています。 Douyin の 15 秒制限により、多くのユーザーは十分に楽しめないと感じ、動画の再生時間を延長したいと考えています。では、Douyin での動画の再生時間を延長するにはどうすればよいでしょうか? 1. Douyin 15 秒は短すぎるので延長したいのですが、どうすれば延長できますか? 1. 複数のビデオを撮影して結合する最も便利な方法は、15 秒のビデオを複数録画し、Douyin の編集機能を使用して結合することです。録画するときは、後で接続できるように、各ビデオの最初と最後に空白スペースを残しておくようにしてください。結合されたビデオの長さは数分になる場合がありますが、これによりビデオ画面が頻繁に切り替わり、視聴体験に影響を与える可能性があります。 2. Douyin の特殊効果とステッカーを使用する Douyin は一連の特殊効果を提供します

See all articles