2023-04-09:使用 Golang 重写的 ffmpeg 示例encode_video.c,实现视频编码并将编码后的数据封装为容器格式,最终写入输出文件。

答案2023-04-09:

本文介绍的是使用 Golang 重写的 ffmpeg 示例代码 encode_video.c,该示例代码实现了将视频编码并封装为容器格式,并最终写入输出文件的功能。

这个示例程序的主要流程如下:

  1. 解析命令行参数,获取输出文件名和所用的编码器名称。

  2. 根据编码器名称查找对应的编码器。

  3. 分配和初始化一个编码器上下文结构体(AVCodecContext)。

  4. 设置编码器参数:比特率、分辨率、帧率等。

  5. 打开编码器。

  6. 创建一个 AVFrame 结构体并为其分配空间,用于存储待编码的视频帧数据。

  7. 创建一个 AVPacket 结构体,用于存储编码后的数据。

  8. 循环编码每一帧视频数据:

    a. 将待编码的视频数据填充到 AVFrame 结构体中。

    b. 发送视频帧到编码器,得到编码后的数据包。

    c. 将编码后的数据包写入输出文件。

  9. 关闭编码器,并在需要时向输出文件写入结束标记。

  10. 释放资源。

在该示例代码中,默认使用 H.264 编码器和 YUV420P 像素格式。在设置编码器参数时,需要指定视频的比特率、分辨率和帧率等参数。通过创建 AVFrame 结构体并为其分配空间,可以将待编码的视频数据填入其中,并发送给编码器进行编码。编码后的数据通过 AVPacket 结构体进行封装,最终写入输出文件。

需要注意的是,在实际应用中,还需要根据具体需求进行相应的配置和优化,例如设置 GOP 大小、调整编码速度等参数,以提高视频质量和编码效率。同时,还需要考虑容器格式的选择,以满足不同场景下的需求。

总之,这个示例代码提供了一个简单的视频编码和封装的实现,为使用 ffmpeg 进行视频处理和转码提供了参考和思路。

代码见moonfdd/ffmpeg-go库。

命令如下:

go run ./examples/internalexamples/encode_video/main.go ./out/encode_video.mp4 mpeg2video

./lib/ffplay  ./out/encode_video.mp4

go代码如下:

package main

import (
"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, codec_name string
var codec *libavcodec.AVCodec
var c *libavcodec.AVCodecContext
var i, x, y ffcommon.FInt
var f *os.File
var frame *libavutil.AVFrame
var pkt *libavcodec.AVPacket
endcode := [...]ffcommon.FUint8T{0, 0, 1, 0xb7} if len(os.Args) <= 2 {
fmt.Printf("Usage: %s <output file> <codec name>\n", os.Args[0])
return 0
}
filename = os.Args[1]
codec_name = os.Args[2] /* find the mpeg1video encoder */
codec = libavcodec.AvcodecFindEncoderByName(codec_name)
if codec == nil {
fmt.Printf("Codec '%s' not found\n", codec_name)
os.Exit(1)
} c = codec.AvcodecAllocContext3()
if c == nil {
fmt.Printf("Could not allocate video codec context\n")
os.Exit(1)
} pkt = libavcodec.AvPacketAlloc()
if pkt == nil {
os.Exit(1)
} /* put sample parameters */
c.BitRate = 400000
/* resolution must be a multiple of two */
c.Width = 352
c.Height = 288
/* frames per second */
c.TimeBase = libavutil.AVRational{1, 25}
c.Framerate = libavutil.AVRational{25, 1} /* emit one intra frame every ten frames
* check frame pict_type before passing frame
* to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
* then gop_size is ignored and the output of encoder
* will always be I frame irrespective to gop_size
*/
c.GopSize = 10
c.MaxBFrames = 1
c.PixFmt = libavutil.AV_PIX_FMT_YUV420P if codec.Id == libavcodec.AV_CODEC_ID_H264 {
libavutil.AvOptSet(c.PrivData, "preset", "slow", 0)
} /* open it */
if c.AvcodecOpen2(codec, nil) < 0 {
fmt.Printf("Could not open codec\n")
os.Exit(1)
} f, _ = os.Create(filename)
if f == nil {
fmt.Printf("Could not open %s\n", filename)
os.Exit(1)
} frame = libavutil.AvFrameAlloc()
if frame == nil {
fmt.Printf("Could not allocate video frame\n")
os.Exit(1)
}
frame.Format = c.PixFmt
frame.Width = c.Width
frame.Height = c.Height ret = frame.AvFrameGetBuffer(0)
if ret < 0 {
fmt.Printf("Could not allocate the video frame data\n")
os.Exit(1)
}
/* encode 1 second of video */
for i = 0; i < 25; i++ {
// fflush(stdout); /* make sure the frame data is writable */
ret = frame.AvFrameMakeWritable()
if ret < 0 {
os.Exit(1)
} /* prepare a dummy image */
/* Y */
for y = 0; y < c.Height; y++ {
for x = 0; x < c.Width; x++ {
*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(frame.Data[0])) + uintptr(y*frame.Linesize[0]+x))) = byte((x + y + i*3) % 256)
}
} /* Cb and Cr */
for y = 0; y < c.Height/2; y++ {
for x = 0; x < c.Width/2; x++ {
*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(frame.Data[1])) + uintptr(y*frame.Linesize[1]+x))) = byte((128 + y + i*2) % 256)
*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(frame.Data[2])) + uintptr(y*frame.Linesize[2]+x))) = byte((64 + x + i*5) % 256)
}
} frame.Pts = int64(i) /* encode the image */
encode(c, frame, pkt, f)
} /* flush the encoder */
encode(c, nil, pkt, f) /* add sequence end code to have a real MPEG file */
if codec.Id == libavcodec.AV_CODEC_ID_MPEG1VIDEO || codec.Id == libavcodec.AV_CODEC_ID_MPEG2VIDEO {
f.Write(endcode[:])
}
f.Close() libavutil.AvFrameFree(&frame)
libavcodec.AvPacketFree(&pkt)
libavcodec.AvcodecFreeContext(&c) return 0
} func encode(enc_ctx *libavcodec.AVCodecContext, frame *libavutil.AVFrame, pkt *libavcodec.AVPacket, output *os.File) {
var ret ffcommon.FInt /* send the frame to the encoder */
if frame != nil {
fmt.Printf("Send frame %3d\n", frame.Pts)
} ret = enc_ctx.AvcodecSendFrame(frame)
if ret < 0 {
fmt.Printf("rror sending a frame for encoding\n")
os.Exit(1)
} for ret >= 0 {
ret = enc_ctx.AvcodecReceivePacket(pkt)
if ret == -libavutil.EAGAIN || ret == libavutil.AVERROR_EOF {
return
} else if ret < 0 {
fmt.Printf("Error during encoding\n")
os.Exit(1)
}
fmt.Printf("Write packet %3d (size=%5d)\n", pkt.Pts, pkt.Size)
output.Write(ffcommon.ByteSliceFromByteP(pkt.Data, int(pkt.Size)))
pkt.AvPacketUnref()
}
} 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-09:使用 Golang 重写的 ffmpeg 示例encode_video.c,实现视频编码并将编码后的数据封装为容器格式,最终写入输出文件。的更多相关文章

  1. FFmpeg简单转码程序--视频剪辑

    学习了雷神的文章,慕斯人分享精神,感其英年而逝,不胜唏嘘.他有分享一个转码程序<最简单的基于FFMPEG的转码程序>其中使用了filter(参考了ffmpeg.c中的流程),他曾说想再编写 ...

  2. 04 . Nginx的Rewrite重写

    Rewrite简介 # Rewrite对应URL Rewrite,即URL重写,就是把传入web的请求重定向到其他URL的过程. # 当运维遇到要重写情况时,往往是要程序员把重写规则写好后,发给你,你 ...

  3. 用Python和FFmpeg查找大码率的视频文件

    用Python和FFmpeg查找大码率的视频文件 本文使用Python2.7, 这个工作分两步 遍历目录下的视频文件 用ffprobe获取是视频文件的码率信息 用ffprobe 获取json格式的视频 ...

  4. 引用AForge.video.ffmpeg,打开时会报错:找不到指定的模块,需要把发行包第三方文件externals\ffmpeg\bin里的dll文件拷到windows的system32文件夹下。

    引用AForge.video.ffmpeg,打开时会报错:找不到指定的模块,需要把发行包第三方文件externals\ffmpeg\bin里的dll文件拷到windows的system32文件夹下. ...

  5. FFmpeg示例程序合集-批量编译脚本

    此前做了一系列有关FFmpeg的示例程序,组成了<最简单的FFmpeg示例程序合集>,其中包含了如下项目:simplest ffmpeg player:                   ...

  6. FFmpeg示例程序合集-Git批量获取脚本

    此前做了一系列有关FFmpeg的示例程序,组成了<FFmpeg示例程序合集>,其中包含了如下项目:simplest ffmpeg player:                  最简单的 ...

  7. FFmpeg开发实战(六):使用 FFmpeg 将YUV数据编码为视频文件

    本文中实现的一个小功能是把一个YUV原始视频数据(时间序列图像)经过h264编码为视频码流,然后在使用mp4封装格式封装. 编码&封装的流程图如下: 使用ffmpeg编码流程: 1.首先使用a ...

  8. FFmpeg实现将图片转换为视频

    ##名称:ffmpeg实现将图片转换为视频 ##平台:ubuntu(已经安装好了ffmpeg工具) ##日期:2017年12月10日 简介: 因为学习需要,需要将连续图片转换成视频,昨天和今天早上用o ...

  9. FFmpeg 入门(1):截取视频帧

    本文转自:FFmpeg 入门(1):截取视频帧 | www.samirchen.com 背景 在 Mac OS 上如果要运行教程中的相关代码需要先安装 FFmpeg,建议使用 brew 来安装: // ...

  10. indows下PHP通过ffmpeg给上传的视频截图详解

    windows下PHP通过ffmpeg给上传的视频截图详解,php_ffmpeg.dll安装下载,找了很久php_ffmpeg.dll的下载地址和应用,发现有用的资源很少,现在问题解决了,贴出来跟大家 ...

随机推荐

  1. Linux系统mysql免安装版配置指南

    1.下载(/usr/local目录) wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.32-linux-glibc2.12-x ...

  2. switch case return return 返回不了值的原因

    我在页面写了一个ajax ,但是控制器 是 用switch case break 控制的控制器  , 我想 在case login 方法里  直接 return  , 但是不好使 始终是 null , ...

  3. SublimeText实现Markdown快速预览

    SublimeText是什么? SublimeText是一个文本编辑器,同时也是一个先进的代码编辑器.SublimeText具有漂亮的用户界面和强大的功能,它的主要功能包括:拼写检查,书签,完整的Py ...

  4. 详解低延时高音质:丢包、抖动与 last mile 优化那些事儿

    本篇是「详解低延时高音质系列」的第三篇技术分享.我们这次要将视角放大,从整个音频引擎链路的角度,来讲讲在时变的网络下,针对不同的应用场景,如何权衡音质和互动的实时性. 当我们在讨论实时互动场景下的低延 ...

  5. 2023最新ELK日志平台(elasticsearch+logstash+kibana)搭建

    前言 去年公司由于不断发展,内部自研系统越来越多,所以后来搭建了一个日志收集平台,并将日志收集功能以二方包形式引入自研系统,避免每个自研系统都要建立一套自己的日志模块,节约了开发时间,管理起来也更加容 ...

  6. MyBatisPlus--入门

    入门案例 MyBatisPlus(MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发.提高效率. 1.新建springboot项目(版本2.5.0),仅保留JDBC 添加mybatis ...

  7. GPSSworld仿真(一):程序题——单窗口排队系统

    3.3 一个仓库共存放了2000吨货物,货物以三种规模出库,少量(10吨),中等(20吨),大量(50吨),分别以10±5分,15分,30±10分的速率出库.如果没有货位达到的情况下,一个仓库能维持供 ...

  8. 寻找区间内第k小的数

    sort排序 这是最直接暴力的方法,时间复杂度为\(O(nlog_n)\) 直接排序,输出第k小的值即可 #include <iostream> #include <algorith ...

  9. 【Deep Learning】DDPM

    DDPM 1. 大致流程 1.1 宏观流程 1.2 训练过程 1.3 推理过程 2. 对比GAN 2.1 GAN流程 2.2 相比GAN优点 训练过程更稳定,损失函数指向性更强(loss数值大小指示训 ...

  10. 开发轻量级REST API样板 基于Node.js、MongoDB 通过Mongoose驱动

    ZY.Node.Mongodb https://gitee.com/Z568_568/node.mongodb.git https://github.com/ZHYI-source/ZY.Node.M ...