Golang と FFmpeg を使用してビデオのちらつきを除去する実践
Golang と FFmpeg を使用してビデオのちらつきを解消する方法
概要:
ビデオのちらつきの問題は、ビデオ処理でよく遭遇する課題です。プロセス。録画した映像のフレームレートと点灯周波数が一致していない場合、映像がちらつく場合があります。この記事では、Golang ライブラリと FFmpeg ライブラリを使用してビデオのちらつきを除去する方法を紹介し、具体的なコード例を示します。
手順:
-
FFmpeg ライブラリをインストールします:
まず、Golang 開発環境に FFmpeg ライブラリをインストールする必要があります。次のコマンドでインストールできます:
go get github.com/giorgisio/goav/avcodecgithub.com/giorgisio/goav/avfilter github.com/giorgisio/goav/avutil github.com/giorgisio/goav/swscale
ログイン後にコピー ビデオ ファイルを開きます:
Use avformat.OpenInput( in FFmpeg ライブラリ ) 関数は、処理する必要があるビデオ ファイルを開きます。ビデオ ファイルのパスをパラメータとして渡して、ビデオ ファイルの関連情報を取得します。サンプル コードは次のとおりです。
package main import ( "fmt" "github.com/giorgisio/goav/avformat" ) func main() { filepath := "path_to_video_file.mp4" avformat.AvRegisterAll() // 打开视频文件 ctx := avformat.AvformatAllocContext() if err := avformat.AvformatOpenInput(&ctx, filepath, nil, nil); err != 0 { fmt.Printf("无法打开文件 %s: %s ", filepath, avutil.AvStrerror(err)) } defer avformat.AvformatCloseInput(&ctx) // 获取视频文件信息 if err := avformat.AvformatFindStreamInfo(ctx, nil); err < 0 { fmt.Printf("无法获取文件信息: %s ", avutil.AvStrerror(err)) } }
ログイン後にコピービデオ フレームの処理:
FFmpeg ライブラリの avcodec.AvcodecDecodeVideo2() 関数を使用して、ビデオ フレームをデコードします。ビデオ フレームをループして各フレームを処理します。処理中に、Golang の画像処理ライブラリ (GoCV など) を使用して、明るさの低減、コントラストの増加などの画像処理操作を実行できます。サンプル コードは次のとおりです:
package main import ( "fmt" "github.com/giorgisio/goav/avcodec" "github.com/giorgisio/goav/avformat" "github.com/giorgisio/goav/avutil" "github.com/giorgisio/goav/swscale" "gocv.io/x/gocv" ) func main() { filepath := "path_to_video_file.mp4" avformat.AvRegisterAll() // 打开视频文件 ctx := avformat.AvformatAllocContext() if err := avformat.AvformatOpenInput(&ctx, filepath, nil, nil); err != 0 { fmt.Printf("无法打开文件 %s: %s ", filepath, avutil.AvStrerror(err)) } defer avformat.AvformatCloseInput(&ctx) // 获取视频文件信息 if err := avformat.AvformatFindStreamInfo(ctx, nil); err < 0 { fmt.Printf("无法获取文件信息: %s ", avutil.AvStrerror(err)) } // 查找视频流索引 streamIndex := avutil.AvFindBestStream(ctx, avutil.AvmediaType(avformat.AvmTypeVideo), -1, -1, nil, 0) codecParams := ctx.Streams()[streamIndex].CodecParameters() // 获取解码器 codec := avcodec.AvcodecFindDecoder(codecParams.CodecId()) if codec == nil { fmt.Println("无法获取解码器") } // 打开解码器 codecCtx := avcodec.AvcodecAllocContext3(codec) if err := avcodec.AvcodecParametersToContext(codecCtx, codecParams); err < 0 { fmt.Printf("无法打开解码器: %s ", avutil.AvStrerror(err)) } defer avcodec.AvcodecFreeContext(&codecCtx) if err := avcodec.AvcodecOpen2(codecCtx, codec, nil); err < 0 { fmt.Printf("无法打开解码器: %s ", avutil.AvStrerror(err)) } // 初始化帧 frame := avutil.AvFrameAlloc() defer avutil.AvFrameFree(&frame) // 初始化解码器上下文 packet := avcodec.AvPacketAlloc() defer avcodec.AvPacketFree(&packet) swsCtx := swscale.SwsGetContext(codecParams.Width(), codecParams.Height(), codecCtx.PixFmt(), codecParams.Width(), codecParams.Height(), avutil.AV_PIX_FMT_BGR24, swscale.SWS_BICUBIC, nil, nil, nil) defer swscale.SwsFreeContext(&swsCtx) for { // 读取帧 if err := avformat.AvReadFrame(ctx, packet); err != 0 { fmt.Printf("无法读取帧: %s ", avutil.AvStrerror(err)) break } if packet.StreamIndex() == streamIndex { if err := avcodec.AvcodecSendPacket(codecCtx, packet); err < 0 { fmt.Printf("无法发送数据包到解码器: %s ", avutil.AvStrerror(err)) } if err := avcodec.AvcodecReceiveFrame(codecCtx, frame); err < 0 { fmt.Printf("无法接收解码帧: %s ", avutil.AvStrerror(err)) } // 进行图像处理操作 img := gocv.NewMatFromBytes(codecParams.Width(), codecParams.Height(), gocv.MatType(gocv.MatTypeCV8UC3), frame.Data(0)) imgDst := gocv.NewMat() // 图像处理操作,以减少亮度为例 gocv.ConvertScaleAbs(img, &imgDst, 0.5, 0) // 输出图像 fmt.Printf("输出图像: %v ", imgDst) img.Close() imgDst.Close() } avcodec.AvPacketUnref(packet) } }
ログイン後にコピー処理されたビデオを書き込みます:
FFmpeg ライブラリの avcodec.AvcodecEncodeVideo2() 関数を使用して、処理されたビデオをエンコードしますvideo Frame を作成し、 avformat.AvWriteFrame() 関数を使用して、エンコードされたフレームをターゲット ビデオ ファイルに書き込みます。サンプル コードは次のとおりです:
package main import ( "fmt" "github.com/giorgisio/goav/avcodec" "github.com/giorgisio/goav/avformat" "github.com/giorgisio/goav/avutil" "github.com/giorgisio/goav/swscale" "gocv.io/x/gocv" ) func main() { filepath := "path_to_video_file.mp4" outputpath := "path_to_output_file.mp4" avformat.AvRegisterAll() // 打开视频文件 ctx := avformat.AvformatAllocContext() if err := avformat.AvformatOpenInput(&ctx, filepath, nil, nil); err != 0 { fmt.Printf("无法打开文件 %s: %s ", filepath, avutil.AvStrerror(err)) } defer avformat.AvformatCloseInput(&ctx) // 获取视频文件信息 if err := avformat.AvformatFindStreamInfo(ctx, nil); err < 0 { fmt.Printf("无法获取文件信息: %s ", avutil.AvStrerror(err)) } // 查找视频流索引 streamIndex := avutil.AvFindBestStream(ctx, avutil.AvmediaType(avformat.AvmTypeVideo), -1, -1, nil, 0) codecParams := ctx.Streams()[streamIndex].CodecParameters() // 获取解码器 codec := avcodec.AvcodecFindDecoder(codecParams.CodecId()) if codec == nil { fmt.Println("无法获取解码器") } // 打开解码器 codecCtx := avcodec.AvcodecAllocContext3(codec) if err := avcodec.AvcodecParametersToContext(codecCtx, codecParams); err < 0 { fmt.Printf("无法打开解码器: %s ", avutil.AvStrerror(err)) } defer avcodec.AvcodecFreeContext(&codecCtx) if err := avcodec.AvcodecOpen2(codecCtx, codec, nil); err < 0 { fmt.Printf("无法打开解码器: %s ", avutil.AvStrerror(err)) } // 初始化帧 frame := avutil.AvFrameAlloc() defer avutil.AvFrameFree(&frame) // 初始化解码器上下文 packet := avcodec.AvPacketAlloc() defer avcodec.AvPacketFree(&packet) swsCtx := swscale.SwsGetContext(codecParams.Width(), codecParams.Height(), codecCtx.PixFmt(), codecParams.Width(), codecParams.Height(), avutil.AV_PIX_FMT_BGR24, swscale.SWS_BICUBIC, nil, nil, nil) defer swscale.SwsFreeContext(&swsCtx) // 创建输出格式上下文 fmtCtx := avformat.AvformatAllocContext() defer avformat.AvformatFreeContext(fmtCtx) // 设置输出文件的格式 fmtCtx.SetOutputFormat(avformat.AvGuessFormat("", outputpath, "")) // 创建输出文件 if avformat.AvioOpen(&fmtCtx.Pb, outputpath, avformat.AVIO_FLAG_WRITE) < 0 { fmt.Println("无法打开输出文件") } // 写入文件头部 if avformat.AvformatWriteHeader(fmtCtx, nil) < 0 { fmt.Println("无法写入文件头部") } for { // 读取帧 if err := avformat.AvReadFrame(ctx, packet); err != 0 { fmt.Printf("无法读取帧: %s ", avutil.AvStrerror(err)) break } if packet.StreamIndex() == streamIndex { if err := avcodec.AvcodecSendPacket(codecCtx, packet); err < 0 { fmt.Printf("无法发送数据包到解码器: %s ", avutil.AvStrerror(err)) } if err := avcodec.AvcodecReceiveFrame(codecCtx, frame); err < 0 { fmt.Printf("无法接收解码帧: %s ", avutil.AvStrerror(err)) } // 进行图像处理操作 img := gocv.NewMatFromBytes(codecParams.Width(), codecParams.Height(), gocv.MatType(gocv.MatTypeCV8UC3), frame.Data(0)) imgDst := gocv.NewMat() // 图像处理操作,以减少亮度为例 gocv.ConvertScaleAbs(img, &imgDst, 0.5, 0) // 将处理后的图像数据转换为原始数据 dstData := imgDst.ToBytes() // 创建输出帧 outputFrame := avutil.AvFrameAlloc() defer avutil.AvFrameFree(&outputFrame) outputFrame.SetData(dstData) // 编码输出帧 if err := avcodec.AvcodecSendFrame(codecCtx, outputFrame); err < 0 { fmt.Printf("无法发送输出帧到编码器: %s ", avutil.AvStrerror(err)) } for err := avcodec.AvcodecReceivePacket(codecCtx, packet); err >= 0; err = avcodec.AvcodecReceivePacket(codecCtx, packet) { packet.SetStreamIndex(0) packet.RescaleTs(codecCtx.TimeBase(), ctx.Streams()[streamIndex].TimeBase()) if err := avformat.AvWriteFrame(fmtCtx, packet); err < 0 { fmt.Printf("无法写入帧: %s ", avutil.AvStrerror(err)) } avcodec.AvPacketUnref(packet) } img.Close() imgDst.Close() } avcodec.AvPacketUnref(packet) } // 写入文件尾部 avformat.AvWriteTrailer(fmtCtx) }
ログイン後にコピー
概要:
この記事では、Golang ライブラリと FFmpeg ライブラリを使用してビデオのちらつきを除去する方法を紹介し、以下を提供します。詳細なコード例。 FFmpeg ライブラリの関数を使用すると、ビデオ ファイルを開いてビデオ フレームを処理し、処理されたフレームを再エンコードしてターゲット ビデオ ファイルに書き込むことができます。実際には、ビデオのちらつきの問題を解決するために、特定のニーズに応じて画像処理操作を実行できます。 Golang と FFmpeg の機能を活用することで、ビデオのちらつきの問題をより柔軟かつ効率的に処理できます。
以上がGolang と FFmpeg を使用してビデオのちらつきを除去する実践の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

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

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

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

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

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

ホットトピック









Go ではファイルを安全に読み書きすることが重要です。ガイドラインには以下が含まれます。 ファイル権限の確認 遅延を使用してファイルを閉じる ファイル パスの検証 コンテキスト タイムアウトの使用 これらのガイドラインに従うことで、データのセキュリティとアプリケーションの堅牢性が確保されます。

Go データベース接続の接続プーリングを構成するにはどうすればよいですか?データベース接続を作成するには、database/sql パッケージの DB タイプを使用します。同時接続の最大数を制御するには、MaxOpenConns を設定します。アイドル状態の接続の最大数を設定するには、ConnMaxLifetime を設定します。

Go フレームワークは、その高いパフォーマンスと同時実行性の利点で際立っていますが、比較的新しい、開発者エコシステムが小さい、一部の機能が欠けているなどの欠点もあります。さらに、急速な変化と学習曲線はフレームワークごとに異なる場合があります。 Gin フレームワークは、効率的なルーティング、組み込みの JSON サポート、強力なエラー処理機能により、RESTful API を構築するための一般的な選択肢です。

GoLang フレームワークと Go フレームワークの違いは、内部アーキテクチャと外部機能に反映されています。 GoLang フレームワークは Go 標準ライブラリに基づいてその機能を拡張していますが、Go フレームワークは特定の目的を達成するための独立したライブラリで構成されています。 GoLang フレームワークはより柔軟であり、Go フレームワークは使いやすいです。 GoLang フレームワークはパフォーマンスの点でわずかに優れており、Go フレームワークはよりスケーラブルです。ケース: gin-gonic (Go フレームワーク) は REST API の構築に使用され、Echo (GoLang フレームワーク) は Web アプリケーションの構築に使用されます。

JSON データは、gjson ライブラリまたは json.Unmarshal 関数を使用して MySQL データベースに保存できます。 gjson ライブラリは、JSON フィールドを解析するための便利なメソッドを提供します。json.Unmarshal 関数には、JSON データをアンマーシャリングするためのターゲット型ポインターが必要です。どちらの方法でも、SQL ステートメントを準備し、データをデータベースに永続化するために挿入操作を実行する必要があります。

ベスト プラクティス: 明確に定義されたエラー タイプ (エラー パッケージ) を使用してカスタム エラーを作成する 詳細を提供する エラーを適切にログに記録する エラーを正しく伝播し、非表示または抑制しないようにする コンテキストを追加するために必要に応じてエラーをラップする

FindStringSubmatch 関数は、正規表現に一致する最初の部分文字列を検索します。この関数は、最初の要素が一致した文字列全体で、後続の要素が個々の部分文字列である、一致する部分文字列を含むスライスを返します。コード例: regexp.FindStringSubmatch(text,pattern) は、一致する部分文字列のスライスを返します。実際のケース: 電子メール アドレスのドメイン名を照合するために使用できます。たとえば、email:="user@example.com", pattern:=@([^\s]+)$ を使用してドメイン名を照合します。 [1]。

バックエンド学習パス:フロントエンドからバックエンドへの探査の旅は、フロントエンド開発から変わるバックエンド初心者として、すでにNodeJSの基盤を持っています...
