File indexing completed on 2025-01-19 03:57:06

0001 /*********************************************************
0002  * Copyright (C) 2020, Val Doroshchuk <valbok@gmail.com> *
0003  *                                                       *
0004  * This file is part of QtAVPlayer.                      *
0005  * Free Qt Media Player based on FFmpeg.                 *
0006  *********************************************************/
0007 
0008 #include "qavvideocodec_p.h"
0009 #include "qavhwdevice_p.h"
0010 #include "qavcodec_p_p.h"
0011 #include "qavpacket_p.h"
0012 #include "qavframe.h"
0013 #include "qavvideoframe.h"
0014 #include <QDebug>
0015 
0016 extern "C" {
0017 #include <libavutil/pixdesc.h>
0018 #include <libavcodec/avcodec.h>
0019 }
0020 
0021 QT_BEGIN_NAMESPACE
0022 
0023 class QAVVideoCodecPrivate : public QAVCodecPrivate
0024 {
0025 public:
0026     QSharedPointer<QAVHWDevice> hw_device;
0027 };
0028 
0029 static bool isSoftwarePixelFormat(AVPixelFormat from)
0030 {
0031     switch (from) {
0032     case AV_PIX_FMT_VAAPI:
0033     case AV_PIX_FMT_VDPAU:
0034     case AV_PIX_FMT_MEDIACODEC:
0035     case AV_PIX_FMT_VIDEOTOOLBOX:
0036     case AV_PIX_FMT_D3D11:
0037     case AV_PIX_FMT_D3D11VA_VLD:
0038 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 0, 0)
0039     case AV_PIX_FMT_OPENCL:
0040 #endif
0041     case AV_PIX_FMT_CUDA:
0042     case AV_PIX_FMT_DXVA2_VLD:
0043 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 58, 101)
0044     case AV_PIX_FMT_XVMC:
0045 #endif
0046 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 134, 0)
0047     case AV_PIX_FMT_VULKAN:
0048 #endif
0049     case AV_PIX_FMT_DRM_PRIME:
0050     case AV_PIX_FMT_MMAL:
0051     case AV_PIX_FMT_QSV:
0052         return false;
0053     default:
0054         return true;
0055     }
0056 }
0057 
0058 static AVPixelFormat negotiate_pixel_format(AVCodecContext *c, const AVPixelFormat *f)
0059 {
0060     auto d = reinterpret_cast<QAVVideoCodecPrivate *>(c->opaque);
0061 
0062     QList<AVHWDeviceType> supported;
0063 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 0, 0)
0064     for (int i = 0;; ++i) {
0065         const AVCodecHWConfig *config = avcodec_get_hw_config(c->codec, i);
0066         if (!config)
0067             break;
0068 
0069         if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)
0070             supported.append(config->device_type);
0071     }
0072 
0073     if (!supported.isEmpty()) {
0074         qDebug() << c->codec->name << ": supported hardware device contexts:";
0075         for (auto a: supported)
0076             qDebug() << "   " << av_hwdevice_get_type_name(a);
0077     } else {
0078         qWarning() << "None of the hardware accelerations are supported";
0079     }
0080 #endif
0081 
0082     QList<AVPixelFormat> softwareFormats;
0083     QList<AVPixelFormat> hardwareFormats;
0084     for (int i = 0; f[i] != AV_PIX_FMT_NONE; ++i) {
0085         if (!isSoftwarePixelFormat(f[i])) {
0086             hardwareFormats.append(f[i]);
0087             continue;
0088         }
0089         softwareFormats.append(f[i]);
0090     }
0091 
0092     qDebug() << "Available pixel formats:";
0093     for (auto a : softwareFormats) {
0094         auto dsc = av_pix_fmt_desc_get(a);
0095         qDebug() << "  " << dsc->name << ": AVPixelFormat(" << a << ")";
0096     }
0097 
0098     for (auto a : hardwareFormats) {
0099         auto dsc = av_pix_fmt_desc_get(a);
0100         qDebug() << "  " << dsc->name << ": AVPixelFormat(" << a << ")";
0101     }
0102 
0103     AVPixelFormat pf = !softwareFormats.isEmpty() ? softwareFormats[0] : AV_PIX_FMT_NONE;
0104     const char *decStr = "software";
0105     if (d->hw_device) {
0106         for (auto f : hardwareFormats) {
0107             if (f == d->hw_device->format()) {
0108                 d->hw_device->init(c);
0109                 pf = d->hw_device->format();
0110                 decStr = "hardware";
0111                 break;
0112             }
0113         }
0114     }
0115 
0116     auto dsc = av_pix_fmt_desc_get(pf);
0117     if (dsc)
0118         qDebug() << "Using" << decStr << "decoding in" << dsc->name;
0119     else
0120         qDebug() << "None of the pixel formats";
0121 
0122     return pf;
0123 }
0124 
0125 QAVVideoCodec::QAVVideoCodec()
0126     : QAVFrameCodec(*new QAVVideoCodecPrivate)
0127 {
0128     d_ptr->avctx->opaque = d_ptr.get();
0129     d_ptr->avctx->get_format = negotiate_pixel_format;
0130 }
0131 
0132 QAVVideoCodec::~QAVVideoCodec()
0133 {
0134     av_buffer_unref(&avctx()->hw_device_ctx);
0135 }
0136 
0137 void QAVVideoCodec::setDevice(const QSharedPointer<QAVHWDevice> &d)
0138 {
0139     d_func()->hw_device = d;
0140 }
0141 
0142 QAVHWDevice *QAVVideoCodec::device() const
0143 {
0144     return d_func()->hw_device.data();
0145 }
0146 
0147 QT_END_NAMESPACE