diff options
author | Yoann Lopes <yoann.lopes@theqtcompany.com> | 2015-09-18 21:12:57 +0200 |
---|---|---|
committer | Yoann Lopes <yoann.lopes@theqtcompany.com> | 2015-10-20 12:51:17 +0000 |
commit | 5b3cd2f8b132a8665d37ceabac3fe8828799788b (patch) | |
tree | d56eb29bc02018f5fb527a77268959e4fea6c1e3 /src/multimedia/video/qvideoframe.cpp | |
parent | ee8aca6c8771a92d558003ea5cf62e5236f21bb5 (diff) |
Add private API for conversion from QVideoFrame to QImage.
The Android plugin had a function to convert from NV21 to RGB32.
It's now moved to the Qt Multimedia library and it supports additional
source formats. It could be further improved with more SIMD code, it
could then become a public API.
Change-Id: Ibee349027048a263a1a7ea74dc51237f7747912c
Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
Diffstat (limited to 'src/multimedia/video/qvideoframe.cpp')
-rw-r--r-- | src/multimedia/video/qvideoframe.cpp | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/src/multimedia/video/qvideoframe.cpp b/src/multimedia/video/qvideoframe.cpp index 4e9e28a4d..f0495577c 100644 --- a/src/multimedia/video/qvideoframe.cpp +++ b/src/multimedia/video/qvideoframe.cpp @@ -33,8 +33,10 @@ #include "qvideoframe.h" +#include "qvideoframe_p.h" #include "qimagevideobuffer_p.h" #include "qmemoryvideobuffer_p.h" +#include "qvideoframeconversionhelper_p.h" #include <qimage.h> #include <qpair.h> @@ -654,6 +656,8 @@ bool QVideoFrame::map(QAbstractVideoBuffer::MapMode mode) d->data[2] = d->data[1] + (d->bytesPerLine[1] * d->size.height() / 2); break; } + default: + break; } d->mappedCount++; @@ -994,11 +998,133 @@ QImage::Format QVideoFrame::imageFormatFromPixelFormat(PixelFormat format) case Format_AdobeDng: return QImage::Format_Invalid; case Format_User: + default: 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*); + +static VideoFrameConvertFunc qConvertFuncs[QVideoFrame::NPixelFormats] = { + /* Format_Invalid */ Q_NULLPTR, // Not needed + /* Format_ARGB32 */ Q_NULLPTR, // Not needed + /* Format_ARGB32_Premultiplied */ Q_NULLPTR, // Not needed + /* Format_RGB32 */ Q_NULLPTR, // Not needed + /* Format_RGB24 */ Q_NULLPTR, // Not needed + /* Format_RGB565 */ Q_NULLPTR, // Not needed + /* Format_RGB555 */ Q_NULLPTR, // Not needed + /* Format_ARGB8565_Premultiplied */ Q_NULLPTR, // Not needed + /* Format_BGRA32 */ qt_convert_BGRA32_to_ARGB32, + /* Format_BGRA32_Premultiplied */ qt_convert_BGRA32_to_ARGB32, + /* 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 */ Q_NULLPTR, + /* Format_AYUV444 */ qt_convert_AYUV444_to_ARGB32, + /* Format_AYUV444_Premultiplied */ Q_NULLPTR, + /* Format_YUV444 */ qt_convert_YUV444_to_ARGB32, + /* Format_YUV420P */ qt_convert_YUV420P_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 */ Q_NULLPTR, + /* Format_IMC2 */ Q_NULLPTR, + /* Format_IMC3 */ Q_NULLPTR, + /* Format_IMC4 */ Q_NULLPTR, + /* Format_Y8 */ Q_NULLPTR, + /* Format_Y16 */ Q_NULLPTR, + /* Format_Jpeg */ Q_NULLPTR, // Not needed + /* Format_CameraRaw */ Q_NULLPTR, + /* Format_AdobeDng */ Q_NULLPTR +}; + +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 +} + +/*! + \internal +*/ +QImage qt_imageFromVideoFrame(const QVideoFrame &f) +{ + QVideoFrame &frame = const_cast<QVideoFrame&>(f); + QImage result; + + if (!frame.isValid() || !frame.map(QAbstractVideoBuffer::ReadOnly)) + return result; + + // Formats supported by QImage don't need conversion + QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()); + if (imageFormat != QImage::Format_Invalid) { + result = QImage(frame.bits(), frame.width(), frame.height(), imageFormat).copy(); + } + + // Load from JPG + else if (frame.pixelFormat() == QVideoFrame::Format_Jpeg) { + result.loadFromData(frame.bits(), frame.mappedBytes(), "JPG"); + } + + // Need conversion + else { + static bool initAsmFuncsDone = false; + if (!initAsmFuncsDone) { + qInitConvertFuncsAsm(); + initAsmFuncsDone = true; + } + VideoFrameConvertFunc convert = qConvertFuncs[frame.pixelFormat()]; + if (!convert) { + qWarning() << Q_FUNC_INFO << ": unsupported pixel format" << frame.pixelFormat(); + } else { + result = QImage(frame.width(), frame.height(), QImage::Format_ARGB32); + convert(frame, result.bits()); + } + } + + frame.unmap(); + + return result; +} + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug dbg, QVideoFrame::PixelFormat pf) { |