446bool QVideoFrame::map(QVideoFrame::MapMode mode)
448 if (!d || !d->videoBuffer)
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 const int uvStride = (d->mapData.dataSize[0] - (yStride * height)) / uvHeight / 2;
517 d->mapData.planeCount = 3;
518 d->mapData.bytesPerLine[2] = d->mapData.bytesPerLine[1] = uvStride;
519 d->mapData.dataSize[0] = yStride * height;
520 d->mapData.dataSize[1] = uvStride * uvHeight;
521 d->mapData.dataSize[2] = uvStride * uvHeight;
522 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
523 d->mapData.data[2] = d->mapData.data[1] + d->mapData.dataSize[1];
526 case QVideoFrameFormat::Format_NV12:
527 case QVideoFrameFormat::Format_NV21:
528 case QVideoFrameFormat::Format_IMC2:
529 case QVideoFrameFormat::Format_IMC4:
530 case QVideoFrameFormat::Format_P010:
531 case QVideoFrameFormat::Format_P016: {
533 d->mapData.planeCount = 2;
534 d->mapData.bytesPerLine[1] = d->mapData.bytesPerLine[0];
535 int size = d->mapData.dataSize[0];
536 d->mapData.dataSize[0] = (d->mapData.bytesPerLine[0] * height());
537 d->mapData.dataSize[1] = size - d->mapData.dataSize[0];
538 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
541 case QVideoFrameFormat::Format_IMC1:
542 case QVideoFrameFormat::Format_IMC3: {
545 d->mapData.planeCount = 3;
546 d->mapData.bytesPerLine[2] = d->mapData.bytesPerLine[1] = d->mapData.bytesPerLine[0];
547 d->mapData.dataSize[0] = (d->mapData.bytesPerLine[0] * height());
548 d->mapData.dataSize[1] = (d->mapData.bytesPerLine[0] * height() / 2);
549 d->mapData.dataSize[2] = (d->mapData.bytesPerLine[0] * height() / 2);
550 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
551 d->mapData.data[2] = d->mapData.data[1] + d->mapData.dataSize[1];
562 if ((mode & QVideoFrame::WriteOnly) != 0) {
563 QMutexLocker lock(&d->imageMutex);
893void QVideoFrame::paint(QPainter *painter,
const QRectF &rect,
const PaintOptions &options)
896 painter->fillRect(rect, options.backgroundColor);
900 QRectF targetRect = rect;
901 QSizeF size = qRotatedFramePresentationSize(*
this);
903 size.scale(targetRect.size(), options.aspectRatioMode);
905 if (options.aspectRatioMode == Qt::KeepAspectRatio) {
906 targetRect = QRect(0, 0, size.width(), size.height());
907 targetRect.moveCenter(rect.center());
909 if (options.backgroundColor != Qt::transparent && rect != targetRect) {
910 if (targetRect.top() > rect.top()) {
911 QRectF top(rect.left(), rect.top(), rect.width(), targetRect.top() - rect.top());
912 painter->fillRect(top, Qt::black);
914 if (targetRect.left() > rect.left()) {
915 QRectF top(rect.left(), targetRect.top(), targetRect.left() - rect.left(), targetRect.height());
916 painter->fillRect(top, Qt::black);
918 if (targetRect.right() < rect.right()) {
919 QRectF top(targetRect.right(), targetRect.top(), rect.right() - targetRect.right(), targetRect.height());
920 painter->fillRect(top, Qt::black);
922 if (targetRect.bottom() < rect.bottom()) {
923 QRectF top(rect.left(), targetRect.bottom(), rect.width(), rect.bottom() - targetRect.bottom());
924 painter->fillRect(top, Qt::black);
929 if (map(QVideoFrame::ReadOnly)) {
930 const QTransform oldTransform = painter->transform();
931 QTransform transform = oldTransform;
932 transform.translate(targetRect.center().x() - size.width()/2,
933 targetRect.center().y() - size.height()/2);
934 painter->setTransform(transform);
936 const bool hasPresentationTransformation =
937 d->presentationTransformation != VideoTransformation{};
940 const QImage image = hasPresentationTransformation
941 ? qImageFromVideoFrame(*
this, qNormalizedFrameTransformation(*
this))
944 painter->drawImage({{}, size}, image, {{},image.size()});
945 painter->setTransform(oldTransform);
948 }
else if (isValid()) {
951 painter->fillRect(rect, Qt::black);
954 if ((options.paintFlags & PaintOptions::DontDrawSubtitles) || d->subtitleText.isEmpty())
958 auto text = d->subtitleText;
959 text.replace(QLatin1Char(
'\n'), QChar::LineSeparator);
961 QVideoTextureHelper::SubtitleLayout layout;
962 layout.update(targetRect.size().toSize(),
this->subtitleText());
963 layout.draw(painter, targetRect.topLeft());
971 return QLatin1String(
"[no timestamp]");
973 bool onlyOne = (start == end);
976 const int s_millis = start % 1000000;
978 const int s_seconds = start % 60;
980 const int s_minutes = start % 60;
985 return QStringLiteral(
"@%1:%2:%3.%4")
986 .arg(start, 1, 10, QLatin1Char(
'0'))
987 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
988 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
989 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
990 return QStringLiteral(
"@%1:%2.%3")
991 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
992 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
993 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
999 return QStringLiteral(
"%1:%2:%3.%4 - forever")
1000 .arg(start, 1, 10, QLatin1Char(
'0'))
1001 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1002 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1003 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
1004 return QStringLiteral(
"%1:%2.%3 - forever")
1005 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1006 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1007 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
1010 const int e_millis = end % 1000000;
1012 const int e_seconds = end % 60;
1014 const int e_minutes = end % 60;
1017 if (start > 0 || end > 0)
1018 return QStringLiteral(
"%1:%2:%3.%4 - %5:%6:%7.%8")
1019 .arg(start, 1, 10, QLatin1Char(
'0'))
1020 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1021 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1022 .arg(s_millis, 2, 10, QLatin1Char(
'0'))
1023 .arg(end, 1, 10, QLatin1Char(
'0'))
1024 .arg(e_minutes, 2, 10, QLatin1Char(
'0'))
1025 .arg(e_seconds, 2, 10, QLatin1Char(
'0'))
1026 .arg(e_millis, 2, 10, QLatin1Char(
'0'));
1027 return QStringLiteral(
"%1:%2.%3 - %4:%5.%6")
1028 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1029 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1030 .arg(s_millis, 2, 10, QLatin1Char(
'0'))
1031 .arg(e_minutes, 2, 10, QLatin1Char(
'0'))
1032 .arg(e_seconds, 2, 10, QLatin1Char(
'0'))
1033 .arg(e_millis, 2, 10, QLatin1Char(
'0'));