89 QAbstractVideoBuffer::MapData mapData;
91 if (m_mapMode == QVideoFrame::NotMapped && mode == QVideoFrame::ReadOnly) {
92 m_mapMode = QVideoFrame::ReadOnly;
93 m_image = qImageFromVideoFrame(QVideoFramePrivate::createFrame(
94 std::make_unique<ImageFromVideoFrameHelper>(*
this),
95 QVideoFrameFormat(m_size, QVideoFrameFormat::Format_RGBA8888)));
96 mapData.planeCount = 1;
97 mapData.bytesPerLine[0] = m_image.bytesPerLine();
98 mapData.dataSize[0] =
static_cast<
int>(m_image.sizeInBytes());
99 mapData.data[0] = m_image.bits();
114 static QShader getShader(
const QString &name)
117 if (f.open(QIODevice::ReadOnly))
118 return QShader::fromSerialized(f.readAll());
126 m_vertexBuffer.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer,
sizeof(g_quad)));
127 m_vertexBuffer->create();
129 m_uniformBuffer.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 64 + 4 + 4));
130 m_uniformBuffer->create();
132 m_sampler.reset(m_rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
133 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
136 m_srb.reset(m_rhi->newShaderResourceBindings());
138 QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_uniformBuffer.get()),
139 QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, externalTex, m_sampler.get())
143 m_vertexShader = getShader(QStringLiteral(
":/qt-project.org/multimedia/shaders/externalsampler.vert.qsb"));
144 Q_ASSERT(m_vertexShader.isValid());
145 m_fragmentShader = getShader(QStringLiteral(
":/qt-project.org/multimedia/shaders/externalsampler.frag.qsb"));
146 Q_ASSERT(m_fragmentShader.isValid());
152 QRhi *m_rhi =
nullptr;
153 std::unique_ptr<QRhiBuffer> m_vertexBuffer;
154 std::unique_ptr<QRhiBuffer> m_uniformBuffer;
155 std::unique_ptr<QRhiSampler> m_sampler;
156 std::unique_ptr<QRhiShaderResourceBindings> m_srb;
157 QShader m_vertexShader;
158 QShader m_fragmentShader;
162 QRhiShaderResourceBindings *shaderResourceBindings,
163 QRhiRenderPassDescriptor *renderPassDescriptor,
164 QShader vertexShader,
165 QShader fragmentShader)
167 std::unique_ptr<QRhiGraphicsPipeline> gp(rhi->newGraphicsPipeline());
168 gp->setTopology(QRhiGraphicsPipeline::TriangleFan);
169 gp->setShaderStages({
170 { QRhiShaderStage::Vertex, vertexShader },
171 { QRhiShaderStage::Fragment, fragmentShader }
174 inputLayout.setBindings({
175 { 4 *
sizeof(
float) }
177 inputLayout.setAttributes({
178 { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
179 { 0, 1, QRhiVertexInputAttribute::Float2, 2 *
sizeof(
float) }
181 gp->setVertexInputLayout(inputLayout);
182 gp->setShaderResourceBindings(shaderResourceBindings);
183 gp->setRenderPassDescriptor(renderPassDescriptor);
191 std::unique_ptr<QRhiTexture> tex(m_rhi->newTexture(QRhiTexture::RGBA8, size, 1, QRhiTexture::RenderTarget));
192 if (!tex->create()) {
193 qWarning(
"Failed to create frame texture");
197 std::unique_ptr<QRhiTextureRenderTarget> renderTarget(m_rhi->newTextureRenderTarget({ { tex.get() } }));
198 std::unique_ptr<QRhiRenderPassDescriptor> renderPassDescriptor(renderTarget->newCompatibleRenderPassDescriptor());
199 renderTarget->setRenderPassDescriptor(renderPassDescriptor.get());
200 renderTarget->create();
202 QRhiResourceUpdateBatch *rub = m_rhi->nextResourceUpdateBatch();
203 rub->uploadStaticBuffer(m_vertexBuffer.get(),
g_quad);
206 char *p = m_uniformBuffer->beginFullDynamicBufferUpdateForCurrentFrame();
207 memcpy(p, identity.constData(), 64);
208 memcpy(p + 64, externalTexMatrix.constData(), 64);
209 float opacity = 1.0f;
210 memcpy(p + 64 + 64, &opacity, 4);
211 m_uniformBuffer->endFullDynamicBufferUpdateForCurrentFrame();
213 auto graphicsPipeline = newGraphicsPipeline(m_rhi, m_srb.get(), renderPassDescriptor.get(),
214 m_vertexShader, m_fragmentShader);
216 const QRhiCommandBuffer::VertexInput vbufBinding(m_vertexBuffer.get(), 0);
218 QRhiCommandBuffer *cb =
nullptr;
219 if (m_rhi->beginOffscreenFrame(&cb) != QRhi::FrameOpSuccess)
222 cb->beginPass(renderTarget.get(), Qt::transparent, { 1.0f, 0 }, rub);
223 cb->setGraphicsPipeline(graphicsPipeline.get());
224 cb->setViewport({0, 0,
float(size.width()),
float(size.height())});
225 cb->setShaderResources(m_srb.get());
226 cb->setVertexInput(0, 1, &vbufBinding);
229 m_rhi->endOffscreenFrame();
231 QOpenGLContext *ctx = QOpenGLContext::currentContext();
232 QOpenGLFunctions *f = ctx->functions();
233 static_cast<QOpenGLExtensions *>(f)->flushShared();
398 QMetaObject::invokeMethod(m_surfaceThread.get(), [&]() {
399 auto rhi = m_sink->rhi();
401 m_surfaceCreatedWithoutRhi =
true;
403 else if (m_surfaceCreatedWithoutRhi) {
404 m_surfaceThread->clearSurfaceTexture();
405 m_surfaceCreatedWithoutRhi =
false;
407 surface = m_surfaceThread->createSurfaceTexture(rhi);
409 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::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)