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 (
"fmt"
"log"
"github.com/giorgisio/goav/avcodec"
"github.com/giorgisio/goav/avformat"
)
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)
// 读取视频帧
packet := avcodec.AvPacketAlloc()
defer avcodec.AvPacketFree(packet)
for formatContext.AvReadFrame(packet) >= 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("视频帧:%d
", frame.Pts())
}
}
}
}
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
上記のコードでは、まず avformat.AvformatAllocContext()
を使用してフォーマット コンテキスト オブジェクトを割り当て、次に avformat.AvformatOpenInput( )
ビデオ ファイルが開かれました。次に、avformat.AvformatFindStreamInfo()
を使用してビデオ ストリームを検索し、
を使用してそれがビデオ ストリームであるかどうかを判断します。 次に、
avcodec.AvcodecFindDecoder()
を使用して適切なデコーダを見つけ、avcodec.AvcodecParametersToContext()
と
最後に、
formatContext.AvReadFrame() を使用してビデオ フレームを読み取り、
videoCodecContext.AvcodecReceiveFrame()
ビデオ スケーリング:
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()
概要:
以上がGolang と FFmpeg: ビデオ フレームのインターセプトとスケーリングを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

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

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

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

ホットトピック











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

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

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

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

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

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

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

ビデオ理解の中心的な目標は、時空間表現を正確に理解することですが、2 つの主な課題に直面しています。それは、短いビデオ クリップには大量の時空間的冗長性があり、もう 1 つは複雑な時空間依存関係です。 3 次元畳み込みニューラル ネットワーク (CNN) とビデオ トランスフォーマーは、これらの課題の 1 つを解決するのにうまく機能していますが、両方の課題に同時に対処するにはいくつかの欠点があります。 UniFormer は両方のアプローチの利点を組み合わせようとしますが、長いビデオをモデリングする際に困難に直面します。自然言語処理の分野における S4、RWKV、RetNet などの低コスト ソリューションの出現により、ビジュアル モデルに新たな道が開かれました。 Mamba は、線形の複雑さを維持しながら長期的なダイナミクスを可能にする選択的状態空間モデル (SSM) で際立っています。
