105 QAbstractVideoBuffer::MapData mapData;
107 if (m_mapMode == QVideoFrame::NotMapped && mode == QVideoFrame::ReadOnly) {
108 m_mapMode = QVideoFrame::ReadOnly;
109 m_image = qImageFromVideoFrame(QVideoFramePrivate::createFrame(
110 std::make_unique<ImageFromVideoFrameHelper>(*
this),
111 QVideoFrameFormat(m_size, QVideoFrameFormat::Format_RGBA8888)));
112 mapData.planeCount = 1;
113 mapData.bytesPerLine[0] = m_image.bytesPerLine();
114 mapData.dataSize[0] =
static_cast<
int>(m_image.sizeInBytes());
115 mapData.data[0] = m_image.bits();
130 static QShader getShader(
const QString &name)
133 if (f.open(QIODevice::ReadOnly))
134 return QShader::fromSerialized(f.readAll());
142 m_vertexBuffer.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer,
sizeof(g_quad)));
143 m_vertexBuffer->create();
145 m_uniformBuffer.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 64 + 4 + 4));
146 m_uniformBuffer->create();
148 m_sampler.reset(m_rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
149 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
152 m_srb.reset(m_rhi->newShaderResourceBindings());
154 QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_uniformBuffer.get()),
155 QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, externalTex, m_sampler.get())
159 m_vertexShader = getShader(QStringLiteral(
":/qt-project.org/multimedia/shaders/externalsampler.vert.qsb"));
160 Q_ASSERT(m_vertexShader.isValid());
161 m_fragmentShader = getShader(QStringLiteral(
":/qt-project.org/multimedia/shaders/externalsampler.frag.qsb"));
162 Q_ASSERT(m_fragmentShader.isValid());
168 QRhi *m_rhi =
nullptr;
169 std::unique_ptr<QRhiBuffer> m_vertexBuffer;
170 std::unique_ptr<QRhiBuffer> m_uniformBuffer;
171 std::unique_ptr<QRhiSampler> m_sampler;
172 std::unique_ptr<QRhiShaderResourceBindings> m_srb;
173 QShader m_vertexShader;
174 QShader m_fragmentShader;
178 QRhiShaderResourceBindings *shaderResourceBindings,
179 QRhiRenderPassDescriptor *renderPassDescriptor,
180 QShader vertexShader,
181 QShader fragmentShader)
183 std::unique_ptr<QRhiGraphicsPipeline> gp(rhi->newGraphicsPipeline());
184 gp->setTopology(QRhiGraphicsPipeline::TriangleFan);
185 gp->setShaderStages({
186 { QRhiShaderStage::Vertex, vertexShader },
187 { QRhiShaderStage::Fragment, fragmentShader }
190 inputLayout.setBindings({
191 { 4 *
sizeof(
float) }
193 inputLayout.setAttributes({
194 { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
195 { 0, 1, QRhiVertexInputAttribute::Float2, 2 *
sizeof(
float) }
197 gp->setVertexInputLayout(inputLayout);
198 gp->setShaderResourceBindings(shaderResourceBindings);
199 gp->setRenderPassDescriptor(renderPassDescriptor);
207 std::unique_ptr<QRhiTexture> tex(m_rhi->newTexture(QRhiTexture::RGBA8, size, 1, QRhiTexture::RenderTarget));
208 if (!tex->create()) {
209 qWarning(
"Failed to create frame texture");
213 std::unique_ptr<QRhiTextureRenderTarget> renderTarget(m_rhi->newTextureRenderTarget({ { tex.get() } }));
214 std::unique_ptr<QRhiRenderPassDescriptor> renderPassDescriptor(renderTarget->newCompatibleRenderPassDescriptor());
215 renderTarget->setRenderPassDescriptor(renderPassDescriptor.get());
216 renderTarget->create();
218 QRhiResourceUpdateBatch *rub = m_rhi->nextResourceUpdateBatch();
219 rub->uploadStaticBuffer(m_vertexBuffer.get(), g_quad);
222 char *p = m_uniformBuffer->beginFullDynamicBufferUpdateForCurrentFrame();
223 memcpy(p, identity.constData(), 64);
224 memcpy(p + 64, externalTexMatrix.constData(), 64);
225 float opacity = 1.0f;
226 memcpy(p + 64 + 64, &opacity, 4);
227 m_uniformBuffer->endFullDynamicBufferUpdateForCurrentFrame();
229 auto graphicsPipeline = newGraphicsPipeline(m_rhi, m_srb.get(), renderPassDescriptor.get(),
230 m_vertexShader, m_fragmentShader);
232 const QRhiCommandBuffer::VertexInput vbufBinding(m_vertexBuffer.get(), 0);
234 QRhiCommandBuffer *cb =
nullptr;
235 if (m_rhi->beginOffscreenFrame(&cb) != QRhi::FrameOpSuccess)
238 cb->beginPass(renderTarget.get(), Qt::transparent, { 1.0f, 0 }, rub);
239 cb->setGraphicsPipeline(graphicsPipeline.get());
240 cb->setViewport({0, 0,
float(size.width()),
float(size.height())});
241 cb->setShaderResources(m_srb.get());
242 cb->setVertexInput(0, 1, &vbufBinding);
245 m_rhi->endOffscreenFrame();
247 QOpenGLContext *ctx = QOpenGLContext::currentContext();
248 QOpenGLFunctions *f = ctx->functions();
249 static_cast<QOpenGLExtensions *>(f)->flushShared();
420 QMetaObject::invokeMethod(m_surfaceThread.get(), [&]() {
421 auto rhi = m_sink->rhi();
423 m_surfaceCreatedWithoutRhi =
true;
425 else if (m_surfaceCreatedWithoutRhi) {
426 m_surfaceThread->clearSurfaceTexture();
427 m_surfaceCreatedWithoutRhi =
false;
429 surface = m_surfaceThread->createSurfaceTexture(rhi);
431 Qt::BlockingQueuedConnection);
MapData map(QVideoFrame::MapMode mode) override
Maps the planes of a video buffer to memory.
void unmap() override
Releases the memory mapped by the map() function.
AndroidTextureVideoBuffer(std::shared_ptr< QRhi > rhi, std::shared_ptr< AndroidTextureThread > thread, std::unique_ptr< QRhiTexture > tex, const QSize &size)
QVideoFrameTexturesUPtr mapTextures(QRhi &rhi, QVideoFrameTexturesUPtr &) override
void setSubtitle(const QString &subtitle)
void setVideoSize(const QSize &) override
AndroidSurfaceTexture * surfaceTexture() override
bool shouldTextureBeUpdated() const
~QAndroidTextureVideoOutput() override
QAndroidVideoFrameTextures(QRhi *rhi, QSize size, quint64 handle)
QRhiTexture * texture(uint plane) const override
TextureCopy(QRhi *rhi, QRhiTexture *externalTex)
std::unique_ptr< QRhiTexture > copyExternalTexture(QSize size, const QMatrix4x4 &externalTexMatrix)
static std::unique_ptr< QRhiGraphicsPipeline > newGraphicsPipeline(QRhi *rhi, QRhiShaderResourceBindings *shaderResourceBindings, QRhiRenderPassDescriptor *renderPassDescriptor, QShader vertexShader, QShader fragmentShader)