Quick Sync Video,简称qsv,是英特尔推出的集成加速接口,使用该接口可以硬解h264,提高解码效率的同时降低CPU占用率,ffmpeg 4.4.2中 doc\example中有一个qsvdec.c的demo,我在此基础上进行修改,实现了硬解h264。
下载安装Intel Media Mdk,https://software.intel.com/en-us/media-sdk,选择window平台,安装后在安装目录下IntelSWTools\Intel(R) Media SDK 2019 R1\Software Development Kit 有include和lib 文件夹,拷贝lib、dll、头文件备用。
创建一个VS c++ 控制台工程,将拷贝的include和lib 等复制到工程目录下,设置好库目录和包含目录以及连接库。新建一个cpp文件,qsvdev.c的代码拷贝到cpp文件,并对代码做出以下修改。
1、修改get_format返回值为AVPixelFormat
static AVPixelFormat get_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts)
{
while (*pix_fmts != AV_PIX_FMT_NONE)
{
if (*pix_fmts == AV_PIX_FMT_QSV)
{
DecodeContext *decode = (DecodeContext *)avctx->opaque;
AVHWFramesContext *frames_ctx;
AVQSVFramesContext *frames_hwctx;
int ret;
/* create a pool of surfaces to be used by the decoder */
avctx->hw_frames_ctx = av_hwframe_ctx_alloc(decode->hw_device_ref);
if (!avctx->hw_frames_ctx)
return AV_PIX_FMT_NONE;
frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
frames_hwctx = (AVQSVFramesContext*)frames_ctx->hwctx;
frames_ctx->format = AV_PIX_FMT_QSV;
frames_ctx->sw_format = avctx->sw_pix_fmt;
frames_ctx->width = FFALIGN(avctx->coded_width, 32);
frames_ctx->height = FFALIGN(avctx->coded_height, 32);
frames_ctx->initial_pool_size = 32;
frames_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
ret = av_hwframe_ctx_init(avctx->hw_frames_ctx);
if (ret < 0)
return AV_PIX_FMT_NONE;
return AV_PIX_FMT_QSV;
}
pix_fmts++;
}
fprintf(stderr, "The QSV pixel format not offered in get_format()\n");
return AV_PIX_FMT_NONE;
}
2、添加SDL 头文件 SDL,在连接器那里输入SDL2.lib、SDL2main.lib,拷贝SDL 相关的DLL到目录下,使用SDL来显示数据。
SDL 初始化
创建窗口
screen = SDL_CreateWindow("test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
decoder_ctx->width, decoder_ctx->height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
创建渲染器
render = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED);
创建纹理
texture = SDL_CreateTexture(render, SDL_PIXELFORMAT_NV12, SDL_TEXTUREACCESS_STREAMING, decoder_ctx->width, decoder_ctx->height);
分配一个buffer用来存储NV12 数据
nv12Data = new unsigned char[decoder_ctx->width * decoder_ctx->height * 1.5];
将NV12 数据拷贝到分配的内存
for (i = 0; i < FF_ARRAY_ELEMS(sw_frame->data) && sw_frame->data[i]; i++)//
{
for (j = 0; j < (sw_frame->height >> (i > 0)); j++)//
{
memcpy(nv12Data + i* sw_frame->width*sw_frame->height + sw_frame->width*j, sw_frame->data[i] + j * sw_frame->linesize[i], sw_frame->width);
}
}
渲染
SDL_UpdateTexture(texture, NULL, nv12Data, sw_frame->linesize[0]);
//SDL_UpdateTexture(texture, NULL, sw_frame->data[0], sw_frame->linesize[0]);
SDL_RenderClear(render);
SDL_RenderCopy(render, texture, NULL, &sdlRect);
SDL_RenderPresent(render);