446bool QVideoFrame::map(QVideoFrame::MapMode mode)
448 if (!d || !d->videoBuffer || d->format.frameSize().isEmpty())
451 QMutexLocker lock(&d->mapMutex);
452 if (mode == QVideoFrame::NotMapped)
455 if (d->mappedCount > 0) {
457 if (d->mapMode == QVideoFrame::ReadOnly && mode == QVideoFrame::ReadOnly) {
465 Q_ASSERT(d->mapData.data[0] ==
nullptr);
466 Q_ASSERT(d->mapData.bytesPerLine[0] == 0);
467 Q_ASSERT(d->mapData.planeCount == 0);
468 Q_ASSERT(d->mapData.dataSize[0] == 0);
470 d->mapData = d->videoBuffer->map(mode);
471 if (d->mapData.planeCount == 0)
476 if (d->mapData.planeCount == 1) {
477 auto pixelFmt = d->format.pixelFormat();
480 case QVideoFrameFormat::Format_Invalid:
481 case QVideoFrameFormat::Format_ARGB8888:
482 case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
483 case QVideoFrameFormat::Format_XRGB8888:
484 case QVideoFrameFormat::Format_BGRA8888:
485 case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
486 case QVideoFrameFormat::Format_BGRX8888:
487 case QVideoFrameFormat::Format_ABGR8888:
488 case QVideoFrameFormat::Format_XBGR8888:
489 case QVideoFrameFormat::Format_RGBA8888:
490 case QVideoFrameFormat::Format_RGBX8888:
491 case QVideoFrameFormat::Format_AYUV:
492 case QVideoFrameFormat::Format_AYUV_Premultiplied:
493 case QVideoFrameFormat::Format_UYVY:
494 case QVideoFrameFormat::Format_YUYV:
495 case QVideoFrameFormat::Format_Y8:
496 case QVideoFrameFormat::Format_Y16:
497 case QVideoFrameFormat::Format_Jpeg:
498 case QVideoFrameFormat::Format_SamplerExternalOES:
499 case QVideoFrameFormat::Format_SamplerRect:
502 case QVideoFrameFormat::Format_YUV420P:
503 case QVideoFrameFormat::Format_YUV420P10:
504 case QVideoFrameFormat::Format_YUV422P:
505 case QVideoFrameFormat::Format_YV12: {
511 const int height =
this->height();
512 const int yStride = d->mapData.bytesPerLine[0];
513 const int uvHeight = pixelFmt == QVideoFrameFormat::Format_YUV422P ? height : height / 2;
514 Q_ASSERT(uvHeight > 0);
515 const int uvSize = d->mapData.dataSize[0] - yStride * height;
516 const int uvStride = uvSize / 2 / uvHeight;
519 d->mapData.planeCount = 3;
520 d->mapData.bytesPerLine[2] = d->mapData.bytesPerLine[1] = uvStride;
521 d->mapData.dataSize[0] = yStride * height;
522 d->mapData.dataSize[2] = d->mapData.dataSize[1] = uvStride * uvHeight;
523 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
524 d->mapData.data[2] = d->mapData.data[1] + d->mapData.dataSize[1];
527 case QVideoFrameFormat::Format_NV12:
528 case QVideoFrameFormat::Format_NV21:
529 case QVideoFrameFormat::Format_IMC2:
530 case QVideoFrameFormat::Format_IMC4:
531 case QVideoFrameFormat::Format_P010:
532 case QVideoFrameFormat::Format_P016: {
534 d->mapData.planeCount = 2;
535 d->mapData.bytesPerLine[1] = d->mapData.bytesPerLine[0];
536 int size = d->mapData.dataSize[0];
537 d->mapData.dataSize[0] = (d->mapData.bytesPerLine[0] * height());
538 d->mapData.dataSize[1] = size - d->mapData.dataSize[0];
539 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
542 case QVideoFrameFormat::Format_IMC1:
543 case QVideoFrameFormat::Format_IMC3: {
546 d->mapData.planeCount = 3;
547 d->mapData.bytesPerLine[2] = d->mapData.bytesPerLine[1] = d->mapData.bytesPerLine[0];
548 d->mapData.dataSize[0] = (d->mapData.bytesPerLine[0] * height());
549 d->mapData.dataSize[1] = (d->mapData.bytesPerLine[0] * height() / 2);
550 d->mapData.dataSize[2] = (d->mapData.bytesPerLine[0] * height() / 2);
551 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
552 d->mapData.data[2] = d->mapData.data[1] + d->mapData.dataSize[1];
563 if ((mode & QVideoFrame::WriteOnly) != 0) {
564 QMutexLocker lock(&d->imageMutex);
894void QVideoFrame::paint(QPainter *painter,
const QRectF &rect,
const PaintOptions &options)
897 painter->fillRect(rect, options.backgroundColor);
901 QRectF targetRect = rect;
902 QSizeF size = qRotatedFramePresentationSize(*
this);
904 size.scale(targetRect.size(), options.aspectRatioMode);
906 if (options.aspectRatioMode == Qt::KeepAspectRatio) {
907 targetRect = QRect(0, 0, size.width(), size.height());
908 targetRect.moveCenter(rect.center());
910 if (options.backgroundColor != Qt::transparent && rect != targetRect) {
911 if (targetRect.top() > rect.top()) {
912 QRectF top(rect.left(), rect.top(), rect.width(), targetRect.top() - rect.top());
913 painter->fillRect(top, Qt::black);
915 if (targetRect.left() > rect.left()) {
916 QRectF top(rect.left(), targetRect.top(), targetRect.left() - rect.left(), targetRect.height());
917 painter->fillRect(top, Qt::black);
919 if (targetRect.right() < rect.right()) {
920 QRectF top(targetRect.right(), targetRect.top(), rect.right() - targetRect.right(), targetRect.height());
921 painter->fillRect(top, Qt::black);
923 if (targetRect.bottom() < rect.bottom()) {
924 QRectF top(rect.left(), targetRect.bottom(), rect.width(), rect.bottom() - targetRect.bottom());
925 painter->fillRect(top, Qt::black);
930 if (map(QVideoFrame::ReadOnly)) {
931 const QTransform oldTransform = painter->transform();
932 QTransform transform = oldTransform;
933 transform.translate(targetRect.center().x() - size.width()/2,
934 targetRect.center().y() - size.height()/2);
935 painter->setTransform(transform);
937 const bool hasPresentationTransformation =
938 d->presentationTransformation != VideoTransformation{};
941 const QImage image = hasPresentationTransformation
942 ? qImageFromVideoFrame(*
this, qNormalizedFrameTransformation(*
this))
945 painter->drawImage({{}, size}, image, {{},image.size()});
946 painter->setTransform(oldTransform);
949 }
else if (isValid()) {
952 painter->fillRect(rect, Qt::black);
955 if ((options.paintFlags & PaintOptions::DontDrawSubtitles) || d->subtitleText.isEmpty())
959 auto text = d->subtitleText;
960 text.replace(QLatin1Char(
'\n'), QChar::LineSeparator);
962 QVideoTextureHelper::SubtitleLayout layout;
963 layout.update(targetRect.size().toSize(),
this->subtitleText());
964 layout.draw(painter, targetRect.topLeft());
972 return QLatin1String(
"[no timestamp]");
974 bool onlyOne = (start == end);
977 const int s_millis = start % 1000000;
979 const int s_seconds = start % 60;
981 const int s_minutes = start % 60;
986 return QStringLiteral(
"@%1:%2:%3.%4")
987 .arg(start, 1, 10, QLatin1Char(
'0'))
988 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
989 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
990 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
991 return QStringLiteral(
"@%1:%2.%3")
992 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
993 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
994 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
1000 return QStringLiteral(
"%1:%2:%3.%4 - forever")
1001 .arg(start, 1, 10, QLatin1Char(
'0'))
1002 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1003 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1004 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
1005 return QStringLiteral(
"%1:%2.%3 - forever")
1006 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1007 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1008 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
1011 const int e_millis = end % 1000000;
1013 const int e_seconds = end % 60;
1015 const int e_minutes = end % 60;
1018 if (start > 0 || end > 0)
1019 return QStringLiteral(
"%1:%2:%3.%4 - %5:%6:%7.%8")
1020 .arg(start, 1, 10, QLatin1Char(
'0'))
1021 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1022 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1023 .arg(s_millis, 2, 10, QLatin1Char(
'0'))
1024 .arg(end, 1, 10, QLatin1Char(
'0'))
1025 .arg(e_minutes, 2, 10, QLatin1Char(
'0'))
1026 .arg(e_seconds, 2, 10, QLatin1Char(
'0'))
1027 .arg(e_millis, 2, 10, QLatin1Char(
'0'));
1028 return QStringLiteral(
"%1:%2.%3 - %4:%5.%6")
1029 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1030 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1031 .arg(s_millis, 2, 10, QLatin1Char(
'0'))
1032 .arg(e_minutes, 2, 10, QLatin1Char(
'0'))
1033 .arg(e_seconds, 2, 10, QLatin1Char(
'0'))
1034 .arg(e_millis, 2, 10, QLatin1Char(
'0'));