diff options
Diffstat (limited to 'src/multimedia')
-rw-r--r-- | src/multimedia/doc/qtmultimedia.qdocconf | 2 | ||||
-rw-r--r-- | src/multimedia/gsttools_headers/qgstutils_p.h | 2 | ||||
-rw-r--r-- | src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h | 5 | ||||
-rw-r--r-- | src/multimedia/multimedia.pro | 2 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframe.cpp | 126 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframe.h | 3 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframe_p.h | 57 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframeconversionhelper.cpp | 348 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframeconversionhelper_avx2.cpp | 83 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframeconversionhelper_p.h | 106 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframeconversionhelper_sse2.cpp | 83 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp | 82 | ||||
-rw-r--r-- | src/multimedia/video/qvideooutputorientationhandler_p.h | 4 | ||||
-rw-r--r-- | src/multimedia/video/video.pri | 11 |
14 files changed, 909 insertions, 5 deletions
diff --git a/src/multimedia/doc/qtmultimedia.qdocconf b/src/multimedia/doc/qtmultimedia.qdocconf index d917062a2..a32043b39 100644 --- a/src/multimedia/doc/qtmultimedia.qdocconf +++ b/src/multimedia/doc/qtmultimedia.qdocconf @@ -32,7 +32,7 @@ exampledirs += ../../../examples/multimedia \ snippets # Specify example install dir under QT_INSTALL_EXAMPLES -examplesinstallpath = multimedia +examplesinstallpath = qtmultimedia/multimedia headerdirs += ../.. diff --git a/src/multimedia/gsttools_headers/qgstutils_p.h b/src/multimedia/gsttools_headers/qgstutils_p.h index 31fb85847..cf677c321 100644 --- a/src/multimedia/gsttools_headers/qgstutils_p.h +++ b/src/multimedia/gsttools_headers/qgstutils_p.h @@ -150,6 +150,8 @@ gboolean qt_gst_element_query_position(GstElement *element, GstFormat format, gi gboolean qt_gst_element_query_duration(GstElement *element, GstFormat format, gint64 *cur); GstCaps *qt_gst_caps_normalize(GstCaps *caps); const gchar *qt_gst_element_get_factory_name(GstElement *element); +gboolean qt_gst_caps_can_intersect(const GstCaps * caps1, const GstCaps * caps2); +GList *qt_gst_video_sinks(); QDebug operator <<(QDebug debug, GstCaps *caps); diff --git a/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h b/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h index a1ef5616b..9c04b9804 100644 --- a/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h +++ b/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h @@ -157,7 +157,12 @@ private: static gboolean unlock(GstBaseSink *sink); +#if GST_CHECK_VERSION(0, 10, 25) static GstFlowReturn show_frame(GstVideoSink *sink, GstBuffer *buffer); +#else + static GstFlowReturn preroll(GstBaseSink *sink, GstBuffer *buffer); + static GstFlowReturn render(GstBaseSink *sink, GstBuffer *buffer); +#endif private: QVideoSurfaceGstDelegate *delegate; diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro index 3aff75949..e3f368cf4 100644 --- a/src/multimedia/multimedia.pro +++ b/src/multimedia/multimedia.pro @@ -55,6 +55,8 @@ SOURCES += \ qmediastoragelocation.cpp \ qmultimedia.cpp +CONFIG += simd optimize_full + include(audio/audio.pri) include(camera/camera.pri) include(controls/controls.pri) 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) { diff --git a/src/multimedia/video/qvideoframe.h b/src/multimedia/video/qvideoframe.h index a273b7f73..633604ebb 100644 --- a/src/multimedia/video/qvideoframe.h +++ b/src/multimedia/video/qvideoframe.h @@ -96,6 +96,9 @@ public: Format_CameraRaw, Format_AdobeDng, +#ifndef Q_QDOC + NPixelFormats, +#endif Format_User = 1000 }; diff --git a/src/multimedia/video/qvideoframe_p.h b/src/multimedia/video/qvideoframe_p.h new file mode 100644 index 000000000..15260c26f --- /dev/null +++ b/src/multimedia/video/qvideoframe_p.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOFRAME_P_H +#define QVIDEOFRAME_P_H + +#include <QtMultimedia/qvideoframe.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +Q_MULTIMEDIA_EXPORT QImage qt_imageFromVideoFrame(const QVideoFrame &frame); + +QT_END_NAMESPACE + +#endif // QVIDEOFRAME_P_H + diff --git a/src/multimedia/video/qvideoframeconversionhelper.cpp b/src/multimedia/video/qvideoframeconversionhelper.cpp new file mode 100644 index 000000000..9599b1947 --- /dev/null +++ b/src/multimedia/video/qvideoframeconversionhelper.cpp @@ -0,0 +1,348 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideoframeconversionhelper_p.h" + +QT_BEGIN_NAMESPACE + +#define CLAMP(n) (n > 255 ? 255 : (n < 0 ? 0 : n)) + +#define EXPAND_UV(u, v) \ + int uu = u - 128; \ + int vv = v - 128; \ + int rv = 409 * vv + 128; \ + int guv = 100 * uu + 208 * vv + 128; \ + int bu = 516 * uu + 128; \ + +static inline quint32 qYUVToARGB32(int y, int rv, int guv, int bu, int a = 0xff) +{ + int yy = (y - 16) * 298; + return (a << 24) + | CLAMP((yy + rv) >> 8) << 16 + | CLAMP((yy - guv) >> 8) << 8 + | CLAMP((yy + bu) >> 8); +} + +static inline void planarYUV420_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 += 2) { + const uchar *lineY0 = y; + const uchar *lineY1 = y + yStride; + 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); + *rgb1++ = qYUVToARGB32(*lineY1++, rv, guv, bu); + *rgb1++ = qYUVToARGB32(*lineY1++, 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) +{ + FETCH_INFO_TRIPLANAR(frame) + planarYUV420_to_ARGB32(plane1, plane1Stride, + plane2, plane2Stride, + plane3, plane3Stride, + 1, + reinterpret_cast<quint32*>(output), + width, height); +} + +void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_TRIPLANAR(frame) + planarYUV420_to_ARGB32(plane1, plane1Stride, + plane3, plane3Stride, + plane2, plane2Stride, + 1, + reinterpret_cast<quint32*>(output), + width, height); +} + +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++ = qYUVToARGB32(y, rv, guv, bu, a); + } + + src += stride; + } +} + +void QT_FASTCALL qt_convert_YUV444_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 3) + + 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 y = *lineSrc++; + int u = *lineSrc++; + int v = *lineSrc++; + + EXPAND_UV(u, v); + + *rgb++ = qYUVToARGB32(y, rv, guv, bu); + } + + src += stride; + } +} + +void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 2) + + quint32 *rgb = reinterpret_cast<quint32*>(output); + + for (int i = 0; i < height; ++i) { + const uchar *lineSrc = src; + + for (int j = 0; j < width; j += 2) { + int u = *lineSrc++; + int y0 = *lineSrc++; + int v = *lineSrc++; + int y1 = *lineSrc++; + + EXPAND_UV(u, v); + + *rgb++ = qYUVToARGB32(y0, rv, guv, bu); + *rgb++ = qYUVToARGB32(y1, rv, guv, bu); + } + + src += stride; + } +} + +void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 2) + + quint32 *rgb = reinterpret_cast<quint32*>(output); + + for (int i = 0; i < height; ++i) { + const uchar *lineSrc = src; + + for (int j = 0; j < width; j += 2) { + int y0 = *lineSrc++; + int u = *lineSrc++; + int y1 = *lineSrc++; + int v = *lineSrc++; + + EXPAND_UV(u, v); + + *rgb++ = qYUVToARGB32(y0, rv, guv, bu); + *rgb++ = qYUVToARGB32(y1, rv, guv, bu); + } + + src += stride; + } +} + +void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_BIPLANAR(frame) + planarYUV420_to_ARGB32(plane1, plane1Stride, + plane2, plane2Stride, + plane2 + 1, plane2Stride, + 2, + reinterpret_cast<quint32*>(output), + width, height); +} + +void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_BIPLANAR(frame) + planarYUV420_to_ARGB32(plane1, plane1Stride, + plane2 + 1, plane2Stride, + plane2, plane2Stride, + 2, + reinterpret_cast<quint32*>(output), + width, height); +} + +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++ = qConvertBGRA32ToARGB32(*bgra++); + *argb++ = qConvertBGRA32ToARGB32(*bgra++); + *argb++ = qConvertBGRA32ToARGB32(*bgra++); + *argb++ = qConvertBGRA32ToARGB32(*bgra++); + } + + // leftovers + for (; x < width; ++x) + *argb++ = qConvertBGRA32ToARGB32(*bgra++); + + src += stride; + } +} + +void QT_FASTCALL qt_convert_BGR24_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++ = qConvertBGR24ToARGB32(bgr); + bgr += 3; + *argb++ = qConvertBGR24ToARGB32(bgr); + bgr += 3; + *argb++ = qConvertBGR24ToARGB32(bgr); + bgr += 3; + *argb++ = qConvertBGR24ToARGB32(bgr); + bgr += 3; + } + + // leftovers + for (; x < width; ++x) { + *argb++ = qConvertBGR24ToARGB32(bgr); + bgr += 3; + } + + src += stride; + } +} + +void QT_FASTCALL qt_convert_BGR565_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 2) + + quint32 *argb = reinterpret_cast<quint32*>(output); + + for (int y = 0; y < height; ++y) { + const quint16 *bgr = reinterpret_cast<const quint16*>(src); + + int x = 0; + for (; x < width - 3; x += 4) { + *argb++ = qConvertBGR565ToARGB32(*bgr++); + *argb++ = qConvertBGR565ToARGB32(*bgr++); + *argb++ = qConvertBGR565ToARGB32(*bgr++); + *argb++ = qConvertBGR565ToARGB32(*bgr++); + } + + // leftovers + for (; x < width; ++x) + *argb++ = qConvertBGR565ToARGB32(*bgr++); + + src += stride; + } +} + +void QT_FASTCALL qt_convert_BGR555_to_ARGB32(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 2) + + quint32 *argb = reinterpret_cast<quint32*>(output); + + for (int y = 0; y < height; ++y) { + const quint16 *bgr = reinterpret_cast<const quint16*>(src); + + int x = 0; + for (; x < width - 3; x += 4) { + *argb++ = qConvertBGR555ToARGB32(*bgr++); + *argb++ = qConvertBGR555ToARGB32(*bgr++); + *argb++ = qConvertBGR555ToARGB32(*bgr++); + *argb++ = qConvertBGR555ToARGB32(*bgr++); + } + + // leftovers + for (; x < width; ++x) + *argb++ = qConvertBGR555ToARGB32(*bgr++); + + src += stride; + } +} + +QT_END_NAMESPACE diff --git a/src/multimedia/video/qvideoframeconversionhelper_avx2.cpp b/src/multimedia/video/qvideoframeconversionhelper_avx2.cpp new file mode 100644 index 000000000..c769c8868 --- /dev/null +++ b/src/multimedia/video/qvideoframeconversionhelper_avx2.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideoframeconversionhelper_p.h" + +#ifdef QT_COMPILER_SUPPORTS_AVX2 + +QT_BEGIN_NAMESPACE + +void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 4) + quint32 *argb = reinterpret_cast<quint32*>(output); + + const __m256i shuffleMask = _mm256_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3, + 12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3); + + for (int y = 0; y < height; ++y) { + const quint32 *bgra = reinterpret_cast<const quint32*>(src); + + int x = 0; + ALIGN(32, argb, x, width) { + *argb = qConvertBGRA32ToARGB32(*bgra); + ++bgra; + ++argb; + } + + for (; x < width - 15; x += 16) { + __m256i pixelData = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(bgra)); + __m256i pixelData2 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(bgra + 8)); + bgra += 16; + pixelData = _mm256_shuffle_epi8(pixelData, shuffleMask); + pixelData2 = _mm256_shuffle_epi8(pixelData2, shuffleMask); + _mm256_store_si256(reinterpret_cast<__m256i*>(argb), pixelData); + _mm256_store_si256(reinterpret_cast<__m256i*>(argb + 8), pixelData2); + argb += 16; + } + + // leftovers + for (; x < width; ++x) { + *argb = qConvertBGRA32ToARGB32(*bgra); + ++bgra; + ++argb; + } + + src += stride; + } +} + +QT_END_NAMESPACE + +#endif diff --git a/src/multimedia/video/qvideoframeconversionhelper_p.h b/src/multimedia/video/qvideoframeconversionhelper_p.h new file mode 100644 index 000000000..eead17a91 --- /dev/null +++ b/src/multimedia/video/qvideoframeconversionhelper_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOFRAMECONVERSIONHELPER_P_H +#define QVIDEOFRAMECONVERSIONHELPER_P_H + +#include <qvideoframe.h> +#include <private/qsimd_p.h> + +typedef void (QT_FASTCALL *VideoFrameConvertFunc)(const QVideoFrame &frame, uchar *output); + +inline quint32 qConvertBGRA32ToARGB32(quint32 bgra) +{ + return (((bgra & 0xFF000000) >> 24) + | ((bgra & 0x00FF0000) >> 8) + | ((bgra & 0x0000FF00) << 8) + | ((bgra & 0x000000FF) << 24)); +} + +inline quint32 qConvertBGR24ToARGB32(const uchar *bgr) +{ + return 0xFF000000 | bgr[0] | bgr[1] << 8 | bgr[2] << 16; +} + +inline quint32 qConvertBGR565ToARGB32(quint16 bgr) +{ + return 0xff000000 + | ((((bgr) >> 8) & 0xf8) | (((bgr) >> 13) & 0x7)) + | ((((bgr) << 5) & 0xfc00) | (((bgr) >> 1) & 0x300)) + | ((((bgr) << 19) & 0xf80000) | (((bgr) << 14) & 0x70000)); +} + +inline quint32 qConvertBGR555ToARGB32(quint16 bgr) +{ + return 0xff000000 + | ((((bgr) >> 7) & 0xf8) | (((bgr) >> 12) & 0x7)) + | ((((bgr) << 6) & 0xf800) | (((bgr) << 1) & 0x700)) + | ((((bgr) << 19) & 0xf80000) | (((bgr) << 11) & 0x70000)); +} + +#define FETCH_INFO_PACKED(frame) \ + const uchar *src = frame.bits(); \ + int stride = frame.bytesPerLine(); \ + int width = frame.width(); \ + int height = frame.height(); + +#define FETCH_INFO_BIPLANAR(frame) \ + const uchar *plane1 = frame.bits(0); \ + const uchar *plane2 = frame.bits(1); \ + int plane1Stride = frame.bytesPerLine(0); \ + int plane2Stride = frame.bytesPerLine(1); \ + int width = frame.width(); \ + int height = frame.height(); + +#define FETCH_INFO_TRIPLANAR(frame) \ + const uchar *plane1 = frame.bits(0); \ + const uchar *plane2 = frame.bits(1); \ + const uchar *plane3 = frame.bits(2); \ + int plane1Stride = frame.bytesPerLine(0); \ + int plane2Stride = frame.bytesPerLine(1); \ + int plane3Stride = frame.bytesPerLine(2); \ + int width = frame.width(); \ + int height = frame.height(); \ + +#define MERGE_LOOPS(width, height, stride, bpp) \ + if (stride == width * bpp) { \ + width *= height; \ + height = 1; \ + stride = 0; \ + } + +#define ALIGN(boundary, ptr, x, length) \ + for (; ((reinterpret_cast<qintptr>(ptr) & (boundary - 1)) != 0) && x < length; ++x) + +#endif // QVIDEOFRAMECONVERSIONHELPER_P_H + diff --git a/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp b/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp new file mode 100644 index 000000000..27689e5bb --- /dev/null +++ b/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideoframeconversionhelper_p.h" + +#ifdef QT_COMPILER_SUPPORTS_SSE2 + +QT_BEGIN_NAMESPACE + +void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 4) + quint32 *argb = reinterpret_cast<quint32*>(output); + + const __m128i zero = _mm_setzero_si128(); + + for (int y = 0; y < height; ++y) { + const quint32 *bgra = reinterpret_cast<const quint32*>(src); + + int x = 0; + ALIGN(16, argb, x, width) { + *argb = qConvertBGRA32ToARGB32(*bgra); + ++bgra; + ++argb; + } + + for (; x < width - 3; x += 4) { + __m128i pixelData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(bgra)); + bgra += 4; + __m128i gaComponents = _mm_unpacklo_epi8(pixelData, zero); + __m128i brComponents = _mm_unpackhi_epi8(pixelData, zero); + gaComponents = _mm_shufflelo_epi16(_mm_shufflehi_epi16(gaComponents, _MM_SHUFFLE(0, 1, 2, 3)), _MM_SHUFFLE(0, 1, 2, 3)); // swap GA + brComponents = _mm_shufflelo_epi16(_mm_shufflehi_epi16(brComponents, _MM_SHUFFLE(0, 1, 2, 3)), _MM_SHUFFLE(0, 1, 2, 3)); // swap BR + pixelData = _mm_packus_epi16(gaComponents, brComponents); + _mm_store_si128(reinterpret_cast<__m128i*>(argb), pixelData); + argb += 4; + } + + // leftovers + for (; x < width; ++x) { + *argb = qConvertBGRA32ToARGB32(*bgra); + ++bgra; + ++argb; + } + + src += stride; + } +} + +QT_END_NAMESPACE + +#endif diff --git a/src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp b/src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp new file mode 100644 index 000000000..b15617cef --- /dev/null +++ b/src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideoframeconversionhelper_p.h" + +#ifdef QT_COMPILER_SUPPORTS_SSSE3 + +QT_BEGIN_NAMESPACE + +void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output) +{ + FETCH_INFO_PACKED(frame) + MERGE_LOOPS(width, height, stride, 4) + quint32 *argb = reinterpret_cast<quint32*>(output); + + __m128i shuffleMask = _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3); + + for (int y = 0; y < height; ++y) { + const quint32 *bgra = reinterpret_cast<const quint32*>(src); + + int x = 0; + ALIGN(16, argb, x, width) { + *argb = qConvertBGRA32ToARGB32(*bgra); + ++bgra; + ++argb; + } + + for (; x < width - 7; x += 8) { + __m128i pixelData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(bgra)); + __m128i pixelData2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(bgra + 4)); + bgra += 8; + pixelData = _mm_shuffle_epi8(pixelData, shuffleMask); + pixelData2 = _mm_shuffle_epi8(pixelData2, shuffleMask); + _mm_store_si128(reinterpret_cast<__m128i*>(argb), pixelData); + _mm_store_si128(reinterpret_cast<__m128i*>(argb + 4), pixelData2); + argb += 8; + } + + // leftovers + for (; x < width; ++x) { + *argb = qConvertBGRA32ToARGB32(*bgra); + ++bgra; + ++argb; + } + + src += stride; + } +} + +QT_END_NAMESPACE + +#endif diff --git a/src/multimedia/video/qvideooutputorientationhandler_p.h b/src/multimedia/video/qvideooutputorientationhandler_p.h index 252ee2920..c690cafae 100644 --- a/src/multimedia/video/qvideooutputorientationhandler_p.h +++ b/src/multimedia/video/qvideooutputorientationhandler_p.h @@ -59,10 +59,10 @@ public: int currentOrientation() const; -signals: +Q_SIGNALS: void orientationChanged(int angle); -private slots: +private Q_SLOTS: void screenOrientationChanged(Qt::ScreenOrientation orientation); private: diff --git a/src/multimedia/video/video.pri b/src/multimedia/video/video.pri index 3e39d9d18..e5fa697ce 100644 --- a/src/multimedia/video/video.pri +++ b/src/multimedia/video/video.pri @@ -14,7 +14,9 @@ PRIVATE_HEADERS += \ video/qimagevideobuffer_p.h \ video/qmemoryvideobuffer_p.h \ video/qvideooutputorientationhandler_p.h \ - video/qvideosurfaceoutput_p.h + video/qvideosurfaceoutput_p.h \ + video/qvideoframe_p.h \ + video/qvideoframeconversionhelper_p.h SOURCES += \ video/qabstractvideobuffer.cpp \ @@ -26,4 +28,9 @@ SOURCES += \ video/qvideosurfaceformat.cpp \ video/qvideosurfaceoutput.cpp \ video/qvideoprobe.cpp \ - video/qabstractvideofilter.cpp + video/qabstractvideofilter.cpp \ + video/qvideoframeconversionhelper.cpp + +SSE2_SOURCES += video/qvideoframeconversionhelper_sse2.cpp +SSSE3_SOURCES += video/qvideoframeconversionhelper_ssse3.cpp +AVX2_SOURCES += video/qvideoframeconversionhelper_avx2.cpp |