首页后端开发GO2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息.

2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息.

时间2023-04-21 23:39:02发布访客分类GO浏览918
导读:2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。答案2023-04-12:主要的过程包括:打开输入视频文件并查找视频流信息。根据视频流类型打开解码器,并设置解码器参数...

2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。

答案2023-04-12:

主要的过程包括:

  1. 打开输入视频文件并查找视频流信息。
  2. 根据视频流类型打开解码器,并设置解码器参数。
  3. 循环读取视频帧数据。
  4. 对每一帧数据进行解码并提取其中的运动矢量信息。
  5. 输出每个运动矢量的相关参数:帧号、来源、块大小、源位置、目标位置、标志等。

具体的过程实现在 main0 函数中,其中调用了 decode_packet 和 open_codec_context 函数来完成解码和上下文打开的过程。最终输出结果通过 fmt.Printf 函数打印到控制台上。

整个程序的主函数为 main,其中设置了 FFmpeg 库的路径和创建了一个 out 目录用于存放输出结果。

代码见moonfdd/ffmpeg-go库。

命令如下:

go run ./examples/internalexamples/extract_mvs/main.go ./resources/big_buck_bunny.mp4

golang代码如下:

package main

import (
	"fmt"
	"os"
	"unsafe"

	"github.com/moonfdd/ffmpeg-go/ffcommon"
	"github.com/moonfdd/ffmpeg-go/libavcodec"
	"github.com/moonfdd/ffmpeg-go/libavformat"
	"github.com/moonfdd/ffmpeg-go/libavutil"
)

func main0() (ret ffcommon.FInt) {

	var pkt libavformat.AVPacket

	if len(os.Args) != 2 {
    
		fmt.Printf("Usage: %s input video>
\n", os.Args[0])
		os.Exit(1)
	}
    
	src_filename = os.Args[1]

	if libavformat.AvformatOpenInput(&
fmt_ctx, src_filename, nil, nil)  0 {

		fmt.Printf("Could not open source file %s\n", src_filename)
		os.Exit(1)
	}


	if fmt_ctx.AvformatFindStreamInfo(nil)  0 {

		fmt.Printf("Could not find stream information\n")
		os.Exit(1)
	}


	open_codec_context(fmt_ctx, libavutil.AVMEDIA_TYPE_VIDEO)

	fmt_ctx.AvDumpFormat(0, src_filename, 0)
	for {

		if video_stream == nil {

			fmt.Printf("Could not find video stream in the input, aborting\n")
			ret = 1
			break
		}


		frame = libavutil.AvFrameAlloc()
		if frame == nil {

			fmt.Printf("Could not allocate frame\n")
			ret = -libavutil.ENOMEM
			break
		}
    

		fmt.Printf("framenum,source,blockw,blockh,srcx,srcy,dstx,dsty,flags\n")

		/* read frames from the file */
		for fmt_ctx.AvReadFrame(&
    pkt) >
= 0 {

			if pkt.StreamIndex == uint32(video_stream_idx) {
    
				ret = decode_packet(&
pkt)
			}

			pkt.AvPacketUnref()
			if ret  0 {

				break
			}

		}


		/* flush cached frames */
		decode_packet(nil)
		break
	}
    
	// end:
	libavcodec.AvcodecFreeContext(&
    video_dec_ctx)
	libavformat.AvformatCloseInput(&
    fmt_ctx)
	libavutil.AvFrameFree(&
frame)
	if ret  0 {

		return 1
	}
 else {

		return 0
	}

}


var fmt_ctx *libavformat.AVFormatContext
var video_dec_ctx *libavcodec.AVCodecContext
var video_stream *libavformat.AVStream
var src_filename string

var video_stream_idx ffcommon.FInt = -1
var frame *libavutil.AVFrame
var video_frame_count ffcommon.FInt

func decode_packet(pkt *libavcodec.AVPacket) ffcommon.FInt {

	ret := video_dec_ctx.AvcodecSendPacket(pkt)
	if ret  0 {

		fmt.Printf("Error while sending a packet to the decoder: %s\n", libavutil.AvErr2str(ret))
		return ret
	}
    

	for ret >
= 0 {

		ret = video_dec_ctx.AvcodecReceiveFrame(frame)
		if ret == -libavutil.EAGAIN || ret == libavutil.AVERROR_EOF {

			break
		}
 else if ret  0 {

			fmt.Printf("Error while receiving a frame from the decoder: %s\n", libavutil.AvErr2str(ret))
			return ret
		}
    

		if ret >
= 0 {

			var i ffcommon.FInt
			var sd *libavutil.AVFrameSideData

			video_frame_count++
			sd = frame.AvFrameGetSideData(libavutil.AV_FRAME_DATA_MOTION_VECTORS)
			if sd != nil {
    
				//const AVMotionVector
				// mvs := (*libavutil.AVMotionVector)(unsafe.Pointer(sd.Data))
				var a [2]libavutil.AVMotionVector
				len0 := uintptr(unsafe.Pointer(&
    a[1])) - uintptr(unsafe.Pointer(&
    a[0]))
				for i = 0;
     i  sd.Size/int32(len0);
 i++ {

					mv := (*libavutil.AVMotionVector)(unsafe.Pointer(uintptr(unsafe.Pointer(sd.Data)) + len0*uintptr(i)))
					fmt.Printf("%d,%2d,%2d,%2d,%4d,%4d,%4d,%4d,0x%d\n",
						video_frame_count, mv.Source,
						mv.W, mv.H, mv.SrcX, mv.SrcY,
						mv.DstX, mv.DstY, mv.Flags)
				}

			}

			frame.AvFrameUnref()
		}

	}


	return 0
}


func open_codec_context(fmt_ctx *libavformat.AVFormatContext, type0 libavutil.AVMediaType) ffcommon.FInt {
    
	var ret ffcommon.FInt
	var st *libavformat.AVStream
	var dec_ctx *libavcodec.AVCodecContext
	var dec *libavcodec.AVCodec
	var opts *libavutil.AVDictionary

	ret = fmt_ctx.AvFindBestStream(type0, -1, -1, &
dec, 0)
	if ret  0 {

		fmt.Printf("Could not find %s stream in input file '%s'\n",
			libavutil.AvGetMediaTypeString(type0), src_filename)
		return ret
	}
 else {

		stream_idx := ret
		st = fmt_ctx.GetStream(uint32(stream_idx))

		dec_ctx = dec.AvcodecAllocContext3()
		if dec_ctx == nil {

			fmt.Printf("Failed to allocate codec\n")
			return -libavutil.EINVAL
		}


		ret = dec_ctx.AvcodecParametersToContext(st.Codecpar)
		if ret  0 {

			fmt.Printf("Failed to copy codec parameters to codec context\n")
			return ret
		}
    

		/* Init the video decoder */
		libavutil.AvDictSet(&
    opts, "flags2", "+export_mvs", 0)
		ret = dec_ctx.AvcodecOpen2(dec, &
opts)
		if ret  0 {

			fmt.Printf("Failed to open %s codec\n",
				libavutil.AvGetMediaTypeString(type0))
			return ret
		}


		video_stream_idx = stream_idx
		video_stream = fmt_ctx.GetStream(uint32(video_stream_idx))
		video_dec_ctx = dec_ctx
	}


	return 0
}


func main() {
    
	os.Setenv("Path", os.Getenv("Path")+";
./lib")
	ffcommon.SetAvutilPath("./lib/avutil-56.dll")
	ffcommon.SetAvcodecPath("./lib/avcodec-58.dll")
	ffcommon.SetAvdevicePath("./lib/avdevice-58.dll")
	ffcommon.SetAvfilterPath("./lib/avfilter-7.dll")
	ffcommon.SetAvformatPath("./lib/avformat-58.dll")
	ffcommon.SetAvpostprocPath("./lib/postproc-55.dll")
	ffcommon.SetAvswresamplePath("./lib/swresample-3.dll")
	ffcommon.SetAvswscalePath("./lib/swscale-5.dll")

	genDir := "./out"
	_, err := os.Stat(genDir)
	if err != nil {

		if os.IsNotExist(err) {

			os.Mkdir(genDir, 0777) //  Everyone can read write and execute
		}

	}


	main0()
}
    

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!

go音视频流媒体ffmpeg

若转载请注明出处: 2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息.
本文地址: https://pptw.com/jishu/4812.html
python – 函数/方法 移动端“动态化”是什么意思?

游客 回复需填写必要信息