diff options
author | Lars Knoll <lars.knoll@qt.io> | 2021-03-17 14:44:11 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2021-04-06 08:06:31 +0000 |
commit | 76aa4e1dd1921441fd34a3907a90e633a2f74911 (patch) | |
tree | 654616d8b20172f16970d8c2634db2659ab43554 /src/multimedia/video | |
parent | 591395e7dc0bd5afc273d843101862168ede81c9 (diff) |
Various improvements to QVideoFrame->QImage conversion
* Implement support for missing pixel formats, we are now able to convert
all supported pixel formats to a QImage.
* Ensure we always convert to a RGB32 or ARGB32_Premultiplied image
* Add missing mappings to gstreamer formats
Change-Id: I8816e0a42ced73c96dfff03f131d7a749b55ae36
Reviewed-by: Doris Verria <doris.verria@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/multimedia/video')
-rw-r--r-- | src/multimedia/video/qvideoframe.cpp | 160 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframe.h | 1 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframeconversionhelper.cpp | 318 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframeconversionhelper_p.h | 18 |
4 files changed, 384 insertions, 113 deletions
diff --git a/src/multimedia/video/qvideoframe.cpp b/src/multimedia/video/qvideoframe.cpp index f1c4dc453..3545c1cc3 100644 --- a/src/multimedia/video/qvideoframe.cpp +++ b/src/multimedia/video/qvideoframe.cpp @@ -52,6 +52,51 @@ #include <QDebug> QT_BEGIN_NAMESPACE +static bool pixelFormatHasAlpha[QVideoFrame::NPixelFormats] = +{ + false, //Format_Invalid, + true, //Format_ARGB32, + true, //Format_ARGB32_Premultiplied, + false, //Format_RGB32, + false, //Format_RGB24, + false, //Format_RGB565, + false, //Format_RGB555, + true, //Format_ARGB8565_Premultiplied, + true, //Format_BGRA32, + true, //Format_BGRA32_Premultiplied, + true, //Format_ABGR32, + false, //Format_BGR32, + false, //Format_BGR24, + false, //Format_BGR565, + false, //Format_BGR555, + true, //Format_BGRA5658_Premultiplied, + + true, //Format_AYUV444, + true, //Format_AYUV444_Premultiplied, + false, //Format_YUV444, + false, //Format_YUV420P, + false, //Format_YUV422P, + false, //Format_YV12, + false, //Format_UYVY, + false, //Format_YUYV, + false, //Format_NV12, + false, //Format_NV21, + false, //Format_IMC1, + false, //Format_IMC2, + false, //Format_IMC3, + false, //Format_IMC4, + false, //Format_Y8, + false, //Format_Y16, + + false, //Format_P010LE, + false, //Format_P010BE, + false, //Format_P016LE, + false, //Format_P016BE, + + false, //Format_Jpeg, + +}; + class QVideoFramePrivate : public QSharedData { @@ -884,6 +929,10 @@ QVideoFrame::PixelFormat QVideoFrame::pixelFormatFromImageFormat(QImage::Format return Format_RGB555; case QImage::Format_RGB888: return Format_RGB24; + case QImage::Format_Grayscale8: + return Format_Y8; + case QImage::Format_Grayscale16: + return Format_Y16; default: return Format_Invalid; } @@ -899,8 +948,6 @@ QVideoFrame::PixelFormat QVideoFrame::pixelFormatFromImageFormat(QImage::Format QImage::Format QVideoFrame::imageFormatFromPixelFormat(PixelFormat format) { switch (format) { - case Format_Invalid: - return QImage::Format_Invalid; case Format_ARGB32: return QImage::Format_ARGB32; case Format_ARGB32_Premultiplied: @@ -915,11 +962,15 @@ QImage::Format QVideoFrame::imageFormatFromPixelFormat(PixelFormat format) return QImage::Format_RGB555; case Format_ARGB8565_Premultiplied: return QImage::Format_ARGB8565_Premultiplied; + case Format_Y8: + return QImage::Format_Grayscale8; + case Format_Y16: + return QImage::Format_Grayscale16; + case Format_ABGR32: case Format_BGRA32: case Format_BGRA32_Premultiplied: case Format_BGR32: case Format_BGR24: - return QImage::Format_Invalid; case Format_BGR565: case Format_BGR555: case Format_BGRA5658_Premultiplied: @@ -937,100 +988,18 @@ QImage::Format QVideoFrame::imageFormatFromPixelFormat(PixelFormat format) case Format_IMC2: case Format_IMC3: case Format_IMC4: - case Format_Y8: - case Format_Y16: + case Format_P010LE: + case Format_P010BE: + case Format_P016LE: + case Format_P016BE: case Format_Jpeg: - return QImage::Format_Invalid; - default: + case Format_Invalid: return QImage::Format_Invalid; } return QImage::Format_Invalid; } -extern void QT_FASTCALL qt_convert_BGRA32_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_BGR24_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_BGR565_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_BGR555_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_AYUV444_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_YUV444_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame&, uchar*); -extern void QT_FASTCALL qt_convert_P016LE_to_ARGB32(const QVideoFrame &, uchar*); -extern void QT_FASTCALL qt_convert_P016BE_to_ARGB32(const QVideoFrame &, uchar*); - -static VideoFrameConvertFunc qConvertFuncs[QVideoFrame::NPixelFormats] = { - /* Format_Invalid */ nullptr, // Not needed - /* Format_ARGB32 */ nullptr, // Not needed - /* Format_ARGB32_Premultiplied */ nullptr, // Not needed - /* Format_RGB32 */ nullptr, // Not needed - /* Format_RGB24 */ nullptr, // Not needed - /* Format_RGB565 */ nullptr, // Not needed - /* Format_RGB555 */ nullptr, // Not needed - /* Format_ARGB8565_Premultiplied */ nullptr, // Not needed - /* Format_BGRA32 */ qt_convert_BGRA32_to_ARGB32, - /* Format_BGRA32_Premultiplied */ qt_convert_BGRA32_to_ARGB32, - /* Format_ABGR32 */ nullptr, - /* Format_BGR32 */ qt_convert_BGRA32_to_ARGB32, - /* Format_BGR24 */ qt_convert_BGR24_to_ARGB32, - /* Format_BGR565 */ qt_convert_BGR565_to_ARGB32, - /* Format_BGR555 */ qt_convert_BGR555_to_ARGB32, - /* Format_BGRA5658_Premultiplied */ nullptr, - /* Format_AYUV444 */ qt_convert_AYUV444_to_ARGB32, - /* Format_AYUV444_Premultiplied */ nullptr, - /* Format_YUV444 */ qt_convert_YUV444_to_ARGB32, - /* Format_YUV420P */ qt_convert_YUV420P_to_ARGB32, - /* Format_YUV422P */ nullptr, - /* Format_YV12 */ qt_convert_YV12_to_ARGB32, - /* Format_UYVY */ qt_convert_UYVY_to_ARGB32, - /* Format_YUYV */ qt_convert_YUYV_to_ARGB32, - /* Format_NV12 */ qt_convert_NV12_to_ARGB32, - /* Format_NV21 */ qt_convert_NV21_to_ARGB32, - /* Format_IMC1 */ nullptr, - /* Format_IMC2 */ nullptr, - /* Format_IMC3 */ nullptr, - /* Format_IMC4 */ nullptr, - /* Format_Y8 */ nullptr, - /* Format_Y16 */ nullptr, - /* Format_P010LE */ qt_convert_P016LE_to_ARGB32, - /* Format_P010BE */ qt_convert_P016BE_to_ARGB32, - /* Format_P016LE */ qt_convert_P016LE_to_ARGB32, - /* Format_P016BE */ qt_convert_P016BE_to_ARGB32, - /* Format_Jpeg */ nullptr, // Not needed -}; - -static void qInitConvertFuncsAsm() -{ -#ifdef QT_COMPILER_SUPPORTS_SSE2 - extern void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_sse2(const QVideoFrame&, uchar*); - if (qCpuHasFeature(SSE2)){ - qConvertFuncs[QVideoFrame::Format_BGRA32] = qt_convert_BGRA32_to_ARGB32_sse2; - qConvertFuncs[QVideoFrame::Format_BGRA32_Premultiplied] = qt_convert_BGRA32_to_ARGB32_sse2; - qConvertFuncs[QVideoFrame::Format_BGR32] = qt_convert_BGRA32_to_ARGB32_sse2; - } -#endif -#ifdef QT_COMPILER_SUPPORTS_SSSE3 - extern void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_ssse3(const QVideoFrame&, uchar*); - if (qCpuHasFeature(SSSE3)){ - qConvertFuncs[QVideoFrame::Format_BGRA32] = qt_convert_BGRA32_to_ARGB32_ssse3; - qConvertFuncs[QVideoFrame::Format_BGRA32_Premultiplied] = qt_convert_BGRA32_to_ARGB32_ssse3; - qConvertFuncs[QVideoFrame::Format_BGR32] = qt_convert_BGRA32_to_ARGB32_ssse3; - } -#endif -#ifdef QT_COMPILER_SUPPORTS_AVX2 - extern void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_avx2(const QVideoFrame&, uchar*); - if (qCpuHasFeature(AVX2)){ - qConvertFuncs[QVideoFrame::Format_BGRA32] = qt_convert_BGRA32_to_ARGB32_avx2; - qConvertFuncs[QVideoFrame::Format_BGRA32_Premultiplied] = qt_convert_BGRA32_to_ARGB32_avx2; - qConvertFuncs[QVideoFrame::Format_BGR32] = qt_convert_BGRA32_to_ARGB32_avx2; - } -#endif -} - /*! Based on the pixel format converts current video frame to image. \since 5.15 @@ -1043,7 +1012,6 @@ QImage QVideoFrame::image() const if (!frame.isValid() || !frame.map(QVideoFrame::ReadOnly)) return result; - qDebug() << "converting video frame:" << frame.pixelFormat(); // Formats supported by QImage don't need conversion QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()); if (imageFormat != QImage::Format_Invalid) { @@ -1057,16 +1025,12 @@ QImage QVideoFrame::image() const // Need conversion else { - static bool initAsmFuncsDone = false; - if (!initAsmFuncsDone) { - qInitConvertFuncsAsm(); - initAsmFuncsDone = true; - } - VideoFrameConvertFunc convert = qConvertFuncs[frame.pixelFormat()]; + VideoFrameConvertFunc convert = qConverterForFormat(frame.pixelFormat()); if (!convert) { qWarning() << Q_FUNC_INFO << ": unsupported pixel format" << frame.pixelFormat(); } else { - result = QImage(frame.width(), frame.height(), QImage::Format_ARGB32_Premultiplied); + auto format = pixelFormatHasAlpha[frame.pixelFormat()] ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + result = QImage(frame.width(), frame.height(), format); convert(frame, result.bits()); } } diff --git a/src/multimedia/video/qvideoframe.h b/src/multimedia/video/qvideoframe.h index 9628045cc..185291e82 100644 --- a/src/multimedia/video/qvideoframe.h +++ b/src/multimedia/video/qvideoframe.h @@ -94,7 +94,6 @@ public: Format_P010LE, Format_P010BE, - Format_P016LE, Format_P016BE, diff --git a/src/multimedia/video/qvideoframeconversionhelper.cpp b/src/multimedia/video/qvideoframeconversionhelper.cpp index 919e150df..b2d724703 100644 --- a/src/multimedia/video/qvideoframeconversionhelper.cpp +++ b/src/multimedia/video/qvideoframeconversionhelper.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qvideoframeconversionhelper_p.h" +#include "qrgb.h" QT_BEGIN_NAMESPACE @@ -94,9 +95,41 @@ static inline void planarYUV420_to_ARGB32(const uchar *y, int yStride, } } +static inline void planarYUV422_to_ARGB32(const uchar *y, int yStride, + const uchar *u, int uStride, + const uchar *v, int vStride, + int uvPixelStride, + quint32 *rgb, + int width, int height) +{ + quint32 *rgb0 = rgb; + quint32 *rgb1 = rgb + width; + + for (int j = 0; j < height; ++j) { + const uchar *lineY0 = y; + const uchar *lineU = u; + const uchar *lineV = v; + + for (int i = 0; i < width; i += 2) { + EXPAND_UV(*lineU, *lineV); + lineU += uvPixelStride; + lineV += uvPixelStride; + + *rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu); + *rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu); + } + + y += yStride << 1; // stride * 2 + u += uStride; + v += vStride; + rgb0 += width; + rgb1 += width; + } +} -void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *output) + +static void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_TRIPLANAR(frame) planarYUV420_to_ARGB32(plane1, plane1Stride, @@ -107,7 +140,19 @@ void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *o width, height); } -void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_YUV422P_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_TRIPLANAR(frame) + planarYUV422_to_ARGB32(plane1, plane1Stride, + plane2, plane2Stride, + plane3, plane3Stride, + 1, + reinterpret_cast<quint32*>(output), + width, height); +} + + +static void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_TRIPLANAR(frame) planarYUV420_to_ARGB32(plane1, plane1Stride, @@ -118,7 +163,32 @@ void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *outp width, height); } -void QT_FASTCALL qt_convert_AYUV444_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_AYUV444_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 4) + + quint32 *rgb = reinterpret_cast<quint32*>(output); + + for (int i = 0; i < height; ++i) { + const uchar *lineSrc = src; + + for (int j = 0; j < width; ++j) { + int a = *lineSrc++; + int y = *lineSrc++; + int u = *lineSrc++; + int v = *lineSrc++; + + EXPAND_UV(u, v); + + *rgb++ = qPremultiply(qYUVToARGB32(y, rv, guv, bu, a)); + } + + src += stride; + } +} + +static void QT_FASTCALL qt_convert_AYUV444_Premultiplied_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_PACKED(frame) MERGE_LOOPS(width, height, stride, 4) @@ -143,7 +213,7 @@ void QT_FASTCALL qt_convert_AYUV444_to_ARGB32(const QVideoFrame &frame, uchar *o } } -void QT_FASTCALL qt_convert_YUV444_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_YUV444_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_PACKED(frame) MERGE_LOOPS(width, height, stride, 3) @@ -167,7 +237,7 @@ void QT_FASTCALL qt_convert_YUV444_to_ARGB32(const QVideoFrame &frame, uchar *ou } } -void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_PACKED(frame) MERGE_LOOPS(width, height, stride, 2) @@ -193,7 +263,7 @@ void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *outp } } -void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_PACKED(frame) MERGE_LOOPS(width, height, stride, 2) @@ -219,7 +289,7 @@ void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *outp } } -void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_BIPLANAR(frame) planarYUV420_to_ARGB32(plane1, plane1Stride, @@ -230,7 +300,7 @@ void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *outp width, height); } -void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_BIPLANAR(frame) planarYUV420_to_ARGB32(plane1, plane1Stride, @@ -241,7 +311,88 @@ void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *outp width, height); } -void QT_FASTCALL qt_convert_BGRA32_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_IMC1_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_TRIPLANAR(frame) + Q_ASSERT(plane1Stride == plane2Stride); + Q_ASSERT(plane1Stride == plane3Stride); + + planarYUV420_to_ARGB32(plane1, plane1Stride, + plane3, plane3Stride, + plane2, plane2Stride, + 1, + reinterpret_cast<quint32*>(output), + width, height); +} + +static void QT_FASTCALL qt_convert_IMC2_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_BIPLANAR(frame) + Q_ASSERT(plane1Stride == plane2Stride); + + planarYUV420_to_ARGB32(plane1, plane1Stride, + plane2 + (plane1Stride >> 1), plane1Stride, + plane2, plane1Stride, + 1, + reinterpret_cast<quint32*>(output), + width, height); +} + +static void QT_FASTCALL qt_convert_IMC3_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_TRIPLANAR(frame) + Q_ASSERT(plane1Stride == plane2Stride); + Q_ASSERT(plane1Stride == plane3Stride); + + planarYUV420_to_ARGB32(plane1, plane1Stride, + plane2, plane2Stride, + plane3, plane3Stride, + 1, + reinterpret_cast<quint32*>(output), + width, height); +} + +static void QT_FASTCALL qt_convert_IMC4_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_BIPLANAR(frame) + Q_ASSERT(plane1Stride == plane2Stride); + + planarYUV420_to_ARGB32(plane1, plane1Stride, + plane2, plane1Stride, + plane2 + (plane1Stride >> 1), plane1Stride, + 1, + reinterpret_cast<quint32*>(output), + width, height); +} + + +static void QT_FASTCALL qt_convert_BGRA32_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 4) + + quint32 *argb = reinterpret_cast<quint32*>(output); + + for (int y = 0; y < height; ++y) { + const quint32 *bgra = reinterpret_cast<const quint32*>(src); + + int x = 0; + for (; x < width - 3; x += 4) { + *argb++ = qPremultiply(qConvertBGRA32ToARGB32(*bgra++)); + *argb++ = qPremultiply(qConvertBGRA32ToARGB32(*bgra++)); + *argb++ = qPremultiply(qConvertBGRA32ToARGB32(*bgra++)); + *argb++ = qPremultiply(qConvertBGRA32ToARGB32(*bgra++)); + } + + // leftovers + for (; x < width; ++x) + *argb++ = qPremultiply(qConvertBGRA32ToARGB32(*bgra++)); + + src += stride; + } +} + +static void QT_FASTCALL qt_convert_BGRA32_Premultiplied_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_PACKED(frame) MERGE_LOOPS(width, height, stride, 4) @@ -267,7 +418,33 @@ void QT_FASTCALL qt_convert_BGRA32_to_ARGB32(const QVideoFrame &frame, uchar *ou } } -void QT_FASTCALL qt_convert_BGR24_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_ABGR32_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 4) + + quint32 *argb = reinterpret_cast<quint32*>(output); + + for (int y = 0; y < height; ++y) { + const quint32 *abgr = reinterpret_cast<const quint32*>(src); + + int x = 0; + for (; x < width - 3; x += 4) { + *argb++ = qConvertABGR32ToARGB32(*abgr++); + *argb++ = qConvertABGR32ToARGB32(*abgr++); + *argb++ = qConvertABGR32ToARGB32(*abgr++); + *argb++ = qConvertABGR32ToARGB32(*abgr++); + } + + // leftovers + for (; x < width; ++x) + *argb++ = qConvertABGR32ToARGB32(*abgr++); + + src += stride; + } +} + +static void QT_FASTCALL qt_convert_BGR24_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_PACKED(frame) MERGE_LOOPS(width, height, stride, 3) @@ -299,7 +476,7 @@ void QT_FASTCALL qt_convert_BGR24_to_ARGB32(const QVideoFrame &frame, uchar *out } } -void QT_FASTCALL qt_convert_BGR565_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_BGR565_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_PACKED(frame) MERGE_LOOPS(width, height, stride, 2) @@ -325,7 +502,7 @@ void QT_FASTCALL qt_convert_BGR565_to_ARGB32(const QVideoFrame &frame, uchar *ou } } -void QT_FASTCALL qt_convert_BGR555_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_BGR555_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_PACKED(frame) MERGE_LOOPS(width, height, stride, 2) @@ -351,6 +528,39 @@ void QT_FASTCALL qt_convert_BGR555_to_ARGB32(const QVideoFrame &frame, uchar *ou } } +static void QT_FASTCALL qt_convert_BGRA5658_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 3) + + quint32 *argb = reinterpret_cast<quint32*>(output); + + for (int y = 0; y < height; ++y) { + const uchar *bgr = src; + + int x = 0; + for (; x < width - 3; x += 4) { + *argb++ = qConvertBGRA5658ToARGB32(bgr); + bgr += 3; + *argb++ = qConvertBGRA5658ToARGB32(bgr); + bgr += 3; + *argb++ = qConvertBGRA5658ToARGB32(bgr); + bgr += 3; + *argb++ = qConvertBGRA5658ToARGB32(bgr); + bgr += 3; + } + + // leftovers + for (; x < width; ++x) { + *argb++ = qConvertBGRA5658ToARGB32(bgr); + bgr += 3; + } + + src += stride; + } +} + + static inline void planarYUV420_16bit_to_ARGB32(const uchar *y, int yStride, const uchar *u, int uStride, const uchar *v, int vStride, @@ -390,7 +600,7 @@ static inline void planarYUV420_16bit_to_ARGB32(const uchar *y, int yStride, } } -void QT_FASTCALL qt_convert_P016LE_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_P016LE_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_BIPLANAR(frame) planarYUV420_16bit_to_ARGB32(plane1 + 1, plane1Stride, @@ -402,7 +612,7 @@ void QT_FASTCALL qt_convert_P016LE_to_ARGB32(const QVideoFrame &frame, uchar *ou } -void QT_FASTCALL qt_convert_P016BE_to_ARGB32(const QVideoFrame &frame, uchar *output) +static void QT_FASTCALL qt_convert_P016BE_to_ARGB32(const QVideoFrame &frame, uchar *output) { FETCH_INFO_BIPLANAR(frame) planarYUV420_16bit_to_ARGB32(plane1, plane1Stride, @@ -414,4 +624,84 @@ void QT_FASTCALL qt_convert_P016BE_to_ARGB32(const QVideoFrame &frame, uchar *ou } +static VideoFrameConvertFunc qConvertFuncs[QVideoFrame::NPixelFormats] = { + /* Format_Invalid */ nullptr, // Not needed + /* Format_ARGB32 */ nullptr, // Not needed + /* Format_ARGB32_Premultiplied */ nullptr, // Not needed + /* Format_RGB32 */ nullptr, // Not needed + /* Format_RGB24 */ nullptr, // Not needed + /* Format_RGB565 */ nullptr, // Not needed + /* Format_RGB555 */ nullptr, // Not needed + /* Format_ARGB8565_Premultiplied */ nullptr, // Not needed + /* Format_BGRA32 */ qt_convert_BGRA32_to_ARGB32, + /* Format_BGRA32_Premultiplied */ qt_convert_BGRA32_Premultiplied_to_ARGB32, + /* Format_ABGR32 */ qt_convert_ABGR32_to_ARGB32, + /* Format_BGR32 */ qt_convert_BGRA32_Premultiplied_to_ARGB32, + /* Format_BGR24 */ qt_convert_BGR24_to_ARGB32, + /* Format_BGR565 */ qt_convert_BGR565_to_ARGB32, + /* Format_BGR555 */ qt_convert_BGR555_to_ARGB32, + /* Format_BGRA5658_Premultiplied */ qt_convert_BGRA5658_to_ARGB32, + /* Format_AYUV444 */ qt_convert_AYUV444_to_ARGB32, + /* Format_AYUV444_Premultiplied */ qt_convert_AYUV444_Premultiplied_to_ARGB32, + /* Format_YUV444 */ qt_convert_YUV444_to_ARGB32, + /* Format_YUV420P */ qt_convert_YUV420P_to_ARGB32, + /* Format_YUV422P */ qt_convert_YUV422P_to_ARGB32, + /* Format_YV12 */ qt_convert_YV12_to_ARGB32, + /* Format_UYVY */ qt_convert_UYVY_to_ARGB32, + /* Format_YUYV */ qt_convert_YUYV_to_ARGB32, + /* Format_NV12 */ qt_convert_NV12_to_ARGB32, + /* Format_NV21 */ qt_convert_NV21_to_ARGB32, + /* Format_IMC1 */ qt_convert_IMC1_to_ARGB32, + /* Format_IMC2 */ qt_convert_IMC2_to_ARGB32, + /* Format_IMC3 */ qt_convert_IMC3_to_ARGB32, + /* Format_IMC4 */ qt_convert_IMC4_to_ARGB32, + /* Format_Y8 */ nullptr, // Not needed + /* Format_Y16 */ nullptr, // Not needed + /* Format_P010LE */ qt_convert_P016LE_to_ARGB32, + /* Format_P010BE */ qt_convert_P016BE_to_ARGB32, + /* Format_P016LE */ qt_convert_P016LE_to_ARGB32, + /* Format_P016BE */ qt_convert_P016BE_to_ARGB32, + /* Format_Jpeg */ nullptr, // Not needed +}; + +static void qInitConvertFuncsAsm() +{ +#ifdef QT_COMPILER_SUPPORTS_SSE2 + extern void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_sse2(const QVideoFrame&, uchar*); + if (qCpuHasFeature(SSE2)){ + qConvertFuncs[QVideoFrame::Format_BGRA32] = qt_convert_BGRA32_to_ARGB32_sse2; + qConvertFuncs[QVideoFrame::Format_BGRA32_Premultiplied] = qt_convert_BGRA32_to_ARGB32_sse2; + qConvertFuncs[QVideoFrame::Format_BGR32] = qt_convert_BGRA32_to_ARGB32_sse2; + } +#endif +#ifdef QT_COMPILER_SUPPORTS_SSSE3 + extern void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_ssse3(const QVideoFrame&, uchar*); + if (qCpuHasFeature(SSSE3)){ + qConvertFuncs[QVideoFrame::Format_BGRA32] = qt_convert_BGRA32_to_ARGB32_ssse3; + qConvertFuncs[QVideoFrame::Format_BGRA32_Premultiplied] = qt_convert_BGRA32_to_ARGB32_ssse3; + qConvertFuncs[QVideoFrame::Format_BGR32] = qt_convert_BGRA32_to_ARGB32_ssse3; + } +#endif +#ifdef QT_COMPILER_SUPPORTS_AVX2 + extern void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_avx2(const QVideoFrame&, uchar*); + if (qCpuHasFeature(AVX2)){ + qConvertFuncs[QVideoFrame::Format_BGRA32] = qt_convert_BGRA32_to_ARGB32_avx2; + qConvertFuncs[QVideoFrame::Format_BGRA32_Premultiplied] = qt_convert_BGRA32_to_ARGB32_avx2; + qConvertFuncs[QVideoFrame::Format_BGR32] = qt_convert_BGRA32_to_ARGB32_avx2; + } +#endif +} + +VideoFrameConvertFunc qConverterForFormat(QVideoFrame::PixelFormat format) +{ + static bool initAsmFuncsDone = false; + if (!initAsmFuncsDone) { + qInitConvertFuncsAsm(); + initAsmFuncsDone = true; + } + VideoFrameConvertFunc convert = qConvertFuncs[format]; + return convert; +} + + QT_END_NAMESPACE diff --git a/src/multimedia/video/qvideoframeconversionhelper_p.h b/src/multimedia/video/qvideoframeconversionhelper_p.h index b7837db2a..0fdcbf8a3 100644 --- a/src/multimedia/video/qvideoframeconversionhelper_p.h +++ b/src/multimedia/video/qvideoframeconversionhelper_p.h @@ -54,8 +54,11 @@ #include <qvideoframe.h> #include <private/qsimd_p.h> +// Converts to RGB32 or ARGB32_Premultiplied typedef void (QT_FASTCALL *VideoFrameConvertFunc)(const QVideoFrame &frame, uchar *output); +VideoFrameConvertFunc qConverterForFormat(QVideoFrame::PixelFormat format); + inline quint32 qConvertBGRA32ToARGB32(quint32 bgra) { return (((bgra & 0xFF000000) >> 24) @@ -64,11 +67,26 @@ inline quint32 qConvertBGRA32ToARGB32(quint32 bgra) | ((bgra & 0x000000FF) << 24)); } +inline quint32 qConvertABGR32ToARGB32(quint32 abgr) +{ + return ((abgr & 0xFF000000) + | ((abgr & 0x00FF0000) >> 16) + | (abgr & 0x0000FF00) + | ((abgr & 0x000000FF) << 16)); +} + inline quint32 qConvertBGR24ToARGB32(const uchar *bgr) { return 0xFF000000 | bgr[0] | bgr[1] << 8 | bgr[2] << 16; } +inline quint32 qConvertBGRA5658ToARGB32(const uchar *bgr) +{ + return (bgr[0] & 0xf8) | (quint32(bgr[0] & 7) << 13) | + (quint32(bgr[1] & 0xe0) << 5) | (quint32(bgr[1] & 0x1f) << 3) | + bgr[2] << 24; +} + inline quint32 qConvertBGR565ToARGB32(quint16 bgr) { return 0xff000000 |