447bool QVideoFrame::map(QVideoFrame::MapMode mode)
449 if (!d || !d->videoBuffer || d->format.frameSize().isEmpty())
452 QMutexLocker lock(&d->mapMutex);
453 if (mode == QVideoFrame::NotMapped)
456 if (d->mappedCount > 0) {
458 if (d->mapMode == QVideoFrame::ReadOnly && mode == QVideoFrame::ReadOnly) {
466 Q_ASSERT(d->mapData.data[0] ==
nullptr);
467 Q_ASSERT(d->mapData.bytesPerLine[0] == 0);
468 Q_ASSERT(d->mapData.planeCount == 0);
469 Q_ASSERT(d->mapData.dataSize[0] == 0);
471 d->mapData = d->videoBuffer->map(mode);
472 if (d->mapData.planeCount == 0)
477 if (d->mapData.planeCount == 1) {
478 auto pixelFmt = d->format.pixelFormat();
481 case QVideoFrameFormat::Format_Invalid:
482 case QVideoFrameFormat::Format_ARGB8888:
483 case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
484 case QVideoFrameFormat::Format_XRGB8888:
485 case QVideoFrameFormat::Format_BGRA8888:
486 case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
487 case QVideoFrameFormat::Format_BGRX8888:
488 case QVideoFrameFormat::Format_ABGR8888:
489 case QVideoFrameFormat::Format_XBGR8888:
490 case QVideoFrameFormat::Format_RGBA8888:
491 case QVideoFrameFormat::Format_RGBX8888:
492 case QVideoFrameFormat::Format_AYUV:
493 case QVideoFrameFormat::Format_AYUV_Premultiplied:
494 case QVideoFrameFormat::Format_UYVY:
495 case QVideoFrameFormat::Format_YUYV:
496 case QVideoFrameFormat::Format_Y8:
497 case QVideoFrameFormat::Format_Y16:
498 case QVideoFrameFormat::Format_Jpeg:
499 case QVideoFrameFormat::Format_SamplerExternalOES:
500 case QVideoFrameFormat::Format_SamplerRect:
503 case QVideoFrameFormat::Format_YUV420P:
504 case QVideoFrameFormat::Format_YUV420P10:
505 case QVideoFrameFormat::Format_YUV422P:
506 case QVideoFrameFormat::Format_YV12: {
512 const int height =
this->height();
513 const int yStride = d->mapData.bytesPerLine[0];
514 const int uvHeight = pixelFmt == QVideoFrameFormat::Format_YUV422P ? height : height / 2;
515 Q_ASSERT(uvHeight > 0);
516 const int uvSize = d->mapData.dataSize[0] - yStride * height;
517 const int uvStride = uvSize / 2 / uvHeight;
520 d->mapData.planeCount = 3;
521 d->mapData.bytesPerLine[2] = d->mapData.bytesPerLine[1] = uvStride;
522 d->mapData.dataSize[0] = yStride * height;
523 d->mapData.dataSize[2] = d->mapData.dataSize[1] = uvStride * uvHeight;
524 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
525 d->mapData.data[2] = d->mapData.data[1] + d->mapData.dataSize[1];
528 case QVideoFrameFormat::Format_NV12:
529 case QVideoFrameFormat::Format_NV21:
530 case QVideoFrameFormat::Format_IMC2:
531 case QVideoFrameFormat::Format_IMC4:
532 case QVideoFrameFormat::Format_P010:
533 case QVideoFrameFormat::Format_P016: {
535 d->mapData.planeCount = 2;
536 d->mapData.bytesPerLine[1] = d->mapData.bytesPerLine[0];
537 int size = d->mapData.dataSize[0];
538 d->mapData.dataSize[0] = (d->mapData.bytesPerLine[0] * height());
539 d->mapData.dataSize[1] = size - d->mapData.dataSize[0];
540 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
543 case QVideoFrameFormat::Format_IMC1:
544 case QVideoFrameFormat::Format_IMC3: {
547 d->mapData.planeCount = 3;
548 d->mapData.bytesPerLine[2] = d->mapData.bytesPerLine[1] = d->mapData.bytesPerLine[0];
549 d->mapData.dataSize[0] = (d->mapData.bytesPerLine[0] * height());
550 d->mapData.dataSize[1] = (d->mapData.bytesPerLine[0] * height() / 2);
551 d->mapData.dataSize[2] = (d->mapData.bytesPerLine[0] * height() / 2);
552 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
553 d->mapData.data[2] = d->mapData.data[1] + d->mapData.dataSize[1];
564 if ((mode & QVideoFrame::WriteOnly) != 0) {
565 QMutexLocker lock(&d->imageMutex);
895void QVideoFrame::paint(QPainter *painter,
const QRectF &rect,
const PaintOptions &options)
898 painter->fillRect(rect, options.backgroundColor);
902 QRectF targetRect = rect;
903 QSizeF size = qRotatedFramePresentationSize(*
this);
905 size.scale(targetRect.size(), options.aspectRatioMode);
907 if (options.aspectRatioMode == Qt::KeepAspectRatio) {
908 targetRect = QRect(0, 0, size.width(), size.height());
909 targetRect.moveCenter(rect.center());
911 if (options.backgroundColor != Qt::transparent && rect != targetRect) {
912 if (targetRect.top() > rect.top()) {
913 QRectF top(rect.left(), rect.top(), rect.width(), targetRect.top() - rect.top());
914 painter->fillRect(top, Qt::black);
916 if (targetRect.left() > rect.left()) {
917 QRectF top(rect.left(), targetRect.top(), targetRect.left() - rect.left(), targetRect.height());
918 painter->fillRect(top, Qt::black);
920 if (targetRect.right() < rect.right()) {
921 QRectF top(targetRect.right(), targetRect.top(), rect.right() - targetRect.right(), targetRect.height());
922 painter->fillRect(top, Qt::black);
924 if (targetRect.bottom() < rect.bottom()) {
925 QRectF top(rect.left(), targetRect.bottom(), rect.width(), rect.bottom() - targetRect.bottom());
926 painter->fillRect(top, Qt::black);
931 if (map(QVideoFrame::ReadOnly)) {
932 const QTransform oldTransform = painter->transform();
933 QTransform transform = oldTransform;
934 transform.translate(targetRect.center().x() - size.width()/2,
935 targetRect.center().y() - size.height()/2);
936 painter->setTransform(transform);
938 const bool hasPresentationTransformation =
939 d->presentationTransformation != VideoTransformation{};
942 const QImage image = hasPresentationTransformation
943 ? qImageFromVideoFrame(*
this, qNormalizedFrameTransformation(*
this))
946 painter->drawImage({{}, size}, image, {{},image.size()});
947 painter->setTransform(oldTransform);
950 }
else if (isValid()) {
953 painter->fillRect(rect, Qt::black);
956 if ((options.paintFlags & PaintOptions::DontDrawSubtitles) || d->subtitleText.isEmpty())
960 auto text = d->subtitleText;
961 text.replace(QLatin1Char(
'\n'), QChar::LineSeparator);
963 QVideoTextureHelper::SubtitleLayout layout;
964 layout.update(targetRect.size().toSize(),
this->subtitleText());
965 layout.draw(painter, targetRect.topLeft());
973 return QLatin1String(
"[no timestamp]");
975 bool onlyOne = (start == end);
978 const int s_millis = start % 1000000;
980 const int s_seconds = start % 60;
982 const int s_minutes = start % 60;
987 return QStringLiteral(
"@%1:%2:%3.%4")
988 .arg(start, 1, 10, QLatin1Char(
'0'))
989 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
990 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
991 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
992 return QStringLiteral(
"@%1:%2.%3")
993 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
994 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
995 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
1001 return QStringLiteral(
"%1:%2:%3.%4 - forever")
1002 .arg(start, 1, 10, QLatin1Char(
'0'))
1003 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1004 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1005 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
1006 return QStringLiteral(
"%1:%2.%3 - forever")
1007 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1008 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1009 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
1012 const int e_millis = end % 1000000;
1014 const int e_seconds = end % 60;
1016 const int e_minutes = end % 60;
1019 if (start > 0 || end > 0)
1020 return QStringLiteral(
"%1:%2:%3.%4 - %5:%6:%7.%8")
1021 .arg(start, 1, 10, QLatin1Char(
'0'))
1022 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1023 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1024 .arg(s_millis, 2, 10, QLatin1Char(
'0'))
1025 .arg(end, 1, 10, QLatin1Char(
'0'))
1026 .arg(e_minutes, 2, 10, QLatin1Char(
'0'))
1027 .arg(e_seconds, 2, 10, QLatin1Char(
'0'))
1028 .arg(e_millis, 2, 10, QLatin1Char(
'0'));
1029 return QStringLiteral(
"%1:%2.%3 - %4:%5.%6")
1030 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1031 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1032 .arg(s_millis, 2, 10, QLatin1Char(
'0'))
1033 .arg(e_minutes, 2, 10, QLatin1Char(
'0'))
1034 .arg(e_seconds, 2, 10, QLatin1Char(
'0'))
1035 .arg(e_millis, 2, 10, QLatin1Char(
'0'));