系列索引:FFmpeg入门系列索引
上一篇:FFmpeg入门教程10.09:软解并使用QML播放视频(YUV420P->OpenGL)
之前几篇文章介绍了使用CPU+FFmpeg解码视频并显示在QWidget/QML/QOpenGL上,本文介绍FFmpeg使用硬件解码,主要是使用CUDA。
主要解码流程和CPU解码差不多。
硬解解码包括CUDA/QSV/DRM/VAAPI/VDPAU等等,CUDA很好理解,你主要装了NVIDIA显卡就可以使用;QSV是Intel CPU自带的解码器,但是现在大部分CPU不带QSV支持(便宜),而且配置也不方便,所以就忽略了。
那么就先选一个:
1 2 3 4 5 6 7 8 9
| type = av_hwdevice_find_type_by_name("cuda"); if (type == AV_HWDEVICE_TYPE_NONE) { fprintf(stderr, "Device type %s is not supported.\n", "h264_cuvid"); fprintf(stderr, "Available device types:"); while((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) fprintf(stderr, " %s", av_hwdevice_get_type_name(type)); fprintf(stderr, "\n"); return -1; }
|
查找名为CUDA的硬件设备,如果没有找到,就输出当前使用的FFmpeg支持的硬件名称。
硬件有了,接下来就是解码器。不同的编码格式对应不同的解码器,比如说H264/H265/VP8等等,以h264为例,此编码器可能支持CUDA硬解也可能不支持(比如说编译的时候没有设置CUDA和硬解支持,那么此时的解码器就不可能支持硬解)。我们需要确定一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| for (i = 0;; i++) { const AVCodecHWConfig *config = avcodec_get_hw_config(videoCodec, i); if (!config) { fprintf(stderr, "Decoder %s does not support device type %s.\n", videoCodec->name, av_hwdevice_get_type_name(type)); return -1; } if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && config->device_type == type) { hw_pix_fmt = config->pix_fmt; break; } }
|
在打开有效解码器之前需要激活硬解:
1 2 3 4 5 6 7 8 9 10 11 12 13
| int FFmpegVideo::hw_decoder_init(AVCodecContext *ctx, const AVHWDeviceType type) { int err = 0;
if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type, NULL, NULL, 0)) < 0) { fprintf(stderr, "Failed to create specified HW device.\n"); return err; } ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
return err; }
|
调用hw_decoder_init来创建硬件上下文。
1 2
| if (hw_decoder_init(videoCodecCtx, type) < 0) return -1;
|
其他的流程代码和软解一样。
QWidget/QML/QOpenGL部分代码和之前的一样,毕竟只是将解码后的数据送往不同的组件显示。
资源占用如下图:
源码在ffmpeg_beginner中10.10.1video_decode_by_cuda_display_by_qwidget
、10.10.2video_decode_by_cuda_display_by_qopengl
、10.10.3video_decode_by_cuda_display_by_qml
下。
下一篇:FFmpeg入门教程10.11:本地yuv文件编码为h264