2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
答案2023-04-01:
步骤如下:
1.导入必要的依赖库,包括 fmt、os、unsafe 和其它 FFmpeg 库相关的 Go 库。
2.定义一个名为 main0() 的函数,该函数负责视频解码操作。在函数中定义了许多变量,例如文件名、编解码器、解析器、编解码器上下文、文件句柄、AVFrame 等等。
3.通过命令行参数获取输入文件名和输出文件名,并进行一些基本的参数检查。
4.通过调用 AvPacketAlloc() 函数创建一个 AVPacket 对象,用于存储解码后的帧数据。如果创建失败,则退出程序。
5.初始化输入缓冲区 inbuf 并设置结尾填充字节为 0。
6.调用 AvcodecFindDecoder() 函数查找 MPEG-1 视频解码器。如果找不到,则退出程序。
7.调用 AvParserInit() 函数初始化解析器。如果初始化失败,则退出程序。
8.调用 AvCodecAllocContext3() 函数分配一个新的编解码器上下文对象。如果分配失败,则退出程序。
9.调用 AvcodecOpen2() 函数打开编解码器。如果打开失败,则退出程序。
10.打开输入文件,并创建一个 AVFrame 对象。
11.进入循环,读取输入文件并将其分解成视频帧。如果读取失败或读取完毕,则跳出循环。
12.调用 AvParserParse2() 函数将输入缓冲区中的数据解析为视频帧,并存储在 AVPacket 对象中。如果解析失败,则退出程序。
13.如果成功解析到一个视频帧,则调用 decode() 函数对其进行解码并保存到输出文件中。
14.在循环结束后,调用 decode() 函数对剩余的数据进行解码并保存到输出文件中。
15.关闭输入文件句柄、解析器、编解码器上下文和 AVFrame 对象等资源,以避免内存泄漏。
16.定义一个名为 pgm_save() 的函数,该函数用于将视频帧写入 PGM 格式文件。
17.定义一个名为 decode() 的函数,该函数用于对视频帧进行解码并调用 pgm_save() 函数将其写入 PGM 格式文件。
18.定义 main() 函数,该函数将 FFmpeg 库的路径设置为当前目录下的 lib 子目录,并调用 main0() 函数进行视频解码操作。
注意:在 Windows 操作系统中,您可能需要将 FFmpeg 库的可执行文件添加到 PATH 环境变量中,或者使用 SetXXXPath() 函数设置它们的路径,才能够正常运行此代码。
代码见github/moonfdd/ffmpeg-go。
执行命令:
./lib/ffmpeg -i ./resources/big_buck_bunny.mp4 -c:v mpeg1video ./out/big_buck_bunny.mpggo run ./examples/internalexamples/decode_video/main.go ./out/big_buck_bunny.mpg ./out/ppm/big_buck_bunny.yuv./lib/ffplay ./out/ppm/big_buck_bunny.yuv-113.ppm
golang代码如下:
package mainimport ("fmt""os""unsafe""github.com/moonfdd/ffmpeg-go/ffcommon""github.com/moonfdd/ffmpeg-go/libavcodec""github.com/moonfdd/ffmpeg-go/libavutil"
)func main0() (ret ffcommon.FInt) {var filename, outfilename stringvar codec *libavcodec.AVCodecvar parser *libavcodec.AVCodecParserContextvar c *libavcodec.AVCodecContextvar f *os.Filevar frame *libavutil.AVFramevar inbuf [INBUF_SIZE + libavcodec.AV_INPUT_BUFFER_PADDING_SIZE]ffcommon.FUint8Tvar data *ffcommon.FUint8Tvar data_size ffcommon.FSizeTvar pkt *libavcodec.AVPacketif len(os.Args) <= 2 {fmt.Printf("Usage: %s <input file> <output file>\nAnd check your input file is encoded by mpeg1video please.\n", os.Args[0])os.Exit(0)}filename = os.Args[1]outfilename = os.Args[2]pkt = libavcodec.AvPacketAlloc()if pkt == nil {os.Exit(1)}/* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) *///memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);/* find the MPEG-1 video decoder */codec = libavcodec.AvcodecFindDecoder(libavcodec.AV_CODEC_ID_MPEG1VIDEO)if codec == nil {fmt.Printf("Codec not found\n")os.Exit(1)}parser = libavcodec.AvParserInit(int32(codec.Id))if parser == nil {fmt.Printf("parser not found\n")os.Exit(1)}c = codec.AvcodecAllocContext3()if c == nil {fmt.Printf("Could not allocate video codec context\n")os.Exit(1)}/* For some codecs, such as msmpeg4 and mpeg4, width and heightMUST be initialized there because this information is notavailable in the bitstream. *//* open it */if c.AvcodecOpen2(codec, nil) < 0 {fmt.Printf("Could not open codec\n")os.Exit(1)}var err errorf, err = os.Open(filename)if err != nil {fmt.Printf("Could not open %s,err = %s\n", filename, err)os.Exit(1)}frame = libavutil.AvFrameAlloc()if frame == nil {fmt.Printf("Could not allocate video frame\n")os.Exit(1)}for {/* read raw data from the input file */var n intn, err = f.Read(inbuf[:INBUF_SIZE])if err != nil {break}data_size = uint64(n)if data_size == 0 {break}/* use the parser to split the data into frames */data = (*byte)(unsafe.Pointer(&inbuf))for data_size > 0 {ret = parser.AvParserParse2(c, &pkt.Data, (*int32)(unsafe.Pointer(&pkt.Size)),data, int32(data_size), libavutil.AV_NOPTS_VALUE, libavutil.AV_NOPTS_VALUE, 0)if ret < 0 {fmt.Printf("Error while parsing\n")os.Exit(1)}data = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(data)) + uintptr(ret)))data_size -= uint64(ret)if pkt.Size != 0 {decode(c, frame, pkt, outfilename)}}}/* flush the decoder */decode(c, frame, nil, outfilename)f.Close()parser.AvParserClose()libavcodec.AvcodecFreeContext(&c)libavutil.AvFrameFree(&frame)libavcodec.AvPacketFree(&pkt)return 0
}const INBUF_SIZE = 4096func pgm_save(buf ffcommon.FBuf, wrap, xsize, ysize ffcommon.FInt, filename string) {var f *os.Filevar i ffcommon.FIntvar err errorf, err = os.Create(filename)if err != nil {return}f.WriteString(fmt.Sprintf("P5\n%d %d\n%d\n", xsize, ysize, 255))bytes := []byte{}for i = 0; i < ysize; i++ {for j := int32(0); j < xsize; j++ {bytes = append(bytes, *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(buf)) + uintptr(i*wrap+j))))}}f.Write(bytes)f.Close()
}func decode(dec_ctx *libavcodec.AVCodecContext, frame *libavutil.AVFrame, pkt *libavcodec.AVPacket, filename string) {// var buf [1024]bytevar ret ffcommon.FIntret = dec_ctx.AvcodecSendPacket(pkt)if ret < 0 {fmt.Printf("Error sending a packet for decoding\n")os.Exit(1)}for ret >= 0 {ret = dec_ctx.AvcodecReceiveFrame(frame)if ret == -libavutil.EAGAIN || ret == libavutil.AVERROR_EOF {return} else if ret < 0 {fmt.Printf("Error during decoding %d\n", ret)os.Exit(1)}fmt.Printf("saving frame %3d\n", dec_ctx.FrameNumber)//fflush(stdout)/* the picture is allocated by the decoder. no need tofree it */pgm_save(frame.Data[0], frame.Linesize[0],frame.Width, frame.Height, fmt.Sprintf("%s-%d.ppm", filename, dec_ctx.FrameNumber))}
}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-56.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-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。 答案2023-04-01: 步骤如下: 1.导入必要的依赖库,包括 fmt、os、unsafe 和其它 FFmpeg 库相关…...
Solidity 学习笔记
主要参考网上资料学习,个人学习笔记有删改,参考出处在文末列出。 0 基础 IDE: remixType Bool: bool public _bool true; 默认false;整型:int、uint、uint256,默认0;地址类型:address,分为 payable 和普…...
ThreadLocal原理
关键点总结: ThreadLocal更像是对其他类型变量的一层包装,通过ThreadLocal的包装使得该变量可以在线程之间隔离和当前线程全局共享。在Thread中有一个threadLocals变量,类型为ThreadLocal.ThreadLocalMap,ThreadLocalMap中key是Th…...
串操作指令详解 MOVS,LODS,STOS,CMPS,SCAS,REP
指令包括:MOVS,LODS,STOS,CMPS,SCAS,REP 串的概念:串是连续存放再内存中的字节块或字块。每个串有一个起始地址和长度, 待操作的数据串称为源串,目的地址称为目标串 目录…...
Java实现判断素数
1 问题 判断101-200之间有多少个素数,并输出所有素数。 2 方法 package homework04; public class Test05 { public static void main(String[] args) { for (int i 101; i < 201; i) { boolean flag true; for (int j 2; j…...
PHP初级教程------------------(2)
目录 运算符 赋值运算符 算术运算符 比较运算符 逻辑运算符 连接运算符 错误抑制符 三目运算符 自操作运算符 编辑 计算机码 位运算符 运算符优先级 流程控制 控制分类 顺序结构 分支结构 If分支 Switch分支 循环结构 For循环 while循环 do-while循环 循环控制 …...
【SQL开发实战技巧】系列(三十五):数仓报表场景☞根据条件返回不同列的数据以及Left /Full Join注意事项
系列文章目录 【SQL开发实战技巧】系列(一):关于SQL不得不说的那些事 【SQL开发实战技巧】系列(二):简单单表查询 【SQL开发实战技巧】系列(三):SQL排序的那些事 【SQL开发实战技巧…...
springBoot自动配置过程介绍
什么是自动配置 以前整合spring mybatis框架时候,需要加很多的bean, 比如说sqlSessionFactory等等 现在springboot帮我们干了,我们只需要引入对应的starter就可以了。 springBoot可以帮我们配置好了一些bean. 如mysql, mogondb相关操作等等ÿ…...
PostgreSQL最后的救命稻草 — pg_resetwal
pg_resetwal— 重置 PostgreSQL 数据库集群的预写日志和其他控制信息 适用版本:PostgreSQL 12/13/14/15语法 pg_resetwal [ -f | --force ] [ -n | --dry-run ] [option...] [ -D | --pgdata ]datadir描述pg_resetwal清除预写日志 WAL,并可选地重置pg_c…...
彻底关闭Windows更新
一、关闭Windows Update服务 1、按“Windows R”键,打开运行对话框,并输入“services.msc”,然后再单击“确定”。 2、在弹出的服务窗口中,找到“Windows Update”选项并双击打开它。 3、在弹出的“Windows Update的属性”对话框…...
Java正则表达式语法
Java正则表达式的语法与示例 | |目录 1匹配验证-验证Email是否正确 2在字符串中查询字符或者字符串 3常用正则表达式 4正则表达式语法 1匹配验证-验证Email是否正确 public static void main(String[] args) { // 要验证的字符串 String str "servicexsoftlab.net&q…...
【2023-3-29】JavaScript使用promise顺序调用函数并抛出异常
JavaScript使用promise顺序调用函数并抛出异常 场景 新建或者编辑时,一个页面中存在多个表单,每个表单都有单独进行表单验证。点击提交时,若有一个表单校验失败,则不能提交。 ps:为啥不放在一个表单中? (…...
Python实现GWO智能灰狼优化算法优化随机森林分类模型(RandomForestClassifier算法)项目实战
说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 灰狼优化算法(GWO),由澳大利亚格里菲斯大学学者 Mirjalili 等人于2014年提出来的一种群智能…...
从redis到epoll到mmap
redis为什么这么快? 比较容易答出的答案 1)纯粹的内存操作 2)单线程操作,不用考虑线程切换 其他优势 3)I/O 多路复用,使用epoll 4)Reactor 设计模式 I/O 多路复用有三种 select、poll、epoll select:使用数组存储轮询 poll:使用链表轮询 epo…...
STM32CubeMX快速构造工程模板(一)
STM32CubeMX作为一个免费开源的软件,能够可视化配置STM32或其他产品硬件资源,能过快速地构造工程模板,很是方便!!! 目录 STM32CubeMX快速构造工程模板 首先第一步,打开软件-点击按钮-输入型号-双击打开。...
Java Web中的ServletContext对象
目录 ServletContext对象 获取上下文初始化参数的相关方法 创建ServletContext对象 1)通过 GenericServlet 提供的 getServletContext() 方法 2)通过 ServletConfig 提供的 getServletContext() 方法 3)通过 HttpSession 提供的 getServletCo…...
回归预测 | MATLAB实现PSO-RF粒子群算法优化随机森林多输入单输出回归预测
回归预测 | MATLAB实现PSO-RF粒子群算法优化随机森林多输入单输出回归预测 目录回归预测 | MATLAB实现PSO-RF粒子群算法优化随机森林多输入单输出回归预测效果一览基本介绍程序设计参考资料效果一览 基本介绍 MATLAB实现PSO-RF粒子群算法优化随机森林多输入单输出回归预测 粒子…...
在小公司工作3年,从事软件测试5年了,才发现自己还是处于“初级“水平,是不是该放弃....
毕业前三年,从早到晚,加班到深夜,一年又一年,直至刚入职场的首个黄金三年过年都去了,而职位却仍在原地踏步。尽管感觉自己努力过,但是实际上,自身的能力从没得到过多少提升。 所以在无数个夜晚…...
基于 OpenCV 与 Java 两个语言版本实现获取某一图片特定区域的颜色对比度
本文目录一、什么是对比度二、什么是颜色直方图三、如何通过RGB计算颜色对比度什么是HSV、Lab颜色空间四、OpenCV代码五、Java代码5.1 平滑处理5.2 完整代码一、什么是对比度 对比度是指图像中不同区域之间的明暗差异程度,它是图像质量中的重要指标之一。除了颜色对…...
Book:实战Java高并发程序设计(第二版)
实战Java高并发程序设计(第二版)为什么会有并行计算?并行计算需要回答的问题基本概念并发级别有哪些?Amdahl定律和Gustafson定律Java并发三特性进程和线程线程的生命周期Thread类run()与start()的区别为什么会有并行计算ÿ…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
Python学习(8) ----- Python的类与对象
Python 中的类(Class)与对象(Object)是面向对象编程(OOP)的核心。我们可以通过“类是模板,对象是实例”来理解它们的关系。 🧱 一句话理解: 类就像“图纸”,对…...
门静脉高压——表现
一、门静脉高压表现 00:01 1. 门静脉构成 00:13 组成结构:由肠系膜上静脉和脾静脉汇合构成,是肝脏血液供应的主要来源。淤血后果:门静脉淤血会同时导致脾静脉和肠系膜上静脉淤血,引发后续系列症状。 2. 脾大和脾功能亢进 00:46 …...
云原生安全实战:API网关Envoy的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口,负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...
嵌入式面试常问问题
以下内容面向嵌入式/系统方向的初学者与面试备考者,全面梳理了以下几大板块,并在每个板块末尾列出常见的面试问答思路,帮助你既能夯实基础,又能应对面试挑战。 一、TCP/IP 协议 1.1 TCP/IP 五层模型概述 链路层(Link Layer) 包括网卡驱动、以太网、Wi‑Fi、PPP 等。负责…...
VSCode 使用CMake 构建 Qt 5 窗口程序
首先,目录结构如下图: 运行效果: cmake -B build cmake --build build 运行: windeployqt.exe F:\testQt5\build\Debug\app.exe main.cpp #include "mainwindow.h"#include <QAppli...
