2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
答案2023-04-12:
主要的过程包括:
- 打开输入视频文件并查找视频流信息。
- 根据视频流类型打开解码器,并设置解码器参数。
- 循环读取视频帧数据。
- 对每一帧数据进行解码并提取其中的运动矢量信息。
- 输出每个运动矢量的相关参数:帧号、来源、块大小、源位置、目标位置、标志等。
具体的过程实现在 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()
}

2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。的更多相关文章
- FFMPEG,将字幕“烧进”MP4视频中
		原文地址:http://blog.csdn.net/ufocode/article/details/75475539 由于mp4容器,不像MKV等容器有自己的字幕流. MKV这种容器的视频格式中,会带 ... 
- ffmpeg使用C语言sdk实现抽取视频中的视频数据
		主要使用函数 特征码:Start code 解码的一些视频参数,分辨率和帧率:SPS/PPS ffmpeg获取SPS/PPS:codec->extradata 实例 #include <s ... 
- java 时间格式化(2016.04.12 12:32:55)
		输入的时间格式如:2016.04.12 12:32:55所示: 想要获取一定格式的日期,时间的方法 String startString = "2016.04.25 12:25:44&quo ... 
- Ubuntu 13.04/12.10安装Oracle 11gR2图文教程(转)
		Ubuntu 13.04/12.10安装Oracle 11gR2图文教程 原文标题:How to Install Oracle 11G R2 Enterprise Edition Database U ... 
- Ubuntu LTS 系统学习使用体会和实用工具软件汇总 6.04 8.04 10.04 12.04 14.04 16.04
		Ubuntu LTS 系统学习体会和工具软件汇总 6.04 8.04 10.04 12.04 14.04 16.04 ubuntu入门必备pdf:http://download.csdn.net/de ... 
- FFmpeg简易播放器的实现-音视频同步
		本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10284653.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ... 
- FFmpeg 向视频中添加文字
		原文地址:http://www.cnblogs.com/wanggang123/p/6707985.html FFmpeg支持添加文字功能,具体如何将文字叠加到视频中的每一张图片,FFmpeg调用了文 ... 
- 解惑:在Ubuntu18.04.2的idea上运行Scala支持的spark程序遇到的问题
		解惑:在Ubuntu18.04.2的idea上运行Scala支持的spark程序遇到的问题 一.前言 最近在做一点小的实验,用到了Scala,spark这些东西,于是在Linux平台上来完成,结果一个 ... 
- 最简单的基于FFmpeg的移动端例子:IOS 视频解码器-保存
		===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ... 
- 最简单的基于FFmpeg的移动端例子:IOS 视频转码器
		===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ... 
随机推荐
- database.property文件
			注意修改用户名密码 mysql8的版本要注意配置时区 此文件放置连接数据库的相关参数 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://l ... 
- 前端小白启动开源框架vue-element
			开发java的我按耐不住想学前端的冲动不想看培训机构的视频,决定自学遇到那种"前端知识图谱"的知识架构,看一眼就完了,不能拿来做入门用入门就得是先把工作环境搭起来,能出活就ok了 ... 
- 禅道  docker 部署
			官方文档:https://hub.docker.com/r/idoop/zentao 1.创建本地目录:mkdir -p /data/zbox 2.启动容器: sudo docker run -itd ... 
- ASP.NET Web应用程序(.NET Framework)开发网站
			1.创建项目 2.控制器脚本说明 [FromBody]JObject value:JObject此类型默认为string,但是string无法正常解析复杂类型的Json数据,所以修改为JObject类 ... 
- 【python】yaml文件的读写
			[python]yaml文件的读写 冰冷的希望 2020-10-22 18:31:47 442 收藏 1分类专栏: python 文章标签: python yaml版权 python专栏收录该内容67 ... 
- Spring 的核心组件详解
			Spring 总共有十几个组件,但是真正核心的组件只有三个:Core.Context 和 Bean.它们构建起了整个 Spring的骨骼架构,没有它们就不可能有 AOP.Web 等上层的特性功能. 一 ... 
- SpringCloud Ribbon 负载均衡
			Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具.可以将面向服务的 REST 模板请求自动转化成客户端负载均衡的服务调用.Spring Cloud Rib ... 
- QGIS 导入文本数据(WKT)
			在做GIS数据处理的时候,经常会遇到原始数据是 text.csv.Excel 等格式的数据.要使用数据前提是要先转换数据. 这里是介绍用 QGIS 导入数据.打开导入方式如下(根据自己的文本类型选择不 ... 
- noopener, noreferrer 及 nofollow 的用法
			<a> 标签通常会配合着使用 noopener, noreferrer 及 nofollow 这些属性, 它们的作用及用法如下. noopener 当给链接加上 target=" ... 
- [云计算]概念辨析:云计算 [IaaS/PaaS/SaaS & 公有云/私有云/混合云]
			1 云计算(Cloud Computing) 1.0 云计算的发展 1.1 概念 "云"实质上就是一个[网络], 狭义上讲,云计算就是一种提供资源的网络,使用者可以随时获取&quo ... 
