467bool QVideoFrame::map(QVideoFrame::MapMode mode)
469 if (!d || !d->videoBuffer || d->format.frameSize().isEmpty())
472 QMutexLocker lock(&d->mapMutex);
473 if (mode == QVideoFrame::NotMapped)
476 if (d->mappedCount > 0) {
478 if (d->mapMode == QVideoFrame::ReadOnly && mode == QVideoFrame::ReadOnly) {
486 Q_ASSERT(d->mapData.data[0] ==
nullptr);
487 Q_ASSERT(d->mapData.bytesPerLine[0] == 0);
488 Q_ASSERT(d->mapData.planeCount == 0);
489 Q_ASSERT(d->mapData.dataSize[0] == 0);
491 d->mapData = d->videoBuffer->map(mode);
492 if (d->mapData.planeCount == 0)
497 if (d->mapData.planeCount == 1) {
498 auto pixelFmt = d->format.pixelFormat();
501 case QVideoFrameFormat::Format_Invalid:
502 case QVideoFrameFormat::Format_ARGB8888:
503 case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
504 case QVideoFrameFormat::Format_XRGB8888:
505 case QVideoFrameFormat::Format_BGRA8888:
506 case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
507 case QVideoFrameFormat::Format_BGRX8888:
508 case QVideoFrameFormat::Format_ABGR8888:
509 case QVideoFrameFormat::Format_XBGR8888:
510 case QVideoFrameFormat::Format_RGBA8888:
511 case QVideoFrameFormat::Format_RGBX8888:
512 case QVideoFrameFormat::Format_AYUV:
513 case QVideoFrameFormat::Format_AYUV_Premultiplied:
514 case QVideoFrameFormat::Format_UYVY:
515 case QVideoFrameFormat::Format_YUYV:
516 case QVideoFrameFormat::Format_Y8:
517 case QVideoFrameFormat::Format_Y16:
518 case QVideoFrameFormat::Format_Jpeg:
519 case QVideoFrameFormat::Format_SamplerExternalOES:
520 case QVideoFrameFormat::Format_SamplerRect:
523 case QVideoFrameFormat::Format_YUV420P:
524 case QVideoFrameFormat::Format_YUV420P10:
525 case QVideoFrameFormat::Format_YUV422P:
526 case QVideoFrameFormat::Format_YV12: {
532 const int height =
this->height();
533 const int yStride = d->mapData.bytesPerLine[0];
534 const int uvHeight = pixelFmt == QVideoFrameFormat::Format_YUV422P ? height : height / 2;
535 Q_ASSERT(uvHeight > 0);
536 const int uvSize = d->mapData.dataSize[0] - yStride * height;
537 const int uvStride = uvSize / 2 / uvHeight;
540 d->mapData.planeCount = 3;
541 d->mapData.bytesPerLine[2] = d->mapData.bytesPerLine[1] = uvStride;
542 d->mapData.dataSize[0] = yStride * height;
543 d->mapData.dataSize[2] = d->mapData.dataSize[1] = uvStride * uvHeight;
544 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
545 d->mapData.data[2] = d->mapData.data[1] + d->mapData.dataSize[1];
548 case QVideoFrameFormat::Format_NV12:
549 case QVideoFrameFormat::Format_NV21:
550 case QVideoFrameFormat::Format_IMC2:
551 case QVideoFrameFormat::Format_IMC4:
552 case QVideoFrameFormat::Format_P010:
553 case QVideoFrameFormat::Format_P016: {
555 d->mapData.planeCount = 2;
556 d->mapData.bytesPerLine[1] = d->mapData.bytesPerLine[0];
557 int size = d->mapData.dataSize[0];
558 d->mapData.dataSize[0] = (d->mapData.bytesPerLine[0] * height());
559 d->mapData.dataSize[1] = size - d->mapData.dataSize[0];
560 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
563 case QVideoFrameFormat::Format_IMC1:
564 case QVideoFrameFormat::Format_IMC3: {
567 d->mapData.planeCount = 3;
568 d->mapData.bytesPerLine[2] = d->mapData.bytesPerLine[1] = d->mapData.bytesPerLine[0];
569 d->mapData.dataSize[0] = (d->mapData.bytesPerLine[0] * height());
570 d->mapData.dataSize[1] = (d->mapData.bytesPerLine[0] * height() / 2);
571 d->mapData.dataSize[2] = (d->mapData.bytesPerLine[0] * height() / 2);
572 d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
573 d->mapData.data[2] = d->mapData.data[1] + d->mapData.dataSize[1];
584 if ((mode & QVideoFrame::WriteOnly) != 0) {
585 QMutexLocker lock(&d->imageMutex);
915void QVideoFrame::paint(QPainter *painter,
const QRectF &rect,
const PaintOptions &options)
918 painter->fillRect(rect, options.backgroundColor);
922 QRectF targetRect = rect;
923 QSizeF size = qRotatedFramePresentationSize(*
this);
925 size.scale(targetRect.size(), options.aspectRatioMode);
927 if (options.aspectRatioMode == Qt::KeepAspectRatio) {
928 targetRect = QRect(0, 0, size.width(), size.height());
929 targetRect.moveCenter(rect.center());
931 if (options.backgroundColor != Qt::transparent && rect != targetRect) {
932 if (targetRect.top() > rect.top()) {
933 QRectF top(rect.left(), rect.top(), rect.width(), targetRect.top() - rect.top());
934 painter->fillRect(top, Qt::black);
936 if (targetRect.left() > rect.left()) {
937 QRectF top(rect.left(), targetRect.top(), targetRect.left() - rect.left(), targetRect.height());
938 painter->fillRect(top, Qt::black);
940 if (targetRect.right() < rect.right()) {
941 QRectF top(targetRect.right(), targetRect.top(), rect.right() - targetRect.right(), targetRect.height());
942 painter->fillRect(top, Qt::black);
944 if (targetRect.bottom() < rect.bottom()) {
945 QRectF top(rect.left(), targetRect.bottom(), rect.width(), rect.bottom() - targetRect.bottom());
946 painter->fillRect(top, Qt::black);
951 if (map(QVideoFrame::ReadOnly)) {
952 const QTransform oldTransform = painter->transform();
953 QTransform transform = oldTransform;
954 transform.translate(targetRect.center().x() - size.width()/2,
955 targetRect.center().y() - size.height()/2);
956 painter->setTransform(transform);
958 const bool hasPresentationTransformation =
959 d->presentationTransformation != VideoTransformation{};
962 const QImage image = hasPresentationTransformation
963 ? qImageFromVideoFrame(*
this, qNormalizedFrameTransformation(*
this))
966 painter->drawImage({{}, size}, image, {{},image.size()});
967 painter->setTransform(oldTransform);
970 }
else if (isValid()) {
973 painter->fillRect(rect, Qt::black);
976 if ((options.paintFlags & PaintOptions::DontDrawSubtitles) || d->subtitleText.isEmpty())
980 QVideoTextureHelper::SubtitleLayout layout;
981 layout.update(targetRect.size().toSize(),
this->subtitleText());
982 layout.draw(painter, targetRect.topLeft());
990 return QLatin1String(
"[no timestamp]");
992 bool onlyOne = (start == end);
995 const int s_millis = start % 1000000;
997 const int s_seconds = start % 60;
999 const int s_minutes = start % 60;
1004 return QStringLiteral(
"@%1:%2:%3.%4")
1005 .arg(start, 1, 10, QLatin1Char(
'0'))
1006 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1007 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1008 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
1009 return QStringLiteral(
"@%1:%2.%3")
1010 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1011 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1012 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
1018 return QStringLiteral(
"%1:%2:%3.%4 - forever")
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 return QStringLiteral(
"%1:%2.%3 - forever")
1024 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1025 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1026 .arg(s_millis, 2, 10, QLatin1Char(
'0'));
1029 const int e_millis = end % 1000000;
1031 const int e_seconds = end % 60;
1033 const int e_minutes = end % 60;
1036 if (start > 0 || end > 0)
1037 return QStringLiteral(
"%1:%2:%3.%4 - %5:%6:%7.%8")
1038 .arg(start, 1, 10, QLatin1Char(
'0'))
1039 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1040 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1041 .arg(s_millis, 2, 10, QLatin1Char(
'0'))
1042 .arg(end, 1, 10, QLatin1Char(
'0'))
1043 .arg(e_minutes, 2, 10, QLatin1Char(
'0'))
1044 .arg(e_seconds, 2, 10, QLatin1Char(
'0'))
1045 .arg(e_millis, 2, 10, QLatin1Char(
'0'));
1046 return QStringLiteral(
"%1:%2.%3 - %4:%5.%6")
1047 .arg(s_minutes, 2, 10, QLatin1Char(
'0'))
1048 .arg(s_seconds, 2, 10, QLatin1Char(
'0'))
1049 .arg(s_millis, 2, 10, QLatin1Char(
'0'))
1050 .arg(e_minutes, 2, 10, QLatin1Char(
'0'))
1051 .arg(e_seconds, 2, 10, QLatin1Char(
'0'))
1052 .arg(e_millis, 2, 10, QLatin1Char(
'0'));