ffmpeg解码

avcodec_send_packet

avcodec_receive_frame

H264 帧分割 

ffmpeg -i v1080.mp4 -s 400x300 test.h264

我们使用这个命令生成一个编码后的 h264 文件。

基于 ffmpeg 接口完成视频解码

 117_test_decode.cpp

#include <iostream>
#include <fstream>

using namespace std;

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

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

int main()
{
	//1 分割h264 存入AVPacket
	// ffmpeg -i v1080.mp4 -s 400x300 test.h264
	string file_name = "test.h264";
	ifstream ifs;
	AVCodec* codec = nullptr;
	AVCodecID codec_id = AV_CODEC_ID_H264;
	AVCodecContext* context = nullptr;
	AVCodecParserContext* parser = nullptr;
	AVPacket* packet = nullptr;
	AVFrame* frame = nullptr;
	unsigned char inbuf[4096] = { 0 };
	int inbuf_len = 0;
	int ret = 0;

	ifs.open(file_name, ios::in | ios::binary);

	if (!ifs)
	{
		return -1;
	}

	//1 找解码器
	codec = avcodec_find_decoder(codec_id);

	if (codec == nullptr)
	{
		cerr << "avcodec_find_decoder failed!" << endl;

		return -1;
	}

	//2 创建上下文
	context = avcodec_alloc_context3(codec);

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

		return -1;
	}

	//3 打开上下文
	ret = avcodec_open2(context, nullptr, nullptr);

	if (ret < 0)
	{
		cerr << "avcodec_open2 failed!" << endl;

		return -1;
	}

	// 分割上下文
	parser = av_parser_init(codec_id);

	if (parser == nullptr)
	{
		cerr << "av_parser_init failed!" << endl;

		return -1;
	}

	packet = av_packet_alloc();

	if (packet == nullptr)
	{
		cerr << "av_packet_alloc failed!" << endl;

		return -1;
	}

	frame = av_frame_alloc();

	if (frame == nullptr)
	{
		cerr << "av_frame_alloc failed!" << endl;

		return -1;
	}

	while (!ifs.eof())
	{
		int len = 0;
		unsigned char* data = inbuf;

		ifs.read((char*)inbuf, sizeof(inbuf));
		len = ifs.gcount();  // 读取的字节数

		while (len > 0)
		{
			// 通过 0001 截断输出到AVPacket 如果满足一个 AVPackret 则返回这个 AVPacket 的大小 不足一个AVPactet 则返回余下的数据大小 不足一个AVPactet的数据会被缓存起来
			int in_len = av_parser_parse2(parser, context,
				&packet->data, &packet->size,  // 输出
				data, len,					   // 输入
				AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0
			);

			data += in_len;
			len -= in_len;

			if (packet->size > 0)
			{
				// cout << packet->size << " " << flush;

				//发送packet到解码线程
				ret = avcodec_send_packet(context, packet);

				if (ret != 0)
				{
					cerr << "avcodec_send_packet failed!" << endl;
					break;
				}

				/* 获取多帧解码数据 */ 
				ret = avcodec_receive_frame(context, frame);

				while (ret == 0)
				{
					//每次会调用av_frame_unref 
					cout << frame->format << " " << flush;
					ret = avcodec_receive_frame(context, frame);
				}
			}
		}
	}

	/* 取出缓存数据 */
	avcodec_send_packet(context, nullptr);

	ret = avcodec_receive_frame(context, frame);

	while (ret == 0)
	{
		cout << frame->format << "-" << flush;
		ret = avcodec_receive_frame(context, frame);
	}

	av_frame_free(&frame);
	av_packet_free(&packet);
	av_parser_close(parser);
	avcodec_free_context(&context);

	ifs.close();

	return 0;
}

我们打开h264文件读取数据到缓冲区中,对这片缓冲区中的数据进行解析,解析出 AVPacket,然后对 AVPacket 进行解码,解码出 AVFrame。

执行结果如下图所示:

我们打印了解码后原始帧的像素格式,0表示使用 YUV420P 像素格式。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值