H264编码介绍和参数设置

本文详细介绍了H264视频编码流程,包括宏块划分、帧内预测、帧间预测、DCT、量化、熵编码等步骤,以及预设编码器设置、比特率控制和关键帧类型的分析。通过C++代码示例,探讨了如何创建和编码H264视频流。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

视频h264编码流程

宏块划分 Macro Block

帧内预测 I帧

帧间预测和GOP P帧和B帧 

DCT离散余弦变换 

量化 

熵编码 

preset 预设编码器 

预设编码器 

比特率控制 

恒定比特率(CBR) 

恒定速率因子(CRF) 

H264码流中NALU sps pps IDR帧的分析 

NALU的类型

SPS 

 

PPS

代码 

114_preset_encoder.cpp

#include <iostream>
#include <fstream>

using namespace std;

extern "C"  // 指定函数是 C 语言函数,函数目标名不包含重载标识,C++ 中调用 C 函数需要使用 extern "C"
{
	// 引用 ffmpeg 头文件
	#include "libavcodec/avcodec.h"
	#include "libavutil/opt.h"
}

// 预处理指令导入库
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avutil.lib")

int main(int argc, char* argv[])
{
	// 1 找到编码器  AV_CODEC_ID_HEVC(H265)
	AVCodec* codec = nullptr;
	AVFrame* frame = nullptr;
	AVPacket* packet = nullptr;
	AVCodecID codec_id = AV_CODEC_ID_H264;
	ofstream ofs;
	string file_name = "400_300_25_preset";
	int r = 0;

	if (argc > 1)
	{
		string suffix = argv[1];

		cout << "suffix = " << suffix << endl;

		if ((suffix == "h265") || (suffix == "hevc"))
		{
			codec_id = AV_CODEC_ID_HEVC;
		}
	}

	if (codec_id == AV_CODEC_ID_H264)
	{
		file_name += ".h264";
	}
	else if (codec_id == AV_CODEC_ID_HEVC)
	{
		file_name += ".h265";
	}

	ofs.open(file_name, ios::out | ios::binary);

	if (!ofs)
	{
		cout << "open " << file_name << " failed!" << endl;

		return -1;
	}

	codec = avcodec_find_encoder(codec_id);

	if (codec == nullptr)
	{
		cout << "avcodec_find_encoder failed!" << endl;

		return -1;
	}

	// 2 编码上下文
	AVCodecContext* context = avcodec_alloc_context3(codec);

	if (context == nullptr)
	{
		cout << "avcodec_alloc_context3 failed!" << endl;

		return -1;
	}

	// 3 设定上下文参数
	context->width = 400;  //视频宽高
	context->height = 300;
	context->pix_fmt = AV_PIX_FMT_YUV420P;  // 源数据像素格式,与编码算法相关
	context->time_base = { 1, 25 };  // 帧时间戳的时间单位  pts*time_base = 播放时间(秒) 分数 1/25
	context->thread_count = 16;  // 编码线程数,可以通过调用系统接口获取cpu核心数量

	// context->max_b_frames = 0;  // B帧设为0 降低延时,增大空间
	//r = av_opt_set(context->priv_data, "preset", "ultrafast", 0);  // 最快速度

	if (r != 0)
	{
		char buf[1024] = { 0 };

		av_strerror(r, buf, sizeof(buf) - 1);
		cout << "av_opt_set preset failed! " << buf << endl;

		avcodec_free_context(&context);

		return -1;
	}

	//r = av_opt_set(context->priv_data, "tune", "zerolatency", 0);  // 零延时 h265不支持b_frame

	///
	/// ABR 平均比特率
	//int br = 500000;  //400kb
	//c->bit_rate = br;

	///
	//CQP 恒定质量 H.264中的QP范围从0到51  
	// x264默认 23   效果较好18
	//  x265默认28 效果较好25
	// av_opt_set_int(context->priv_data, "qp", 18, 0);

	/
	/// 恒定比特率(CBR) 由于MP4不支持NAL填充,因此输出文件必须为(MPEG-2 TS)
	/*context->rc_min_rate = br;
	context->rc_max_rate = br;
	context->rc_buffer_size = br;
	context->bit_rate = br;
	av_opt_set(context->priv_data, "nal-hrd", "cbr", 0);*/

	if (r != 0)
	{
		char buf[1024] = { 0 };

		av_strerror(r, buf, sizeof(buf) - 1);
		cout << "av_opt_set tune failed! " << buf << endl;

		avcodec_free_context(&context);

		return -1;
	}

	context->gop_size = 6;

	// 4 打开编码上下文
	r = avcodec_open2(context, codec, nullptr);

	if (r != 0)
	{
		char buf[1024] = { 0 };

		av_strerror(r, buf, sizeof(buf) - 1);
		cout << "avcodec_open2 failed! " << buf << endl;

		avcodec_free_context(&context);

		return -1;
	}

	// 创建好AVFrame空间 未压缩数据
	frame = av_frame_alloc();
	frame->width = context->width;
	frame->height = context->height;
	frame->format = context->pix_fmt;

	r = av_frame_get_buffer(frame, 0);

	if (r != 0)
	{
		char buf[1024] = { 0 };

		av_strerror(r, buf, sizeof(buf) - 1);
		cout << "av_frame_get_buffer failed! " << buf << endl;

		avcodec_free_context(&context);

		return -1;
	}

	packet = av_packet_alloc();

	/* 十秒视频 250帧 */
	for (int i = 0; i < 250; i++)
	{
		// 生成AVFrame 数据 每帧数据不同
		// Y
		for (int h = 0; h < frame->height; h++)
		{
			for (int w = 0; w < frame->width; w++)
			{
				frame->data[0][frame->linesize[0] * h + w] = h + w + i * 3;
			}
		}

		// UV
		for (int h = 0; h < frame->height / 2; h++)
		{
			for (int w = 0; w < frame->width / 2; w++)
			{
				frame->data[1][frame->linesize[1] * h + w] = 128 + h + i * 2;
				frame->data[2][frame->linesize[2] * h + w] = 64 + w + i * 5;
			}
		}

		frame->pts = i;  // 显示的时间
		r = avcodec_send_frame(context, frame);

		if (r != 0)
		{
			break;
		}

		while (r >= 0)  // 返回多帧
		{
			// 接收压缩帧,一般前几次调用返回空(缓冲,立刻返回,编码未完成)
			// 编码是在独立的线程中
			// 每次调用会重新分配packet中的空间
			r = avcodec_receive_packet(context, packet);

			if ((r == AVERROR(EAGAIN)) || (r == AVERROR_EOF))
			{
				break;
			}
			else if (r < 0)
			{
				char buf[1024] = { 0 };

				av_strerror(r, buf, sizeof(buf) - 1);
				cout << "avcodec_receive_packet failed! " << buf << endl;
				avcodec_free_context(&context);

				break;
			}

			// cout << packet->size << " " << flush;
			ofs.write((char*)packet->data, packet->size);

			/// 分析NALU
			/// 一个AVPacket中包含多个NALU 以0001间隔,多个是以001间隔
			/    0001[NAL_HEAD]
			  [NAL_HEAD] 
			//1个字节 orbidden_bit(1bit),nal_reference_bit(2bits)(优先级),
			/// nal_unit_type(5bits)
			///    1:非IDR图像中不采用数据划分的片段
			///    5:IDR图像的片段
			///    6:补充增强信息(SEI)
			///    7:序列参数集 / SPS
			///    8:图像参数集 / PPS

			int nal_unit_type = 0;
			char nal_head = *(packet->data + 4);  // +4 去掉开头的0001

			nal_unit_type = nal_head & 0x1f;
			cout << nal_unit_type << " " << flush;

			for (int i = 4; i < packet->size - 3; i++)  // 一个data中由多条nalu
			{
				if ((packet->data[i] == 0) && (packet->data[i + 1] == 0) && (packet->data[i + 2] == 1))
				{
					nal_unit_type = packet->data[i + 3] & 0x1f;
					cout << "(" << nal_unit_type << ")" << " " << flush;
				}
			}

			av_packet_unref(packet);
		}
	}

	ofs.close();
	av_packet_free(&packet);
	av_frame_free(&frame);
	avcodec_free_context(&context);  // 释放编码器上下文

	return 0;
}

我们来查看每个NALU中的类型。

运行结果如下所示:

 

H264编码器标准草案发布时,很多人都觉得H.264太复杂,不宜实用。眨眼间3年过去了,以往的论断、疑惑被如今的现实冲洗的干干净净。一张7.92G的1小时50分的av,分辨720*480,用Ahead dvd ripper,现在用最新的ffdshow h264编码(4线程,码率1500k),需要1小时10分左右。cpu吃不完,占用率在50%左右。 采用H.264编码,将视频文件压缩转换为MP4/3GP/F4V/AVI格式.绿色软件,使用方便,压缩速度快,图像质量好. 本软件使用Windows系统注册解码器进行视频解码.Windows Media Player能够播放的视频格式,本软件都可以进行压缩.对于不支持的视频格式,可以安装解码包,如ffdshow, 影音风暴等. H264编码器功能: 1、四路视频实时预览,也可利用Web界面对多路直播信号远程集中管理进行配置管理, 2、领先的码率控制技术(CBR/VBR),使其能轻松运作于280Kbps~ 6000Kbps之间。 3、可变的GOP结构:I,IP,IBP,IBBP。 4、PCM音频信道。 5、指纹式植入的视频流的音频处理技术,使得视音频实时同步。 6、支持输出文件格式:FLV,MPEG-4,MPEG-2及HTTP,RTSP,UDP网络协议。 7、支持VBR及CBR压缩方式。 8、支持多种分辨率:FULL,D1等; 9、可将录制FLV格式文件再转换为MP4格式文件进行存储; 10、支持自动录制手工录制; 11、能设定自动录制计划,时间设定为某月某周某日时分秒,自动进行录制; 12、每路直播信号,能设定不同时段的定时任务; 13、可设定录制文件保存路径; 14、支持网络存储,如NASNAS SAN等网络环境。 H264编码器截图:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值