最简单的基于 FFmpeg 的视频编码器(YUV 编码为 H.264)

最简单的基于 FFmpeg 的视频编码器(YUV 编码为 H.264)

  • 最简单的基于 FFmpeg 的视频编码器(YUV 编码为 H.264)
    • 正文
    • 结果
    • 工程文件下载

最简单的基于 FFmpeg 的视频编码器(YUV 编码为 H.264)

参考雷霄骅博士的文章,链接:最简单的基于FFMPEG的视频编码器(YUV编码为H.264)

正文

本文介绍一个最简单的基于 FFmpeg 的视频编码器。

该编码器实现了 YUV420P 的像素数据编码为 H.264 的压缩编码数据。

下面附一张使用 FFmpeg 编码视频的流程图。使用该流程,不仅可以编码 H.264 的视频,而且可以编码 MPEG4/MPEG2/VP8 等等各种 FFmpeg 支持的视频。图中蓝色背景的函数是实际输出数据的函数。浅绿色的函数是视频编码的函数。

在这里插入图片描述

简单介绍一下流程中各个函数的意义:

  1. av_register_all():注册 FFmpeg 所有编解码器。
  2. avformat_alloc_output_context2():初始化输出码流的 AVFormatContext。
  3. avio_open():打开输出文件。
  4. av_new_stream():创建输出码流的 AVStream。
  5. avcodec_find_encoder():查找编码器。
  6. avcodec_open2():打开编码器。
  7. avformat_write_header():写文件头(对于某些没有文件头的封装格式,不需要此函数。比如说 MPEG2TS)。
  8. avcodec_encode_video2():编码一帧视频。即将 AVFrame(存储 YUV 像素数据)编码为 AVPacket(存储 H.264 等格式的码流数据)。
  9. av_write_frame():将编码后的视频码流写入文件。
  10. flush_encoder():输入的像素数据读取完成后调用此函数。用于输出编码器中剩余的 AVPacket。
  11. av_write_trailer():写文件尾(对于某些没有文件头的封装格式,不需要此函数。比如说 MPEG2TS)。

源代码:

// Simplest FFmpeg Video Encoder H.264.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"#include <stdio.h>
#include <stdlib.h>// 解决报错:fopen() 函数不安全
#pragma warning(disable:4996)// 解决报错:无法解析的外部符号 __imp__fprintf,该符号在函数 _ShowError 中被引用
#pragma comment(lib, "legacy_stdio_definitions.lib")
extern "C"
{// 解决报错:无法解析的外部符号 __imp____iob_func,该符号在函数 _ShowError 中被引用FILE __iob_func[3] = { *stdin, *stdout, *stderr };
}#define __STDC_CONSTANT_MACROS#ifdef _WIN32
// Windows
extern "C"
{
#include "libavutil/opt.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
};
#else
// Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#ifdef __cplusplus
};
#endif
#endifint flush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index)
{int ret;int got_frame;AVPacket enc_pkt;if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities & CODEC_CAP_DELAY)){return 0;}while (1){enc_pkt.data = NULL;enc_pkt.size = 0;av_init_packet(&enc_pkt);ret = avcodec_encode_video2(fmt_ctx->streams[stream_index]->codec, &enc_pkt,NULL, &got_frame);av_frame_free(NULL);if (ret < 0)break;if (!got_frame){ret = 0;break;}printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d.\n", enc_pkt.size);// mux encoded frameret = av_write_frame(fmt_ctx, &enc_pkt);if (ret < 0){break;}}return ret;
}int main(int argc, char* argv[])
{AVFormatContext* pFormatCtx;AVOutputFormat* fmt;AVStream* video_stream;AVCodecContext* pCodecCtx;AVCodec* pCodec;AVPacket pkt;uint8_t* picture_buf;AVFrame* pFrame;int ret;int picture_size = 0;int y_size = 0;int framecnt = 0;// Input raw YUV data FILE *fp_in = fopen("ds_480x272.yuv", "rb");// FILE *in_file = fopen("src01_480x272.yuv", "rb");const int in_width = 480, in_height = 272; // Input data's width and heightint framenum = 100; // Frames to encode // Output Filepath const char* out_file = "ds.h264";// const char* out_file = "src01.h264";              // const char* out_file = "src01.ts";// const char* out_file = "src01.hevc";av_register_all();// Method1// pFormatCtx = avformat_alloc_context();// fmt = av_guess_format(NULL, out_file, NULL); // Guess Format// pFormatCtx->oformat = fmt;// Method 2avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);fmt = pFormatCtx->oformat;//Open output URLret = avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE);if (ret < 0){printf("Can't open output file.\n");return -1;}video_stream = avformat_new_stream(pFormatCtx, 0);// video_st->time_base.num = 1; // video_st->time_base.den = 25;  if (video_stream == NULL){printf("Can't create video stream.\n");return -1;}// Param that must setpCodecCtx = video_stream->codec;// pCodecCtx->codec_id = AV_CODEC_ID_HEVC;pCodecCtx->codec_id = fmt->video_codec;pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;pCodecCtx->width = in_width;pCodecCtx->height = in_height;pCodecCtx->bit_rate = 400000;pCodecCtx->gop_size = 250;pCodecCtx->time_base.num = 1;pCodecCtx->time_base.den = 25;// H.264// pCodecCtx->me_range = 16;// pCodecCtx->max_qdiff = 4;// pCodecCtx->qcompress = 0.6;pCodecCtx->qmin = 10;pCodecCtx->qmax = 51;// Optional ParampCodecCtx->max_b_frames = 3;// Set OptionAVDictionary *param = 0;// H.264if (pCodecCtx->codec_id == AV_CODEC_ID_H264){av_dict_set(&param, "preset", "slow", 0);av_dict_set(&param, "tune", "zerolatency", 0);// av_dict_set(&param, "profile", "main", 0);}// H.265if (pCodecCtx->codec_id == AV_CODEC_ID_H265){av_dict_set(&param, "preset", "ultrafast", 0);av_dict_set(&param, "tune", "zero-latency", 0);}// Show some Informationav_dump_format(pFormatCtx, 0, out_file, 1);pCodec = avcodec_find_encoder(pCodecCtx->codec_id);if (!pCodec){printf("Can't find encoder.\n");return -1;}ret = avcodec_open2(pCodecCtx, pCodec, &param);if (ret < 0){printf("Failed to open encoder.\n");return -1;}pFrame = av_frame_alloc();picture_size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);picture_buf = (uint8_t *)av_malloc(picture_size);avpicture_fill((AVPicture *)pFrame, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);// Write File Headeravformat_write_header(pFormatCtx, NULL);av_new_packet(&pkt, picture_size);y_size = pCodecCtx->width * pCodecCtx->height;for (int i = 0; i < framenum; i++){// Read raw YUV dataif (fread(picture_buf, 1, y_size * 3 / 2, fp_in) <= 0){printf("Failed to read raw data.\n");return -1;}else if (feof(fp_in)){break;}pFrame->data[0] = picture_buf; // YpFrame->data[1] = picture_buf + y_size; // U pFrame->data[2] = picture_buf + y_size * 5 / 4; // V// PTS// pFrame->pts = i;pFrame->pts = i*(video_stream->time_base.den) / ((video_stream->time_base.num) * 25);int got_picture = 0;// Encoderet = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture);if (ret < 0){printf("Failed to encode! \n");return -1;}if (got_picture == 1){printf("Succeed to encode frame: %5d\tsize:%5d\n", framecnt, pkt.size);framecnt++;pkt.stream_index = video_stream->index;ret = av_write_frame(pFormatCtx, &pkt);av_free_packet(&pkt);}}// Flush Encoderret = flush_encoder(pFormatCtx, 0);if (ret < 0){printf("Flushing encoder failed.\n");return -1;}// Write file trailerav_write_trailer(pFormatCtx);// Cleanif (video_stream){avcodec_close(video_stream->codec);av_free(pFrame);av_free(picture_buf);}avio_close(pFormatCtx->pb);avformat_free_context(pFormatCtx);fclose(fp_in);system("pause");return 0;
}

结果

运行程序,将输入 YUV 文件编码为 H.264 文件,以下是其信息:

在这里插入图片描述

可以正常播放。

在这里插入图片描述

工程文件下载

GitHub:UestcXiye / Simplest-FFmpeg-Video-Encoder-H.264

CSDN:Simplest FFmpeg Video Encoder H.264.zip

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/679009.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第78讲 修改密码

系统管理实现 修改密码实现 前端 modifyPassword.vue&#xff1a; <template><el-card><el-formref"formRef":model"form":rules"rules"label-width"150px"><el-form-item label"用户名&#xff1a;&quo…

《CSS 简易速速上手小册》第2章:CSS 布局与定位(2024 最新版)

文章目录 2.1 Flexbox&#xff1a;灵活的布局解决方案2.1.1 基础知识2.1.2 重点案例&#xff1a;创建一个响应式导航菜单2.1.3 拓展案例 1&#xff1a;卡片布局2.1.4 拓展案例 2&#xff1a;中心对齐的登录表单 2.2 Grid 布局&#xff1a;网格系统的魔力2.2.1 基础知识2.2.2 重…

C语言求解猴子分桃子

问题&#xff1a;海滩上有一堆桃子&#xff0c;五只猴子来分。第一只猴子把这堆桃子平均分为五份&#xff0c;多了一个&#xff0c;这只 猴子把多的一个扔入海中&#xff0c;拿走了一份。第二只猴子把剩下的桃子又平均分成五份&#xff0c;又多了 一个&#xff0c;它同样把多的…

english_syntax

文章目录 什么是英语的句子&#xff1f;英语句子的结构句子的成分&#xff08;词性问题&#xff09;谓语系动词主语宾语表语 并列句从句引导词名词性从句形容词性从句&#xff08;定语从句&#xff09;副词性从句&#xff08;状语从句&#xff09; 特殊结构强调句型倒装句型虚拟…

VitePress-13- 配置-title的作用详解

作用描述 1、title 是当前站点的标题&#xff1b;2、默认值是 &#xff1a;VitePress&#xff1b;3、当使用默认主题时&#xff0c;会直接展示在 页面的【导航条】中&#xff1b;4、一个特殊的作用 &#xff1a; 会作为单个页面的默认标题后缀&#xff01;除非又指定了【title…

WSL下如何使用Ubuntu本地部署Vits2.3-Extra-v2:中文特化修复版(新手从0开始部署教程)

环境&#xff1a; 硬&#xff1a; 台式电脑 1.cpu:I5 11代以上 2.内存16G以上 3.硬盘固态500G以上 4.显卡N卡8G显存以上 20系2070以上 本案例英伟达4070 12G 5.网络可连github 软&#xff1a; Win10 专业版 19045以上 WSL2 -Ubuntu22.04 1.bert-Vits2.3 Extra-v2:…

CSP-201912-1-报数

CSP-201912-1-报数 知识点总结 整数转化为字符串#include <string> string str_num to_string(num);字符串中查找是否包含字符‘7’&#xff1a;str_num.find(7) 未找到返回-1找到返回返回该字符在字符串中的位置&#xff08;即第一次出现的索引位置&#xff09; #i…

腾讯云4核8G服务器够用吗?容纳多少人同时访问?

腾讯云4核8G服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…

java nio零拷贝

零拷贝是一种计算机执行IO操作的优化技术&#xff0c;其核心目标是减少数据拷贝次数&#xff0c;从而提高系统性能。它主要体现在以下几个方面&#xff1a; 1. **定义与原理**&#xff1a;零拷贝字面上的意思包括“零”和“拷贝”。其中&#xff0c;“拷贝”是指数据从一个存储…

读千脑智能笔记11_保存人类遗产

1. 智能生物通常能延续多久 1.1. SETI和METI计划的可行性在很大程度上取决于智能生物通常能延续多久 1.1.1. 搜寻地外文明&#xff08;以下简称SETI&#xff09;计划的目标 1.1.1.1. 这是一个力图寻找宇宙其他地方智能生物存在证据的研究项目 1.1.1.2. SETI计划旨在寻找含有…

[NSSCTF]-Web:[SWPUCTF 2021 新生赛]easy_sql解析

查看网页 有提示&#xff0c;参数是wllm&#xff0c;并且要我们输入点东西 所以&#xff0c;我们尝试以get方式传入 有回显&#xff0c;但似乎没啥用 从上图看应该是字符型漏洞&#xff0c;单引号字符注入 先查看字段数 /?wllm2order by 3-- 没回显 报错了&#xff0c;说明…

顺序表、链表(ArrayList、LinkedList)

目录 前言&#xff1a; 顺序表&#xff08;ArrayList&#xff09;&#xff1a; 顺序表的原理&#xff1a; ArrayList源码&#xff1a; 的含义&#xff1a;​编辑 ArrayList的相关方法&#xff1a;​编辑 向上转型List&#xff1a; 练习题&#xff08;杨辉三角&#x…

轻薄型工业平板亿道EM-T195,续航持久高达10小时

时尚而坚固的 10.1英寸EM-T195触摸屏平板电脑融合了高耐力和无与伦比的适应性&#xff0c;可抵御极端天气条件和多重冲击&#xff0c;借助强大的联发科8核处理器&#xff0c;它可以从容面对任何工作挑战。 其读取能力&#xff08;2D 成像器&#xff09;结合其坚固性&#xff0…

探索现代Web前端开发框架:选择最适合你的工具

在当今快速发展的Web开发领域&#xff0c;前端开发框架的选择显得尤为关键。这些框架可以帮助我们更高效地构建出交互性强、性能卓越的用户界面。本文将带你了解几个当前最受欢迎的Web前端开发框架&#xff0c;并帮助你根据自己的需求选择最合适的工具。 1. React React由Fac…

2.10日学习打卡----初学RocketMQ(一)

2.10日学习打卡 对于MQ(Message queue)消息队列的一些解释可以看我原来写的文章 初学RabbitMQ 各大MQ产品比较 一.RocketMQ概述 发展历程 RocketMQ概念术语 生产者和消费者 生产者负责生产消息&#xff0c;一般由业务系统负责生产消息&#xff0c;消费者即后台系统&…

无人机遥感技术应用分析,无人机遥感系统测绘技术详解

由于无人机具有机动快速、使用成本低、维护操作简单等技术特点,因此被作为一种理想的飞行平台广泛应用于军事和民用各个领域。尤其是进入二十一世纪以后,许多国家将无人机系统的研究、开发、应用置于优先发展的地位,体积小、重量轻、探测精度高的新型传感器的不断问世,也使无人…

解决挂梯子 无法正常上网 的问题

方法&#xff1a; 打开 控制面板 &#x1f449; 网络和Internet &#x1f449; Internet选项 &#x1f449; 连接 &#x1f449; 局域网设置 &#x1f449; 代理服务器 &#x1f449; 取消选项 有问题可参考下图

中科大计网学习记录笔记(九):DNS

前言&#xff1a; 学习视频&#xff1a;中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版&#xff0c;James F.Kurose&#xff0c;Keith W.Ross&#xff09;》课程 该视频是B站非常著名的计网学习视频&#xff0c;但相信很多朋友和我一样在听完前面的部分发现信…

【MySQL】-18 MySQL综合-4(MySQL储存引擎精讲+MySQL数据类型简介+MySQL整数类型+MySQL小数类型)

MySQL储存引擎精讲MySQL数据类型简介MySQL整数类型MySQL小数类型 十一 MySQL存储引擎精讲11.1 什么是存储引擎11.2 MySQL 5.7 支持的存储引擎11.3 如何选择 MySQL 存储引擎11.4 MySQL 默认存储引擎 十二 MySQL数据类型简介12.1 MySQL 常见数据类型1) 整数类型2) 日期/时间类型3…

Python中的正则表达式(一)

在Python中&#xff0c;正则表达式是一种用于匹配和操作字符串的强大工具。正则表达式由一系列字符和特殊字符组成&#xff0c;用于定义搜索模式。 在Python中&#xff0c;我们使用内置的 re 模块来操作正则表达式。要使用正则表达式&#xff0c;我们首先需要导入 re 模块。 下…