前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >2023-04-09:使用 Golang 重写的 ffmpeg 示例encode_video.c,实现视频编码并将编码后的数据封装为容器格式,最终写入输出文件。

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

原创
作者头像
福大大架构师每日一题
发布于 2023-04-09 13:34:30
发布于 2023-04-09 13:34:30
4590
举报

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. 将编码后的数据包写入输出文件。

  1. 关闭编码器,并在需要时向输出文件写入结束标记。
  2. 释放资源。

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

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

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

代码见moonfdd/ffmpeg-go库。

命令如下:

代码语言:shell
AI代码解释
复制
go run ./examples/internalexamples/encode_video/main.go ./out/encode_video.mp4 mpeg2video

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

go代码如下:

代码语言:go
AI代码解释
复制
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()
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
福大大架构师每日一题
2023/06/08
4940
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264文件。
福大大架构师每日一题
2023/02/28
8010
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
福大大架构师每日一题
2023/04/06
3770
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
福大大架构师每日一题
2023/04/01
8000
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
福大大架构师每日一题
2023/06/08
2990
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
福大大架构师每日一题
2023/06/08
3060
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
福大大架构师每日一题
2023/04/05
1.6K0
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
2022-04-24:用go语言重写ffmpeg的muxing.c示例。
总体上,本程序实现了将虚假音频和视频数据编码成指定格式并写入输出文件的功能。其中,步骤 2 的主要作用是为音频和视频流创建必要的对象和参数,以便后续进行编码和写入;步骤 3 和 4 则是生成虚假数据并进行编码和写入的具体实现。
福大大架构师每日一题
2023/04/24
3740
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Inte
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Intel Quick Sync Video 等)对视频进行解码,从而提高解码效率和性能。在进行硬件加速解码时,相较于 CPU 的软件解码方式,GPU 可以利用其并行处理能力和更高的带宽进行更高效的解码操作。请用go语言改写hw_decode.c文件。
福大大架构师每日一题
2023/06/09
7800
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Inte
2023-03-15:屏幕录制并且显示视频,不要用命令。代码用go语言编写。
使用moonfdd/ffmpeg-go和moonfdd/sdl2-go库来实现屏幕录制并显示视频,大体流程如下:
福大大架构师每日一题
2023/03/15
1.2K0
2023-03-15:屏幕录制并且显示视频,不要用命令。代码用go语言编写。
2023-05-04:用go语言重写ffmpeg的scaling_video.c示例,用于实现视频缩放(Scaling)功能。
2023-05-04:用go语言重写ffmpeg的scaling_video.c示例,用于实现视频缩放(Scaling)功能。
福大大架构师每日一题
2023/05/04
2850
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Intel Quick Sync Vid
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Intel Quick Sync Video 等)对视频进行解码,从而提高解码效率和性能。在进行硬件加速解码时,相较于 CPU 的软件解码方式,GPU 可以利用其并行处理能力和更高的带宽进行更高效的解码操作。请用go语言改写hw_decode.c文件。
福大大架构师每日一题
2023/04/18
9660
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Intel Quick Sync Vid
2023-02-25:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420SP格式文件,YUV420P不要转换成YUV420SP。
2023-02-25:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420SP格式文件,YUV420P不要转换成YUV420SP。
福大大架构师每日一题
2023/02/25
3350
2023-03-19:使用Go语言和FFmpeg库实现pcm编码为mp3。
本文将介绍如何使用Go语言和FFmpeg库实现PCM音频文件编码为MP3格式。我们将使用moonfdd/ffmpeg-go库,并在Windows 10 64位操作系统下完成本次实验。
福大大架构师每日一题
2023/03/19
6750
2023-03-19:使用Go语言和FFmpeg库实现pcm编码为mp3。
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
福大大架构师每日一题
2023/06/08
7080
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
福大大架构师每日一题
2023/04/12
5130
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
2023-03-23:音视频解混合(demuxer)为PCM和YUV420P,用go语言编写。
2023-03-23:音视频解混合(demuxer)为PCM和YUV420P,用go语言编写。
福大大架构师每日一题
2023/03/23
3760
2023-03-23:音视频解混合(demuxer)为PCM和YUV420P,用go语言编写。
2023-03-23:音视频解混合(demuxer)为PCM和YUV420P,用go语言编写。
2023-03-23:音视频解混合(demuxer)为PCM和YUV420P,用go语言编写。
福大大架构师每日一题
2023/06/08
2700
2023-03-23:音视频解混合(demuxer)为PCM和YUV420P,用go语言编写。
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
福大大架构师每日一题
2023/03/30
4500
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
福大大架构师每日一题
2023/03/17
2K0
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
推荐阅读
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与
4940
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264
8010
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
3770
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
8000
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
2990
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
3060
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
1.6K0
2022-04-24:用go语言重写ffmpeg的muxing.c示例。
3740
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Inte
7800
2023-03-15:屏幕录制并且显示视频,不要用命令。代码用go语言编写。
1.2K0
2023-05-04:用go语言重写ffmpeg的scaling_video.c示例,用于实现视频缩放(Scaling)功能。
2850
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Intel Quick Sync Vid
9660
2023-02-25:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420SP格式文件,YUV420P不要转换成YUV420SP。
3350
2023-03-19:使用Go语言和FFmpeg库实现pcm编码为mp3。
6750
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频
7080
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
5130
2023-03-23:音视频解混合(demuxer)为PCM和YUV420P,用go语言编写。
3760
2023-03-23:音视频解混合(demuxer)为PCM和YUV420P,用go语言编写。
2700
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
4500
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
2K0
相关推荐
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档