Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qffmpeghwaccel_mediacodec.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
7#include <rhi/qrhi.h>
8
9extern "C" {
10#include <libavcodec/mediacodec.h>
11#include <libavutil/hwcontext_mediacodec.h>
12}
13
14#if !defined(Q_OS_ANDROID)
15# error "Configuration error"
16#endif
17
18namespace QFFmpeg {
19
21{
22public:
23 MediaCodecTextureSet(qint64 textureHandle) : handle(textureHandle) { }
24
25 qint64 textureHandle(QRhi *, int plane) override { return (plane == 0) ? handle : 0; }
26
27private:
28 qint64 handle;
29};
30
31namespace {
32
33void deleteSurface(AVHWDeviceContext *ctx)
34{
35 AndroidSurfaceTexture* s = reinterpret_cast<AndroidSurfaceTexture *>(ctx->user_opaque);
36 delete s;
37}
38
39AndroidSurfaceTexture* getTextureSurface(AVFrame *frame)
40{
41 if (!frame || !frame->hw_frames_ctx)
42 return nullptr;
43
44 auto *frameContext = reinterpret_cast<AVHWFramesContext *>(frame->hw_frames_ctx->data);
45
46 if (!frameContext || !frameContext->device_ctx)
47 return nullptr;
48
49 AVHWDeviceContext *deviceContext = frameContext->device_ctx;
50
51 return reinterpret_cast<AndroidSurfaceTexture *>(deviceContext->user_opaque);
52}
53} // namespace
54
55void MediaCodecTextureConverter::setupDecoderSurface(AVCodecContext *avCodecContext)
56{
57 std::unique_ptr<AndroidSurfaceTexture> androidSurfaceTexture(new AndroidSurfaceTexture(0));
58 AVMediaCodecContext *mediacodecContext = av_mediacodec_alloc_context();
59 av_mediacodec_default_init(avCodecContext, mediacodecContext, androidSurfaceTexture->surface());
60
61 if (!avCodecContext->hw_device_ctx || !avCodecContext->hw_device_ctx->data)
62 return;
63
64 AVHWDeviceContext *deviceContext =
65 reinterpret_cast<AVHWDeviceContext *>(avCodecContext->hw_device_ctx->data);
66
67 if (!deviceContext->hwctx)
68 return;
69
70 AVMediaCodecDeviceContext *mediaDeviceContext =
71 reinterpret_cast<AVMediaCodecDeviceContext *>(deviceContext->hwctx);
72
73 if (!mediaDeviceContext)
74 return;
75
76 mediaDeviceContext->surface = androidSurfaceTexture->surface();
77
78 Q_ASSERT(deviceContext->user_opaque == nullptr);
79 deviceContext->user_opaque = androidSurfaceTexture.release();
80 deviceContext->free = deleteSurface;
81}
82
84{
85 AndroidSurfaceTexture * androidSurfaceTexture = getTextureSurface(frame);
86
87 if (!androidSurfaceTexture || !androidSurfaceTexture->isValid())
88 return {};
89
90 if (!externalTexture || m_currentSurfaceIndex != androidSurfaceTexture->index()) {
91 m_currentSurfaceIndex = androidSurfaceTexture->index();
92 androidSurfaceTexture->detachFromGLContext();
93 externalTexture = std::unique_ptr<QRhiTexture>(
94 rhi->newTexture(QRhiTexture::Format::RGBA8, { frame->width, frame->height }, 1,
95 QRhiTexture::ExternalOES));
96
97 if (!externalTexture->create()) {
98 qWarning() << "Failed to create the external texture!";
99 return {};
100 }
101
102 quint64 textureHandle = externalTexture->nativeTexture().object;
103 androidSurfaceTexture->attachToGLContext(textureHandle);
104 }
105
106 // release a MediaCodec buffer and render it to the surface
107 AVMediaCodecBuffer *buffer = (AVMediaCodecBuffer *)frame->data[3];
108
109 if (!buffer) {
110 qWarning() << "Received a frame without AVMediaCodecBuffer.";
111 } else if (av_mediacodec_release_buffer(buffer, 1) < 0) {
112 qWarning() << "Failed to render buffer to surface.";
113 return {};
114 }
115
116 androidSurfaceTexture->updateTexImage();
117
118 return new MediaCodecTextureSet(externalTexture->nativeTexture().object);
119}
120}
static void setupDecoderSurface(AVCodecContext *s)
TextureSet * getTextures(AVFrame *frame) override
qint64 textureHandle(QRhi *, int plane) override