源文件:
#include <iostream>
#include <fstream>
#include <string>
#include"xsdl.h"
using namespace std;
extern "C" { //指定函数是c语言函数,函数名不包含重载标注
//引用ffmpeg头文件
#include <libavcodec/avcodec.h>
}
//预处理指令导入库
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
int main(int argc, char* argv[])
{
auto view = XVideoView::Create();
//1 分割h264 存入AVPacket
string filename = "test.h264";
ifstream ifs(filename, ios::binary);
if (!ifs)return -1;
unsigned char inbuf[4096] = { 0 };//用于存储h264编码流
AVCodecID codec_id = AV_CODEC_ID_H264;
//1 找解码器
auto codec = avcodec_find_decoder(codec_id);
//2 创建解码器上下文
auto c = avcodec_alloc_context3(codec);
//硬件加速格式 DXVA2
auto hw_type = AV_HWDEVICE_TYPE_DXVA2;
/// 打印所有支持的硬件加速方式
for (int i = 0;; i++)
{
auto config = avcodec_get_hw_config(codec, i);
if (!config)break;
if (config->device_type)
cout << av_hwdevice_get_type_name(config->device_type) << endl;
}
//初始化硬件加速上下文
AVBufferRef* hw_ctx = nullptr;
av_hwdevice_ctx_create(&hw_ctx, hw_type, NULL, NULL, 0);
//设定硬件GPU加速
c->hw_device_ctx = av_buffer_ref(hw_ctx);
c->thread_count = 16;
//3 打开上下文
avcodec_open2(c, NULL, NULL);
//分割上下文
auto parser = av_parser_init(codec_id);
auto pkt = av_packet_alloc();
auto frame = av_frame_alloc();
auto begin = NowMs();
int count = 0;//解码统计
bool is_init_win = false;
while (!ifs.eof())
{
ifs.read((char*)inbuf, sizeof(inbuf));//将h264编码的流读入inbuf中,一次读4096
int data_size = ifs.gcount();// 读取的字节数,inbuf中的字节数
if (data_size <= 0)break;
if (ifs.eof())
{
ifs.clear();
ifs.seekg(0, ios::beg);
}
auto data = inbuf;
while (data_size > 0) //一次有多帧数据
{
//通过0001 截断输出到AVPacket 返回帧大小
int ret = av_parser_parse2(parser, c,
&pkt->data, &pkt->size, //截断后输出到AVpacket的data中
data, data_size, //h264编码流,待处理数据
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0
);//返回消耗的输入数据字节数ret。如果所有输入数据都被消耗,则返回值等于 buf_size。如果解析过程中出现错误,则返回负数。
data += ret;//data指针向前移动 ret个字节,继续处理inbuf未处理的数据
data_size -= ret; //待处理的数据大小
if (pkt->size)
{
//cout << pkt->size << " "<<flush;
//发送packet到解码线程
ret = avcodec_send_packet(c, pkt);//把avpacket给解码器进行解码
if (ret < 0)
break;
//获取多帧解码数据
while (ret >= 0)
{
//每次回调用av_frame_unref
ret = avcodec_receive_frame(c, frame);//拿到解码后的数据存储到frame中
if (ret < 0)
break;
// cout << frame->format << " " << flush;
//
/// 第一帧初始化窗口
if (!is_init_win)
{
is_init_win = true;
// view->Init(frame->width, frame->height, (XVideoView::Format)frame->format);
}
// view->DrawFrame(frame);
count++;//每有一帧被渲染count+1
auto cur = NowMs();
if (cur - begin >= 1000)// 1秒钟计算一次
{
cout << "\nfps = " << count << endl;
count = 0;
begin = cur;
}
}
}
}
}
///取出缓存数据,防止丢帧
int ret = avcodec_send_packet(c, NULL);
while (ret >= 0)
{
ret = avcodec_receive_frame(c, frame);
if (ret < 0)
break;
cout << frame->format << "-" << flush;
}
av_parser_close(parser);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
getchar();
return 0;
}
运行结果:
![](https://img-blog.csdnimg.cn/direct/caf827aa33f943b6958a59c63cfc7e72.png)