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

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 "qavhwdevice_mediacodec_p.h"
0009 #include "qavvideobuffer_gpu_p.h"
0010 #include "qavcodec_p.h"
0011 #include "qavandroidsurfacetexture_p.h"
0012 #include <GLES/gl.h>
0013 
0014 extern "C" {
0015 #include <libavutil/pixdesc.h>
0016 #include <libavcodec/mediacodec.h>
0017 #include <libavutil/hwcontext_mediacodec.h>
0018 }
0019 
0020 QT_BEGIN_NAMESPACE
0021 
0022 Q_GLOBAL_STATIC(QAVAndroidSurfaceTexture, androidSurfaceTexture);
0023 
0024 class QAVHWDevice_MediaCodecPrivate
0025 {
0026 public:
0027     GLuint texture = 0;
0028 };
0029 
0030 QAVHWDevice_MediaCodec::QAVHWDevice_MediaCodec()
0031     : d_ptr(new QAVHWDevice_MediaCodecPrivate)
0032 {
0033 }
0034 
0035 QAVHWDevice_MediaCodec::~QAVHWDevice_MediaCodec()
0036 {
0037     Q_D(QAVHWDevice_MediaCodec);
0038     if (d->texture)
0039         glDeleteTextures(1, &d->texture);
0040 }
0041 
0042 void QAVHWDevice_MediaCodec::init(AVCodecContext *avctx)
0043 {
0044 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0045     AVBufferRef *hw_device_ctx = avctx->hw_device_ctx;
0046     if (hw_device_ctx) {
0047         AVHWDeviceContext *deviceContext = reinterpret_cast<AVHWDeviceContext *>(hw_device_ctx->data);
0048         if (deviceContext->hwctx) {
0049             AVMediaCodecDeviceContext *mediaDeviceContext =
0050                 reinterpret_cast<AVMediaCodecDeviceContext *>(deviceContext->hwctx);
0051             if (mediaDeviceContext)
0052                 mediaDeviceContext->surface = androidSurfaceTexture->surface();
0053         }
0054     }
0055 #else
0056     Q_UNUSED(avctx);
0057 #endif
0058 }
0059 
0060 AVPixelFormat QAVHWDevice_MediaCodec::format() const
0061 {
0062     return AV_PIX_FMT_MEDIACODEC;
0063 }
0064 
0065 AVHWDeviceType QAVHWDevice_MediaCodec::type() const
0066 {
0067     return AV_HWDEVICE_TYPE_MEDIACODEC;
0068 }
0069 
0070 class VideoBuffer_MediaCodec : public QAVVideoBuffer_GPU
0071 {
0072 public:
0073     VideoBuffer_MediaCodec(QAVHWDevice_MediaCodecPrivate *hw, const QAVVideoFrame &frame)
0074         : QAVVideoBuffer_GPU(frame)
0075         , m_hw(hw)
0076     {
0077     }
0078 
0079     QAVVideoFrame::HandleType handleType() const override
0080     {
0081         return QAVVideoFrame::GLTextureHandle;
0082     }
0083 
0084     QVariant handle(QRhi */*rhi*/) const override
0085     {
0086         if (!androidSurfaceTexture->isValid())
0087             return {};
0088 
0089         if (!m_hw->texture) {
0090             androidSurfaceTexture->detachFromGLContext();
0091             glGenTextures(1, &m_hw->texture);
0092             androidSurfaceTexture->attachToGLContext(m_hw->texture);
0093         }
0094 
0095         AVMediaCodecBuffer *buffer = reinterpret_cast<AVMediaCodecBuffer *>(frame().frame()->data[3]);
0096         if (!buffer) {
0097             qWarning() << "Received a frame without AVMediaCodecBuffer.";
0098         } else if (av_mediacodec_release_buffer(buffer, 1) < 0) {
0099             qWarning() << "Failed to render buffer to surface.";
0100             return {};
0101         }
0102 
0103         androidSurfaceTexture->updateTexImage();
0104         return m_hw->texture;
0105     }
0106 
0107     QAVHWDevice_MediaCodecPrivate *m_hw = nullptr;
0108 };
0109 
0110 QAVVideoBuffer *QAVHWDevice_MediaCodec::videoBuffer(const QAVVideoFrame &frame) const
0111 {
0112     return new VideoBuffer_MediaCodec(d_ptr.get(), frame);
0113 }
0114 
0115 QT_END_NAMESPACE