32 [](
int,
int) {
return 0; },
34 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
40 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
46 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
52 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
58 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
64 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
70 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
76 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
82 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
88 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
94 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
100 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
106 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
112 { { 1, 1 }, { 2, 2 }, { 2, 2 } }
118 { { 1, 1 }, { 2, 1 }, { 2, 1 } }
124 { { 1, 1 }, { 2, 2 }, { 2, 2 } }
130 { { 2, 1 }, { 1, 1 }, { 1, 1 } }
136 { { 2, 1 }, { 1, 1 }, { 1, 1 } }
142 { { 1, 1 }, { 2, 2 }, { 1, 1 } }
148 { { 1, 1 }, { 2, 2 }, { 1, 1 } }
155 h += 2*(((
h/2) + 15) & ~15);
159 { { 1, 1 }, { 2, 2 }, { 2, 2 } }
165 { { 1, 1 }, { 1, 2 }, { 1, 1 } }
172 h += 2*(((
h/2) + 15) & ~15);
176 { { 1, 1 }, { 2, 2 }, { 2, 2 } }
182 { { 1, 1 }, { 1, 2 }, { 1, 1 } }
188 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
194 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
200 { { 1, 1 }, { 2, 2 }, { 1, 1 } }
206 { { 1, 1 }, { 2, 2 }, { 1, 1 } }
211 [](
int,
int) {
return 0; },
213 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
219 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
224 [](
int,
int) {
return 0; },
226 { { 1, 1 }, { 1, 1 }, { 1, 1 } }
232 { { 1, 1 }, { 2, 2 }, { 2, 2 } }
341QString fragmentShaderFileName(
const QVideoFrameFormat &format, QRhi *,
342 QRhiSwapChain::Format surfaceFormat)
345 switch (format.pixelFormat()) {
346 case QVideoFrameFormat::Format_Y8:
347 shaderFile = QStringLiteral(
"y");
349 case QVideoFrameFormat::Format_Y16:
350 shaderFile = QStringLiteral(
"y16");
352 case QVideoFrameFormat::Format_AYUV:
353 case QVideoFrameFormat::Format_AYUV_Premultiplied:
354 shaderFile = QStringLiteral(
"ayuv");
356 case QVideoFrameFormat::Format_ARGB8888:
357 case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
358 case QVideoFrameFormat::Format_XRGB8888:
359 shaderFile = QStringLiteral(
"argb");
361 case QVideoFrameFormat::Format_ABGR8888:
362 case QVideoFrameFormat::Format_XBGR8888:
363 shaderFile = QStringLiteral(
"abgr");
365 case QVideoFrameFormat::Format_Jpeg:
366 shaderFile = QStringLiteral(
"bgra");
368 case QVideoFrameFormat::Format_RGBA8888:
369 case QVideoFrameFormat::Format_RGBX8888:
370 case QVideoFrameFormat::Format_BGRA8888:
371 case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
372 case QVideoFrameFormat::Format_BGRX8888:
373 shaderFile = QStringLiteral(
"rgba");
375 case QVideoFrameFormat::Format_YUV420P:
376 case QVideoFrameFormat::Format_YUV422P:
377 case QVideoFrameFormat::Format_IMC3:
378 shaderFile = QStringLiteral(
"yuv_triplanar");
380 case QVideoFrameFormat::Format_YUV420P10:
381 shaderFile = QStringLiteral(
"yuv_triplanar_p10");
383 case QVideoFrameFormat::Format_YV12:
384 case QVideoFrameFormat::Format_IMC1:
385 shaderFile = QStringLiteral(
"yvu_triplanar");
387 case QVideoFrameFormat::Format_IMC2:
388 shaderFile = QStringLiteral(
"imc2");
390 case QVideoFrameFormat::Format_IMC4:
391 shaderFile = QStringLiteral(
"imc4");
393 case QVideoFrameFormat::Format_UYVY:
394 shaderFile = QStringLiteral(
"uyvy");
396 case QVideoFrameFormat::Format_YUYV:
397 shaderFile = QStringLiteral(
"yuyv");
399 case QVideoFrameFormat::Format_P010:
400 case QVideoFrameFormat::Format_P016:
402 if (format.colorTransfer() == QVideoFrameFormat::ColorTransfer_ST2084) {
403 shaderFile = QStringLiteral(
"nv12_bt2020_pq");
406 if (format.colorTransfer() == QVideoFrameFormat::ColorTransfer_STD_B67) {
407 shaderFile = QStringLiteral(
"nv12_bt2020_hlg");
410 shaderFile = QStringLiteral(
"p016");
412 case QVideoFrameFormat::Format_NV12:
413 shaderFile = QStringLiteral(
"nv12");
415 case QVideoFrameFormat::Format_NV21:
416 shaderFile = QStringLiteral(
"nv21");
418 case QVideoFrameFormat::Format_SamplerExternalOES:
420 shaderFile = QStringLiteral(
"externalsampler");
423 case QVideoFrameFormat::Format_SamplerRect:
425 shaderFile = QStringLiteral(
"rectsampler_bgra");
429 case QVideoFrameFormat::Format_Invalid:
434 if (shaderFile.isEmpty())
437 shaderFile.prepend(u":/qt-project.org/multimedia/shaders/");
439 if (surfaceFormat == QRhiSwapChain::HDRExtendedSrgbLinear)
440 shaderFile.append(u"_linear");
442 shaderFile.append(u".frag.qsb");
444 Q_ASSERT_X(QFile::exists(shaderFile), Q_FUNC_INFO,
445 QStringLiteral(
"Shader file %1 does not exist").arg(shaderFile).toLatin1());
446 qCDebug(qLcVideoTextureHelper) <<
"fragmentShaderFileName returns" << shaderFile;
484 auto colorSpace = format.colorSpace();
485 if (colorSpace == QVideoFrameFormat::ColorSpace_Undefined) {
486 if (format.frameHeight() > 576)
488 colorSpace = QVideoFrameFormat::ColorSpace_BT709;
491 colorSpace = QVideoFrameFormat::ColorSpace_BT601;
493 switch (colorSpace) {
494 case QVideoFrameFormat::ColorSpace_AdobeRgb:
496 1.0f, 0.000f, 1.402f, -0.701f,
497 1.0f, -0.344f, -0.714f, 0.529f,
498 1.0f, 1.772f, 0.000f, -0.886f,
499 0.0f, 0.000f, 0.000f, 1.000f
502 case QVideoFrameFormat::ColorSpace_BT709:
503 if (format.colorRange() == QVideoFrameFormat::ColorRange_Full)
505 1.0f, 0.0f, 1.5748f, -0.790488f,
506 1.0f, -0.187324f, -0.468124f, 0.329010f,
507 1.0f, 1.855600f, 0.0f, -0.931439f,
508 0.0f, 0.0f, 0.0f, 1.0f
511 1.1644f, 0.0000f, 1.7927f, -0.9729f,
512 1.1644f, -0.2132f, -0.5329f, 0.3015f,
513 1.1644f, 2.1124f, 0.0000f, -1.1334f,
514 0.0000f, 0.0000f, 0.0000f, 1.0000f
516 case QVideoFrameFormat::ColorSpace_BT2020:
517 if (format.colorRange() == QVideoFrameFormat::ColorRange_Full)
519 1.f, 0.0000f, 1.4746f, -0.7402f,
520 1.f, -0.1646f, -0.5714f, 0.3694f,
521 1.f, 1.8814f, 0.000f, -0.9445f,
522 0.0f, 0.0000f, 0.000f, 1.0000f
525 1.1644f, 0.000f, 1.6787f, -0.9157f,
526 1.1644f, -0.1874f, -0.6504f, 0.3475f,
527 1.1644f, 2.1418f, 0.0000f, -1.1483f,
528 0.0000f, 0.0000f, 0.0000f, 1.0000f
530 case QVideoFrameFormat::ColorSpace_BT601:
533 if (format.colorRange() == QVideoFrameFormat::ColorRange_Full)
535 1.f, 0.000f, 1.772f, -0.886f,
536 1.f, -0.1646f, -0.57135f, 0.36795f,
537 1.f, 1.42f, 0.000f, -0.71f,
538 0.0f, 0.000f, 0.000f, 1.0000f
541 1.164f, 0.000f, 1.596f, -0.8708f,
542 1.164f, -0.392f, -0.813f, 0.5296f,
543 1.164f, 2.017f, 0.000f, -1.0810f,
544 0.000f, 0.000f, 0.000f, 1.0000f
585 const QVideoFrame &frame,
const QMatrix4x4 &transform,
float opacity,
593 switch (format.pixelFormat()) {
594 case QVideoFrameFormat::Format_Invalid:
597 case QVideoFrameFormat::Format_ARGB8888:
598 case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
599 case QVideoFrameFormat::Format_XRGB8888:
600 case QVideoFrameFormat::Format_BGRA8888:
601 case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
602 case QVideoFrameFormat::Format_BGRX8888:
603 case QVideoFrameFormat::Format_ABGR8888:
604 case QVideoFrameFormat::Format_XBGR8888:
605 case QVideoFrameFormat::Format_RGBA8888:
606 case QVideoFrameFormat::Format_RGBX8888: {
607 if (format.colorRange() == QVideoFrameFormat::ColorRange_Video) {
608 constexpr float scale = 255.0f / 219.0f;
609 constexpr float offset = -16.0f / 219.0f;
612 scale, 0.f, 0.f, offset,
613 0.f, scale, 0.f, offset,
614 0.f, 0.f, scale, offset,
623 case QVideoFrameFormat::Format_Jpeg:
624 case QVideoFrameFormat::Format_Y8:
625 case QVideoFrameFormat::Format_Y16:
627 case QVideoFrameFormat::Format_IMC1:
628 case QVideoFrameFormat::Format_IMC2:
629 case QVideoFrameFormat::Format_IMC3:
630 case QVideoFrameFormat::Format_IMC4:
631 case QVideoFrameFormat::Format_AYUV:
632 case QVideoFrameFormat::Format_AYUV_Premultiplied:
633 case QVideoFrameFormat::Format_YUV420P:
634 case QVideoFrameFormat::Format_YUV420P10:
635 case QVideoFrameFormat::Format_YUV422P:
636 case QVideoFrameFormat::Format_YV12:
637 case QVideoFrameFormat::Format_UYVY:
638 case QVideoFrameFormat::Format_YUYV:
639 case QVideoFrameFormat::Format_NV12:
640 case QVideoFrameFormat::Format_NV21:
641 case QVideoFrameFormat::Format_P010:
642 case QVideoFrameFormat::Format_P016:
643 cmat = colorMatrix(format);
645 case QVideoFrameFormat::Format_SamplerExternalOES:
647 if (
auto hwBuffer = QVideoFramePrivate::hwBuffer(frame))
648 cmat = hwBuffer->externalTextureMatrix();
650 case QVideoFrameFormat::Format_SamplerRect:
656 const QSize videoSize = frame.size();
657 cmat.scale(videoSize.width(), videoSize.height());
666 switch (format.colorTransfer()) {
667 case QVideoFrameFormat::ColorTransfer_ST2084:
670 case QVideoFrameFormat::ColorTransfer_STD_B67:
680 auto ud =
reinterpret_cast<
UniformData*>(dst->data());
681 memcpy(ud->transformMatrix, transform.constData(),
sizeof(ud->transformMatrix));
682 memcpy(ud->colorMatrix, cmat.constData(),
sizeof(ud->transformMatrix));
683 ud->opacity = opacity;
684 ud->width =
float(format.frameWidth());
685 ud->masteringWhite = fromLinear(
float(format.maxLuminance())/100.f);
686 ud->maxLum = fromLinear(
float(maxNits)/100.f);
687 const TextureDescription* desc = textureDescription(format.pixelFormat());
690 using FallbackPolicy = QVideoTextureHelper::TextureDescription::FallbackPolicy;
691 auto fallbackPolicy = isDmaBuf
692 ? FallbackPolicy::Disable
693 : FallbackPolicy::Enable;
698 const bool useRedComponent =
699 !desc->hasTextureFormat(TextureDescription::Red_8)
700 || isRhiTextureFormatSupported(rhi, QRhiTexture::R8)
701 || rhi->isFeatureSupported(QRhi::RedOrAlpha8IsRed)
703 ud->redOrAlphaIndex = useRedComponent ? 0 : 3;
705 for (
int plane = 0; plane < desc->nplanes; ++plane)
706 ud->planeFormats[plane] = desc->rhiTextureFormat(plane, rhi, fallbackPolicy);
716 QRhiResourceUpdateBatch &rub,
int plane,
717 std::unique_ptr<QRhiTexture> &tex)
719 Q_ASSERT(frame.isMapped());
722 QVideoFrameFormat::PixelFormat pixelFormat = fmt.pixelFormat();
723 QSize size = fmt.frameSize();
725 const TextureDescription &texDesc = descriptions[pixelFormat];
726 QSize planeSize = texDesc.rhiPlaneSize(size, plane, &rhi);
728 bool needsRebuild = !tex || tex->pixelSize() != planeSize || tex->format() != texDesc.rhiTextureFormat(plane, &rhi);
730 tex.reset(rhi.newTexture(texDesc.rhiTextureFormat(plane, &rhi), planeSize, 1, {}));
732 qWarning(
"Failed to create new texture (size %dx%d)", planeSize.width(), planeSize.height());
738 tex->setFormat(texDesc.rhiTextureFormat(plane, &rhi));
739 tex->setPixelSize(planeSize);
740 if (!tex->create()) {
741 qWarning(
"Failed to create texture (size %dx%d)", planeSize.width(), planeSize.height());
750 if (pixelFormat == QVideoFrameFormat::Format_Jpeg) {
751 Q_ASSERT(plane == 0);
757 const QVideoFrameFormat surfaceFormat = frame.surfaceFormat();
759 const bool hasSurfaceTransform = surfaceFormat.isMirrored()
760 || surfaceFormat.scanLineDirection() == QVideoFrameFormat::BottomToTop
761 || surfaceFormat.rotation() != QtVideo::Rotation::None;
763 if (hasSurfaceTransform)
764 image = qImageFromVideoFrame(frame, VideoTransformation{});
766 image = frame.toImage();
768 image.convertTo(QImage::Format_ARGB32);
769 subresDesc.setImage(image);
773 subresDesc.setData(QByteArray::fromRawData(
774 reinterpret_cast<
const char *>(frame.bits(plane)), frame.mappedBytes(plane)));
775 subresDesc.setDataStride(frame.bytesPerLine(plane));
781 rub.uploadTexture(tex.get(), desc);
788 QVideoFrameFormat::PixelFormat pixelFormat, QSize size,
int plane)
790 const TextureDescription &texDesc = descriptions[pixelFormat];
791 QSize planeSize = texDesc.rhiPlaneSize(size, plane, &rhi);
793 QRhiTexture::Flags textureFlags = {};
794 if (pixelFormat == QVideoFrameFormat::Format_SamplerExternalOES) {
796 if (rhi.backend() == QRhi::OpenGLES2)
797 textureFlags |= QRhiTexture::ExternalOES;
800 if (pixelFormat == QVideoFrameFormat::Format_SamplerRect) {
802 if (rhi.backend() == QRhi::OpenGLES2)
803 textureFlags |= QRhiTexture::TextureRectangleGL;
807 if (quint64 handle = texturesSet.textureHandle(rhi, plane); handle) {
808 std::unique_ptr<QRhiTexture> tex(rhi.newTexture(texDesc.rhiTextureFormat(plane, &rhi), planeSize, 1, textureFlags));
809 if (tex->createFrom({handle, 0}))
812 qWarning(
"Failed to initialize QRhiTexture wrapper for native texture object %llu",handle);
856 QRhiResourceUpdateBatch &rub,
857 QVideoFrameTexturesUPtr &oldTextures)
859 qCDebug(qLcVideoTextureHelper) <<
"createTexturesFromMemory, pixelFormat:" << frame.pixelFormat();
860 if (!frame.map(QVideoFrame::ReadOnly)) {
861 qWarning() <<
"Cannot map a video frame in ReadOnly mode!";
865 auto unmapFrameGuard = qScopeGuard([&frame] { frame.unmap(); });
867 const TextureDescription &texDesc = descriptions[frame.surfaceFormat().pixelFormat()];
871 std::unique_ptr<QVideoFrameTexturesFromMemory> textures(canReuseTextures ?
875 RhiTextureArray& textureArray = textures->textureArray();
876 bool shouldKeepMapping =
false;
877 for (quint8 plane = 0; plane < texDesc.nplanes; ++plane) {
878 const auto result = updateTextureWithMap(frame, rhi, rub, plane, textureArray[plane]);
883 shouldKeepMapping =
true;
887 textures->setMappedFrame(shouldKeepMapping ?
std::move(frame) : QVideoFrame());
892QVideoFrameTexturesUPtr createTextures(
const QVideoFrame &frame, QRhi &rhi,
893 QRhiResourceUpdateBatch &rub,
894 QVideoFrameTexturesUPtr &oldTextures)
896 if (!frame.isValid())
899 auto setSourceFrame = [&frame](QVideoFrameTexturesUPtr result) {
900 result->setSourceFrame(frame);
904 if (QHwVideoBuffer *hwBuffer = QVideoFramePrivate::hwBuffer(frame)) {
905 if (
auto textures = hwBuffer->mapTextures(rhi, oldTextures))
906 return setSourceFrame(
std::move(textures));
909 if (
auto textures = createTexturesArray<QVideoFrameTexturesFromRhiTextureArray>(
910 rhi, *hwBuffer, format.pixelFormat(), format.frameSize()))
911 return setSourceFrame(
std::move(textures));
914 if (
auto textures = createTexturesFromMemory(frame, rhi, rub, oldTextures))
915 return setSourceFrame(
std::move(textures));
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
static std::unique_ptr< QRhiTexture > createTextureFromHandle(QVideoFrameTexturesHandles &texturesSet, QRhi &rhi, QVideoFrameFormat::PixelFormat pixelFormat, QSize size, int plane)
static QVideoFrameTexturesUPtr createTexturesFromMemory(QVideoFrame frame, QRhi &rhi, QRhiResourceUpdateBatch &rub, QVideoFrameTexturesUPtr &oldTextures)
static UpdateTextureWithMapResult updateTextureWithMap(const QVideoFrame &frame, QRhi &rhi, QRhiResourceUpdateBatch &rub, int plane, std::unique_ptr< QRhiTexture > &tex)
static QVideoFrameTexturesUPtr createTexturesArray(QRhi &rhi, QVideoFrameTexturesHandles &texturesSet, QVideoFrameFormat::PixelFormat pixelFormat, QSize size, Args &&...args)
Q_MULTIMEDIA_EXPORT void updateUniformData(QByteArray *dst, QRhi *rhi, const QVideoFrameFormat &format, const QVideoFrame &frame, const QMatrix4x4 &transform, float opacity, float maxNits=100)