diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2015-11-05 10:10:26 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2015-11-05 10:10:26 +0100 |
commit | 11df4e75e4eca82d28dc147fcefb29d62b38a5dc (patch) | |
tree | 36f7593c1f5d48123127a918ec23c6fe47b8169a | |
parent | 318159c8492883d7ef29804a68c398cceaa5f89a (diff) | |
parent | 3ef5831041fe1206043f3b36f063eef4842ce243 (diff) |
Merge remote-tracking branch 'origin/5.6' into dev
Change-Id: I64a2e98adeb387e532f0b22129ade7ca7e8dc22a
44 files changed, 1375 insertions, 724 deletions
diff --git a/dist/changes-5.5.1 b/dist/changes-5.5.1 new file mode 100644 index 000000000..d81d815b1 --- /dev/null +++ b/dist/changes-5.5.1 @@ -0,0 +1,68 @@ +Qt 5.5.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.5.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + http://doc.qt.io/qt-5.5/ + +The Qt version 5.5 series is binary compatible with the 5.4.x series. +Applications compiled for 5.4 will continue to run with 5.5. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + http://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Library * +**************************************************************************** + +QtMultimedia +------------ + + - The environment variable QT_QUICK_NO_TEXTURE_VIDEOFRAMES can now be used + to disable OpenGL texture based video frames when using the VideoOutput + QML type. This can be useful in applications that wish to filter and + process the video frames using QAbstractVideoFilter and are not GPU + based. + - QCamera's viewfinder capabilities functions now report correct values + when filtering by pixel aspect ratio. + - [QTBUG-46359] fixed crash after using moveToThread() on a QSoundEffect. + - [QTBUG-47205] fixed VideoOutput (QML) rendering frames from the wrong + source when having multiple VideoOutputs using different sources. + - [QTBUG-47630] fixed Camera.supportedViewfinderFrameRateRanges() (QML) + returning incorrect values when the argument is not of type 'size'. + - [QTBUG-47859] fixed crash when using Radio.radioData (QML) without + a radio backend available. + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + +Android +------- + + - Fixed QVideoProbe stopping to work when using QMediaRecorder to record + the camera. + - Video frames passed to a QAbstractVideoFilter can now be mapped to + system memory. + +Linux +----- + + - QCameraImageProcessing::isWhiteBalanceModeSupported() now correctly + reports if a given white balance mode is supported. + - [QTBUG-45707] fixed QAudioRecorder::stop() sometimes failing to + actually stop the recording. + + WinRT +----- + + - [QTBUG-46456] QCameraImageCapture: getting the list of supported + image capture resolutions and setting the image capture resolution is + now supported. + - [QTBUG-47373] fixed crash occurring with some camera operations. diff --git a/src/gsttools/qgstreamervideooverlay.cpp b/src/gsttools/qgstreamervideooverlay.cpp index 1dcedbcd6..06f93ef6a 100644 --- a/src/gsttools/qgstreamervideooverlay.cpp +++ b/src/gsttools/qgstreamervideooverlay.cpp @@ -148,9 +148,7 @@ GstElement *QGstreamerVideoOverlay::findBestVideoSink() const // If none of the known video sinks are available, try to find one that implements the // GstVideoOverlay interface and has autoplugging rank. - GList *list = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO, - GST_RANK_MARGINAL); - + GList *list = qt_gst_video_sinks(); for (GList *item = list; item != NULL; item = item->next) { GstElementFactory *f = GST_ELEMENT_FACTORY(item->data); @@ -242,12 +240,17 @@ void QGstreamerVideoOverlay::setRenderRectangle(const QRect &rect) h = rect.height(); } -#if !GST_CHECK_VERSION(1,0,0) +#if GST_CHECK_VERSION(1,0,0) + if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink)) + gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(m_videoSink), x, y, w, h); +#elif GST_CHECK_VERSION(0, 10, 29) if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(m_videoSink), x, y , w , h); #else - if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink)) - gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(m_videoSink), x, y, w, h); + Q_UNUSED(x) + Q_UNUSED(y) + Q_UNUSED(w) + Q_UNUSED(h) #endif } diff --git a/src/gsttools/qgstutils.cpp b/src/gsttools/qgstutils.cpp index b13038c21..50a56232a 100644 --- a/src/gsttools/qgstutils.cpp +++ b/src/gsttools/qgstutils.cpp @@ -774,6 +774,7 @@ QSet<QString> QGstUtils::supportedMimeTypes(bool (*isValidFactory)(GstElementFac return supportedMimeTypes; } +#if GST_CHECK_VERSION(1, 0, 0) namespace { struct ColorFormat { QImage::Format imageFormat; GstVideoFormat gstFormat; }; @@ -786,6 +787,7 @@ static const ColorFormat qt_colorLookup[] = }; } +#endif #if GST_CHECK_VERSION(1,0,0) QImage QGstUtils::bufferToImage(GstBuffer *buffer, const GstVideoInfo &videoInfo) @@ -1212,6 +1214,7 @@ void QGstUtils::setMetaData(GstElement *element, const QMap<QByteArray, QVariant tagValue.toDouble(), NULL); break; +#if GST_CHECK_VERSION(0, 10, 31) case QVariant::DateTime: { QDateTime date = tagValue.toDateTime().toLocalTime(); gst_tag_setter_add_tags(GST_TAG_SETTER(element), @@ -1223,6 +1226,7 @@ void QGstUtils::setMetaData(GstElement *element, const QMap<QByteArray, QVariant NULL); break; } +#endif default: break; } @@ -1408,8 +1412,10 @@ GstCaps *qt_gst_pad_get_caps(GstPad *pad) { #if GST_CHECK_VERSION(1,0,0) return gst_pad_query_caps(pad, NULL); -#else +#elif GST_CHECK_VERSION(0, 10, 26) return gst_pad_get_caps_reffed(pad); +#else + return gst_pad_get_caps(pad); #endif } @@ -1464,6 +1470,67 @@ const gchar *qt_gst_element_get_factory_name(GstElement *element) return name; } +gboolean qt_gst_caps_can_intersect(const GstCaps * caps1, const GstCaps * caps2) +{ +#if GST_CHECK_VERSION(0, 10, 25) + return gst_caps_can_intersect(caps1, caps2); +#else + GstCaps *intersection = gst_caps_intersect(caps1, caps2); + gboolean res = !gst_caps_is_empty(intersection); + gst_caps_unref(intersection); + return res; +#endif +} + +#if !GST_CHECK_VERSION(0, 10, 31) +static gboolean qt_gst_videosink_factory_filter(GstPluginFeature *feature, gpointer) +{ + guint rank; + const gchar *klass; + + if (!GST_IS_ELEMENT_FACTORY(feature)) + return FALSE; + + klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature)); + if (!(strstr(klass, "Sink") && strstr(klass, "Video"))) + return FALSE; + + rank = gst_plugin_feature_get_rank(feature); + if (rank < GST_RANK_MARGINAL) + return FALSE; + + return TRUE; +} + +static gint qt_gst_compare_ranks(GstPluginFeature *f1, GstPluginFeature *f2) +{ + gint diff; + + diff = gst_plugin_feature_get_rank(f2) - gst_plugin_feature_get_rank(f1); + if (diff != 0) + return diff; + + return strcmp(gst_plugin_feature_get_name(f2), gst_plugin_feature_get_name (f1)); +} +#endif + +GList *qt_gst_video_sinks() +{ + GList *list = NULL; + +#if GST_CHECK_VERSION(0, 10, 31) + list = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO, + GST_RANK_MARGINAL); +#else + list = gst_registry_feature_filter(gst_registry_get_default(), + (GstPluginFeatureFilter)qt_gst_videosink_factory_filter, + FALSE, NULL); + list = g_list_sort(list, (GCompareFunc)qt_gst_compare_ranks); +#endif + + return list; +} + QDebug operator <<(QDebug debug, GstCaps *caps) { if (caps) { diff --git a/src/gsttools/qvideosurfacegstsink.cpp b/src/gsttools/qvideosurfacegstsink.cpp index 737bc648d..d59709723 100644 --- a/src/gsttools/qvideosurfacegstsink.cpp +++ b/src/gsttools/qvideosurfacegstsink.cpp @@ -376,9 +376,6 @@ void QVideoSurfaceGstSink::class_init(gpointer g_class, gpointer class_data) sink_parent_class = reinterpret_cast<GstVideoSinkClass *>(g_type_class_peek_parent(g_class)); - GstVideoSinkClass *video_sink_class = reinterpret_cast<GstVideoSinkClass *>(g_class); - video_sink_class->show_frame = QVideoSurfaceGstSink::show_frame; - GstBaseSinkClass *base_sink_class = reinterpret_cast<GstBaseSinkClass *>(g_class); base_sink_class->get_caps = QVideoSurfaceGstSink::get_caps; base_sink_class->set_caps = QVideoSurfaceGstSink::set_caps; @@ -387,6 +384,14 @@ void QVideoSurfaceGstSink::class_init(gpointer g_class, gpointer class_data) base_sink_class->stop = QVideoSurfaceGstSink::stop; base_sink_class->unlock = QVideoSurfaceGstSink::unlock; +#if GST_CHECK_VERSION(0, 10, 25) + GstVideoSinkClass *video_sink_class = reinterpret_cast<GstVideoSinkClass *>(g_class); + video_sink_class->show_frame = QVideoSurfaceGstSink::show_frame; +#else + base_sink_class->preroll = QVideoSurfaceGstSink::preroll; + base_sink_class->render = QVideoSurfaceGstSink::render; +#endif + GstElementClass *element_class = reinterpret_cast<GstElementClass *>(g_class); element_class->change_state = QVideoSurfaceGstSink::change_state; @@ -674,10 +679,30 @@ gboolean QVideoSurfaceGstSink::unlock(GstBaseSink *base) return TRUE; } +#if GST_CHECK_VERSION(0, 10, 25) GstFlowReturn QVideoSurfaceGstSink::show_frame(GstVideoSink *base, GstBuffer *buffer) { VO_SINK(base); return sink->delegate->render(buffer); } +#else +GstFlowReturn QVideoSurfaceGstSink::preroll(GstBaseSink *base, GstBuffer *buffer) +{ + VO_SINK(base); + gboolean showPrerollFrame = true; + g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, NULL); + + if (showPrerollFrame) + return sink->delegate->render(buffer); + + return GST_FLOW_OK; +} + +GstFlowReturn QVideoSurfaceGstSink::render(GstBaseSink *base, GstBuffer *buffer) +{ + VO_SINK(base); + return sink->delegate->render(buffer); +} +#endif QT_END_NAMESPACE 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 diff --git a/src/multimediawidgets/doc/qtmultimediawidgets.qdocconf b/src/multimediawidgets/doc/qtmultimediawidgets.qdocconf index 19e956a0e..4d36dae89 100644 --- a/src/multimediawidgets/doc/qtmultimediawidgets.qdocconf +++ b/src/multimediawidgets/doc/qtmultimediawidgets.qdocconf @@ -28,7 +28,7 @@ exampledirs += ../../../examples/multimediawidgets \ snippets # Specify example install dir under QT_INSTALL_EXAMPLES -examplesinstallpath = multimediawidgets +examplesinstallpath = qtmultimedia/multimediawidgets headerdirs += ../ diff --git a/src/plugins/android/src/common/qandroidmultimediautils.cpp b/src/plugins/android/src/common/qandroidmultimediautils.cpp index a41cc0e1b..9255db549 100644 --- a/src/plugins/android/src/common/qandroidmultimediautils.cpp +++ b/src/plugins/android/src/common/qandroidmultimediautils.cpp @@ -68,564 +68,5 @@ bool qt_sizeLessThan(const QSize &s1, const QSize &s2) return s1.width() * s1.height() < s2.width() * s2.height(); } -// Pre-computed Y coefficients for all possible y values (0-255). Stored as fixed-point (16:16) -// Y = 1.164 * (y - 16) -static const int coefficientsY[256] = { - -593888, -555746, -517604, -479462, -441320, -403178, -365036, -326894, -288752, -250610, - -212468, -174326, -136184, -98042, -59900, -21758, 16384, 54526, 92668, 130810, - 168952, 207094, 245236, 283378, 321520, 359662, 397804, 435946, 474088, 512230, - 550372, 588514, 626656, 664798, 702940, 741082, 779224, 817366, 855508, 893650, - 931792, 969934, 1008076, 1046218, 1084360, 1122502, 1160644, 1198786, 1236928, 1275070, - 1313212, 1351354, 1389496, 1427638, 1465780, 1503922, 1542064, 1580206, 1618348, 1656490, - 1694632, 1732774, 1770916, 1809058, 1847200, 1885342, 1923484, 1961626, 1999768, 2037910, - 2076052, 2114194, 2152336, 2190478, 2228620, 2266762, 2304904, 2343046, 2381188, 2419330, - 2457472, 2495614, 2533756, 2571898, 2610040, 2648182, 2686324, 2724466, 2762608, 2800750, - 2838892, 2877034, 2915176, 2953318, 2991460, 3029602, 3067744, 3105886, 3144028, 3182170, - 3220312, 3258454, 3296596, 3334738, 3372880, 3411022, 3449164, 3487306, 3525448, 3563590, - 3601732, 3639874, 3678016, 3716158, 3754300, 3792442, 3830584, 3868726, 3906868, 3945010, - 3983152, 4021294, 4059436, 4097578, 4135720, 4173862, 4212004, 4250146, 4288288, 4326430, - 4364572, 4402714, 4440856, 4478998, 4517140, 4555282, 4593424, 4631566, 4669708, 4707850, - 4745992, 4784134, 4822276, 4860418, 4898560, 4936702, 4974844, 5012986, 5051128, 5089270, - 5127412, 5165554, 5203696, 5241838, 5279980, 5318122, 5356264, 5394406, 5432548, 5470690, - 5508832, 5546974, 5585116, 5623258, 5661400, 5699542, 5737684, 5775826, 5813968, 5852110, - 5890252, 5928394, 5966536, 6004678, 6042820, 6080962, 6119104, 6157246, 6195388, 6233530, - 6271672, 6309814, 6347956, 6386098, 6424240, 6462382, 6500524, 6538666, 6576808, 6614950, - 6653092, 6691234, 6729376, 6767518, 6805660, 6843802, 6881944, 6920086, 6958228, 6996370, - 7034512, 7072654, 7110796, 7148938, 7187080, 7225222, 7263364, 7301506, 7339648, 7377790, - 7415932, 7454074, 7492216, 7530358, 7568500, 7606642, 7644784, 7682926, 7721068, 7759210, - 7797352, 7835494, 7873636, 7911778, 7949920, 7988062, 8026204, 8064346, 8102488, 8140630, - 8178772, 8216914, 8255056, 8293198, 8331340, 8369482, 8407624, 8445766, 8483908, 8522050, - 8560192, 8598334, 8636476, 8674618, 8712760, 8750902, 8789044, 8827186, 8865328, 8903470, - 8941612, 8979754, 9017896, 9056038, 9094180, 9132322 -}; - -// V lookup table for the Red component. Stored as fixed-point (16:16). -// V = 1.596 * (v - 128) -static const int coefficientsRV[256] = { - -6694144, -6641846, -6589548, -6537250, -6484952, -6432654, -6380356, -6328058, -6275760, - -6223462, -6171164, -6118866, -6066568, -6014270, -5961972, -5909674, -5857376, -5805078, - -5752780, -5700482, -5648184, -5595886, -5543588, -5491290, -5438992, -5386694, -5334396, - -5282098, -5229800, -5177502, -5125204, -5072906, -5020608, -4968310, -4916012, -4863714, - -4811416, -4759118, -4706820, -4654522, -4602224, -4549926, -4497628, -4445330, -4393032, - -4340734, -4288436, -4236138, -4183840, -4131542, -4079244, -4026946, -3974648, -3922350, - -3870052, -3817754, -3765456, -3713158, -3660860, -3608562, -3556264, -3503966, -3451668, - -3399370, -3347072, -3294774, -3242476, -3190178, -3137880, -3085582, -3033284, -2980986, - -2928688, -2876390, -2824092, -2771794, -2719496, -2667198, -2614900, -2562602, -2510304, - -2458006, -2405708, -2353410, -2301112, -2248814, -2196516, -2144218, -2091920, -2039622, - -1987324, -1935026, -1882728, -1830430, -1778132, -1725834, -1673536, -1621238, -1568940, - -1516642, -1464344, -1412046, -1359748, -1307450, -1255152, -1202854, -1150556, -1098258, - -1045960, -993662, -941364, -889066, -836768, -784470, -732172, -679874, -627576, - -575278, -522980, -470682, -418384, -366086, -313788, -261490, -209192, -156894, - -104596, -52298, 0, 52298, 104596, 156894, 209192, 261490, 313788, - 366086, 418384, 470682, 522980, 575278, 627576, 679874, 732172, 784470, - 836768, 889066, 941364, 993662, 1045960, 1098258, 1150556, 1202854, 1255152, - 1307450, 1359748, 1412046, 1464344, 1516642, 1568940, 1621238, 1673536, 1725834, - 1778132, 1830430, 1882728, 1935026, 1987324, 2039622, 2091920, 2144218, 2196516, - 2248814, 2301112, 2353410, 2405708, 2458006, 2510304, 2562602, 2614900, 2667198, - 2719496, 2771794, 2824092, 2876390, 2928688, 2980986, 3033284, 3085582, 3137880, - 3190178, 3242476, 3294774, 3347072, 3399370, 3451668, 3503966, 3556264, 3608562, - 3660860, 3713158, 3765456, 3817754, 3870052, 3922350, 3974648, 4026946, 4079244, - 4131542, 4183840, 4236138, 4288436, 4340734, 4393032, 4445330, 4497628, 4549926, - 4602224, 4654522, 4706820, 4759118, 4811416, 4863714, 4916012, 4968310, 5020608, - 5072906, 5125204, 5177502, 5229800, 5282098, 5334396, 5386694, 5438992, 5491290, - 5543588, 5595886, 5648184, 5700482, 5752780, 5805078, 5857376, 5909674, 5961972, - 6014270, 6066568, 6118866, 6171164, 6223462, 6275760, 6328058, 6380356, 6432654, - 6484952, 6537250, 6589548, 6641846 -}; - -// U lookup table for the Green component. Stored as fixed-point (16:16). -// U = 0.391 * (u - 128) -static const int coefficientsGU[256] = { - 1639936, 1627124, 1614312, 1601500, 1588688, 1575876, 1563064, 1550252, 1537440, - 1524628, 1511816, 1499004, 1486192, 1473380, 1460568, 1447756, 1434944, 1422132, - 1409320, 1396508, 1383696, 1370884, 1358072, 1345260, 1332448, 1319636, 1306824, - 1294012, 1281200, 1268388, 1255576, 1242764, 1229952, 1217140, 1204328, 1191516, - 1178704, 1165892, 1153080, 1140268, 1127456, 1114644, 1101832, 1089020, 1076208, - 1063396, 1050584, 1037772, 1024960, 1012148, 999336, 986524, 973712, 960900, - 948088, 935276, 922464, 909652, 896840, 884028, 871216, 858404, 845592, - 832780, 819968, 807156, 794344, 781532, 768720, 755908, 743096, 730284, - 717472, 704660, 691848, 679036, 666224, 653412, 640600, 627788, 614976, - 602164, 589352, 576540, 563728, 550916, 538104, 525292, 512480, 499668, - 486856, 474044, 461232, 448420, 435608, 422796, 409984, 397172, 384360, - 371548, 358736, 345924, 333112, 320300, 307488, 294676, 281864, 269052, - 256240, 243428, 230616, 217804, 204992, 192180, 179368, 166556, 153744, - 140932, 128120, 115308, 102496, 89684, 76872, 64060, 51248, 38436, - 25624, 12812, 0, -12812, -25624, -38436, -51248, -64060, -76872, - -89684, -102496, -115308, -128120, -140932, -153744, -166556, -179368, -192180, - -204992, -217804, -230616, -243428, -256240, -269052, -281864, -294676, -307488, - -320300, -333112, -345924, -358736, -371548, -384360, -397172, -409984, -422796, - -435608, -448420, -461232, -474044, -486856, -499668, -512480, -525292, -538104, - -550916, -563728, -576540, -589352, -602164, -614976, -627788, -640600, -653412, - -666224, -679036, -691848, -704660, -717472, -730284, -743096, -755908, -768720, - -781532, -794344, -807156, -819968, -832780, -845592, -858404, -871216, -884028, - -896840, -909652, -922464, -935276, -948088, -960900, -973712, -986524, -999336, - -1012148, -1024960, -1037772, -1050584, -1063396, -1076208, -1089020, -1101832, -1114644, - -1127456, -1140268, -1153080, -1165892, -1178704, -1191516, -1204328, -1217140, -1229952, - -1242764, -1255576, -1268388, -1281200, -1294012, -1306824, -1319636, -1332448, -1345260, - -1358072, -1370884, -1383696, -1396508, -1409320, -1422132, -1434944, -1447756, -1460568, - -1473380, -1486192, -1499004, -1511816, -1524628, -1537440, -1550252, -1563064, -1575876, - -1588688, -1601500, -1614312, -1627124 -}; - -// V lookup table for the Green component. Stored as fixed-point (16:16). -// V = 0.813 * (v - 128) -static const int coefficientsGV[256] = { - 3409920, 3383280, 3356640, 3330000, 3303360, 3276720, 3250080, 3223440, 3196800, - 3170160, 3143520, 3116880, 3090240, 3063600, 3036960, 3010320, 2983680, 2957040, - 2930400, 2903760, 2877120, 2850480, 2823840, 2797200, 2770560, 2743920, 2717280, - 2690640, 2664000, 2637360, 2610720, 2584080, 2557440, 2530800, 2504160, 2477520, - 2450880, 2424240, 2397600, 2370960, 2344320, 2317680, 2291040, 2264400, 2237760, - 2211120, 2184480, 2157840, 2131200, 2104560, 2077920, 2051280, 2024640, 1998000, - 1971360, 1944720, 1918080, 1891440, 1864800, 1838160, 1811520, 1784880, 1758240, - 1731600, 1704960, 1678320, 1651680, 1625040, 1598400, 1571760, 1545120, 1518480, - 1491840, 1465200, 1438560, 1411920, 1385280, 1358640, 1332000, 1305360, 1278720, - 1252080, 1225440, 1198800, 1172160, 1145520, 1118880, 1092240, 1065600, 1038960, - 1012320, 985680, 959040, 932400, 905760, 879120, 852480, 825840, 799200, - 772560, 745920, 719280, 692640, 666000, 639360, 612720, 586080, 559440, - 532800, 506160, 479520, 452880, 426240, 399600, 372960, 346320, 319680, - 293040, 266400, 239760, 213120, 186480, 159840, 133200, 106560, 79920, - 53280, 26640, 0, -26640, -53280, -79920, -106560, -133200, -159840, - -186480, -213120, -239760, -266400, -293040, -319680, -346320, -372960, -399600, - -426240, -452880, -479520, -506160, -532800, -559440, -586080, -612720, -639360, - -666000, -692640, -719280, -745920, -772560, -799200, -825840, -852480, -879120, - -905760, -932400, -959040, -985680, -1012320, -1038960, -1065600, -1092240, -1118880, - -1145520, -1172160, -1198800, -1225440, -1252080, -1278720, -1305360, -1332000, -1358640, - -1385280, -1411920, -1438560, -1465200, -1491840, -1518480, -1545120, -1571760, -1598400, - -1625040, -1651680, -1678320, -1704960, -1731600, -1758240, -1784880, -1811520, -1838160, - -1864800, -1891440, -1918080, -1944720, -1971360, -1998000, -2024640, -2051280, -2077920, - -2104560, -2131200, -2157840, -2184480, -2211120, -2237760, -2264400, -2291040, -2317680, - -2344320, -2370960, -2397600, -2424240, -2450880, -2477520, -2504160, -2530800, -2557440, - -2584080, -2610720, -2637360, -2664000, -2690640, -2717280, -2743920, -2770560, -2797200, - -2823840, -2850480, -2877120, -2903760, -2930400, -2957040, -2983680, -3010320, -3036960, - -3063600, -3090240, -3116880, -3143520, -3170160, -3196800, -3223440, -3250080, -3276720, - -3303360, -3330000, -3356640, -3383280 -}; - -// U lookup table for the Blue component. Stored as fixed-point (16:16). -// U = 2.018 * (u - 128) -static const int coefficientsBU[256] = { - -8464128, -8398002, -8331876, -8265750, -8199624, -8133498, -8067372, -8001246, -7935120, - -7868994, -7802868, -7736742, -7670616, -7604490, -7538364, -7472238, -7406112, -7339986, - -7273860, -7207734, -7141608, -7075482, -7009356, -6943230, -6877104, -6810978, -6744852, - -6678726, -6612600, -6546474, -6480348, -6414222, -6348096, -6281970, -6215844, -6149718, - -6083592, -6017466, -5951340, -5885214, -5819088, -5752962, -5686836, -5620710, -5554584, - -5488458, -5422332, -5356206, -5290080, -5223954, -5157828, -5091702, -5025576, -4959450, - -4893324, -4827198, -4761072, -4694946, -4628820, -4562694, -4496568, -4430442, -4364316, - -4298190, -4232064, -4165938, -4099812, -4033686, -3967560, -3901434, -3835308, -3769182, - -3703056, -3636930, -3570804, -3504678, -3438552, -3372426, -3306300, -3240174, -3174048, - -3107922, -3041796, -2975670, -2909544, -2843418, -2777292, -2711166, -2645040, -2578914, - -2512788, -2446662, -2380536, -2314410, -2248284, -2182158, -2116032, -2049906, -1983780, - -1917654, -1851528, -1785402, -1719276, -1653150, -1587024, -1520898, -1454772, -1388646, - -1322520, -1256394, -1190268, -1124142, -1058016, -991890, -925764, -859638, -793512, - -727386, -661260, -595134, -529008, -462882, -396756, -330630, -264504, -198378, - -132252, -66126, 0, 66126, 132252, 198378, 264504, 330630, 396756, - 462882, 529008, 595134, 661260, 727386, 793512, 859638, 925764, 991890, - 1058016, 1124142, 1190268, 1256394, 1322520, 1388646, 1454772, 1520898, 1587024, - 1653150, 1719276, 1785402, 1851528, 1917654, 1983780, 2049906, 2116032, 2182158, - 2248284, 2314410, 2380536, 2446662, 2512788, 2578914, 2645040, 2711166, 2777292, - 2843418, 2909544, 2975670, 3041796, 3107922, 3174048, 3240174, 3306300, 3372426, - 3438552, 3504678, 3570804, 3636930, 3703056, 3769182, 3835308, 3901434, 3967560, - 4033686, 4099812, 4165938, 4232064, 4298190, 4364316, 4430442, 4496568, 4562694, - 4628820, 4694946, 4761072, 4827198, 4893324, 4959450, 5025576, 5091702, 5157828, - 5223954, 5290080, 5356206, 5422332, 5488458, 5554584, 5620710, 5686836, 5752962, - 5819088, 5885214, 5951340, 6017466, 6083592, 6149718, 6215844, 6281970, 6348096, - 6414222, 6480348, 6546474, 6612600, 6678726, 6744852, 6810978, 6877104, 6943230, - 7009356, 7075482, 7141608, 7207734, 7273860, 7339986, 7406112, 7472238, 7538364, - 7604490, 7670616, 7736742, 7802868, 7868994, 7935120, 8001246, 8067372, 8133498, - 8199624, 8265750, 8331876, 8398002 -}; - -// R = min(max(r, 0), 255) << 16 -// where 'r' is the converted red component from YUV, which is always in the range -320 <= r < 704 -// and needs to be clamped to 0-255. It also precomputes the bitshift needed to create an RGB value. -static const quint32 _clampedR[1024] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 65536, 131072, 196608, 262144, 327680, 393216, 458752, - 524288, 589824, 655360, 720896, 786432, 851968, 917504, 983040, - 1048576, 1114112, 1179648, 1245184, 1310720, 1376256, 1441792, 1507328, - 1572864, 1638400, 1703936, 1769472, 1835008, 1900544, 1966080, 2031616, - 2097152, 2162688, 2228224, 2293760, 2359296, 2424832, 2490368, 2555904, - 2621440, 2686976, 2752512, 2818048, 2883584, 2949120, 3014656, 3080192, - 3145728, 3211264, 3276800, 3342336, 3407872, 3473408, 3538944, 3604480, - 3670016, 3735552, 3801088, 3866624, 3932160, 3997696, 4063232, 4128768, - 4194304, 4259840, 4325376, 4390912, 4456448, 4521984, 4587520, 4653056, - 4718592, 4784128, 4849664, 4915200, 4980736, 5046272, 5111808, 5177344, - 5242880, 5308416, 5373952, 5439488, 5505024, 5570560, 5636096, 5701632, - 5767168, 5832704, 5898240, 5963776, 6029312, 6094848, 6160384, 6225920, - 6291456, 6356992, 6422528, 6488064, 6553600, 6619136, 6684672, 6750208, - 6815744, 6881280, 6946816, 7012352, 7077888, 7143424, 7208960, 7274496, - 7340032, 7405568, 7471104, 7536640, 7602176, 7667712, 7733248, 7798784, - 7864320, 7929856, 7995392, 8060928, 8126464, 8192000, 8257536, 8323072, - 8388608, 8454144, 8519680, 8585216, 8650752, 8716288, 8781824, 8847360, - 8912896, 8978432, 9043968, 9109504, 9175040, 9240576, 9306112, 9371648, - 9437184, 9502720, 9568256, 9633792, 9699328, 9764864, 9830400, 9895936, - 9961472, 10027008, 10092544, 10158080, 10223616, 10289152, 10354688, 10420224, - 10485760, 10551296, 10616832, 10682368, 10747904, 10813440, 10878976, 10944512, - 11010048, 11075584, 11141120, 11206656, 11272192, 11337728, 11403264, 11468800, - 11534336, 11599872, 11665408, 11730944, 11796480, 11862016, 11927552, 11993088, - 12058624, 12124160, 12189696, 12255232, 12320768, 12386304, 12451840, 12517376, - 12582912, 12648448, 12713984, 12779520, 12845056, 12910592, 12976128, 13041664, - 13107200, 13172736, 13238272, 13303808, 13369344, 13434880, 13500416, 13565952, - 13631488, 13697024, 13762560, 13828096, 13893632, 13959168, 14024704, 14090240, - 14155776, 14221312, 14286848, 14352384, 14417920, 14483456, 14548992, 14614528, - 14680064, 14745600, 14811136, 14876672, 14942208, 15007744, 15073280, 15138816, - 15204352, 15269888, 15335424, 15400960, 15466496, 15532032, 15597568, 15663104, - 15728640, 15794176, 15859712, 15925248, 15990784, 16056320, 16121856, 16187392, - 16252928, 16318464, 16384000, 16449536, 16515072, 16580608, 16646144, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, - 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680 -}; - -// G = min(max(g, 0), 255) << 8 -// where 'g' is the converted green component from YUV, which is always in the range -320 <= r < 704 -// and needs to be clamped to 0-255. It also precomputes the bitshift needed to create an RGB value. -static const quint32 _clampedG[1024] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 256, 512, 768, 1024, 1280, 1536, 1792, - 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840, - 4096, 4352, 4608, 4864, 5120, 5376, 5632, 5888, - 6144, 6400, 6656, 6912, 7168, 7424, 7680, 7936, - 8192, 8448, 8704, 8960, 9216, 9472, 9728, 9984, - 10240, 10496, 10752, 11008, 11264, 11520, 11776, 12032, - 12288, 12544, 12800, 13056, 13312, 13568, 13824, 14080, - 14336, 14592, 14848, 15104, 15360, 15616, 15872, 16128, - 16384, 16640, 16896, 17152, 17408, 17664, 17920, 18176, - 18432, 18688, 18944, 19200, 19456, 19712, 19968, 20224, - 20480, 20736, 20992, 21248, 21504, 21760, 22016, 22272, - 22528, 22784, 23040, 23296, 23552, 23808, 24064, 24320, - 24576, 24832, 25088, 25344, 25600, 25856, 26112, 26368, - 26624, 26880, 27136, 27392, 27648, 27904, 28160, 28416, - 28672, 28928, 29184, 29440, 29696, 29952, 30208, 30464, - 30720, 30976, 31232, 31488, 31744, 32000, 32256, 32512, - 32768, 33024, 33280, 33536, 33792, 34048, 34304, 34560, - 34816, 35072, 35328, 35584, 35840, 36096, 36352, 36608, - 36864, 37120, 37376, 37632, 37888, 38144, 38400, 38656, - 38912, 39168, 39424, 39680, 39936, 40192, 40448, 40704, - 40960, 41216, 41472, 41728, 41984, 42240, 42496, 42752, - 43008, 43264, 43520, 43776, 44032, 44288, 44544, 44800, - 45056, 45312, 45568, 45824, 46080, 46336, 46592, 46848, - 47104, 47360, 47616, 47872, 48128, 48384, 48640, 48896, - 49152, 49408, 49664, 49920, 50176, 50432, 50688, 50944, - 51200, 51456, 51712, 51968, 52224, 52480, 52736, 52992, - 53248, 53504, 53760, 54016, 54272, 54528, 54784, 55040, - 55296, 55552, 55808, 56064, 56320, 56576, 56832, 57088, - 57344, 57600, 57856, 58112, 58368, 58624, 58880, 59136, - 59392, 59648, 59904, 60160, 60416, 60672, 60928, 61184, - 61440, 61696, 61952, 62208, 62464, 62720, 62976, 63232, - 63488, 63744, 64000, 64256, 64512, 64768, 65024, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280, - 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280 -}; - -// B = min(max(b, 0), 255) -// where 'b' is the converted blue component from YUV, which is always in the range -320 <= r < 704 -static const quint32 _clampedB[1024] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 -}; - -static const quint32 *clampedR = _clampedR + 320; -static const quint32 *clampedG = _clampedG + 320; -static const quint32 *clampedB = _clampedB + 320; - -#define MAKE_RGB(r, g, b) 0xff000000 | clampedR[r] | clampedG[g] | clampedB[b] - -void qt_convert_NV21_to_ARGB32(const uchar *yuv, quint32 *rgb, int width, int height) -{ - const uchar *y0 = yuv; - const uchar *y1 = yuv + width; - const uchar *vu = yuv + width * height; - - quint32 *rgb0 = rgb; - quint32 *rgb1 = rgb + width; - - for (int i = 0; i < height; i += 2) { - for (int j = 0; j < width; j += 2) { - int v = *vu++; - int u = *vu++; - - int ruv = coefficientsRV[v] >> 15; - int guv = (coefficientsGU[u] + coefficientsGV[v]) >> 15; - int buv = coefficientsBU[u] >> 15; - - int y = coefficientsY[*y0++] >> 15; - int r = y + ruv; - int g = y + guv; - int b = y + buv; - *rgb0++ = MAKE_RGB(r, g, b); - - y = coefficientsY[*y0++] >> 15; - r = y + ruv; - g = y + guv; - b = y + buv; - *rgb0++ = MAKE_RGB(r, g, b); - - y = coefficientsY[*y1++] >> 15; - r = y + ruv; - g = y + guv; - b = y + buv; - *rgb1++ = MAKE_RGB(r, g, b); - - y = coefficientsY[*y1++] >> 15; - r = y + ruv; - g = y + guv; - b = y + buv; - *rgb1++ = MAKE_RGB(r, g, b); - } - - rgb0 += width; - rgb1 += width; - y0 += width; - y1 += width; - } -} QT_END_NAMESPACE diff --git a/src/plugins/android/src/common/qandroidmultimediautils.h b/src/plugins/android/src/common/qandroidmultimediautils.h index ea6a322e7..6955c49e9 100644 --- a/src/plugins/android/src/common/qandroidmultimediautils.h +++ b/src/plugins/android/src/common/qandroidmultimediautils.h @@ -45,7 +45,6 @@ int qt_findClosestValue(const QList<int> &list, int value); bool qt_sizeLessThan(const QSize &s1, const QSize &s2); -void qt_convert_NV21_to_ARGB32(const uchar *yuv, quint32 *rgb, int width, int height); QT_END_NAMESPACE diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index 179bcdf96..cf1879eb1 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -43,6 +43,8 @@ #include <qguiapplication.h> #include <qdebug.h> #include <qvideoframe.h> +#include <private/qmemoryvideobuffer_p.h> +#include <private/qvideoframe_p.h> QT_BEGIN_NAMESPACE @@ -582,11 +584,10 @@ void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data, QImage QAndroidCameraSession::prepareImageFromPreviewData(const QByteArray &data, int width, int height, int rotation) { - QImage result(width, height, QImage::Format_ARGB32); - qt_convert_NV21_to_ARGB32((const uchar *)data.constData(), - (quint32 *)result.bits(), - width, - height); + QVideoFrame frame(new QMemoryVideoBuffer(data, width), + QSize(width, height), QVideoFrame::Format_NV21); + + QImage result = qt_imageFromVideoFrame(frame); QTransform transform; diff --git a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm index 924c62d97..705ec633f 100644 --- a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm +++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm @@ -174,7 +174,7 @@ public: GL_RGBA, CVPixelBufferGetWidth(m_buffer), CVPixelBufferGetHeight(m_buffer), - GL_BGRA, + GL_RGBA, GL_UNSIGNED_BYTE, 0, &m_texture); @@ -240,18 +240,8 @@ private: int width = CVPixelBufferGetWidth(imageBuffer); int height = CVPixelBufferGetHeight(imageBuffer); - QVideoFrame::PixelFormat format; - -#ifdef Q_OS_IOS - bool useTexture = m_renderer->supportsTextures() - && CVPixelBufferGetPixelFormatType(imageBuffer) == kCVPixelFormatType_32BGRA; - - if (useTexture) - format = QVideoFrame::Format_BGRA32; - else -#endif - format = AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat(CVPixelBufferGetPixelFormatType(imageBuffer)); - + QVideoFrame::PixelFormat format = + AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat(CVPixelBufferGetPixelFormatType(imageBuffer)); if (format == QVideoFrame::Format_Invalid) return; diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h index 2b322cfaf..838234522 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.h +++ b/src/plugins/avfoundation/camera/avfcamerasession.h @@ -70,6 +70,7 @@ public: static int defaultCameraIndex(); static const QList<AVFCameraInfo> &availableCameraDevices(); static AVFCameraInfo cameraDeviceInfo(const QByteArray &device); + AVFCameraInfo activeCameraInfo() const { return m_activeCameraInfo; } void setVideoOutput(AVFCameraRendererControl *output); AVCaptureSession *captureSession() const { return m_captureSession; } @@ -93,10 +94,12 @@ public Q_SLOTS: void processSessionStopped(); void onCameraFrameFetched(const QVideoFrame &frame); + Q_SIGNALS: void readyToConfigureConnections(); void stateChanged(QCamera::State newState); void activeChanged(bool); + void newViewfinderFrame(const QVideoFrame &frame); void error(int error, const QString &errorString); private: @@ -107,6 +110,7 @@ private: static int m_defaultCameraIndex; static QList<AVFCameraInfo> m_cameraDevices; + AVFCameraInfo m_activeCameraInfo; AVFCameraService *m_service; AVFCameraRendererControl *m_videoOutput; diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm index 83f8c0ed3..66dc43d81 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.mm +++ b/src/plugins/avfoundation/camera/avfcamerasession.mm @@ -333,6 +333,7 @@ void AVFCameraSession::attachVideoInputDevice() [m_captureSession removeInput:m_videoInput]; [m_videoInput release]; m_videoInput = 0; + m_activeCameraInfo = AVFCameraInfo(); } AVCaptureDevice *videoDevice = m_service->videoDeviceControl()->createCaptureDevice(); @@ -346,6 +347,7 @@ void AVFCameraSession::attachVideoInputDevice() qWarning() << "Failed to create video device input"; } else { if ([m_captureSession canAddInput:m_videoInput]) { + m_activeCameraInfo = m_cameraDevices.at(m_service->videoDeviceControl()->selectedDevice()); [m_videoInput retain]; [m_captureSession addInput:m_videoInput]; } else { @@ -414,6 +416,8 @@ FourCharCode AVFCameraSession::defaultCodec() void AVFCameraSession::onCameraFrameFetched(const QVideoFrame &frame) { + Q_EMIT newViewfinderFrame(frame); + m_videoProbesMutex.lock(); QSet<AVFMediaVideoProbeControl *>::const_iterator i = m_videoProbes.constBegin(); while (i != m_videoProbes.constEnd()) { diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.h b/src/plugins/avfoundation/camera/avfimagecapturecontrol.h index 993725653..dd5e8e8bb 100644 --- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.h +++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.h @@ -36,19 +36,23 @@ #import <AVFoundation/AVFoundation.h> +#include <QtCore/qqueue.h> +#include <QtCore/qsemaphore.h> #include <QtMultimedia/qcameraimagecapturecontrol.h> +#include "avfcamerasession.h" #include "avfstoragelocation.h" QT_BEGIN_NAMESPACE -class AVFCameraSession; -class AVFCameraService; -class AVFCameraControl; - class AVFImageCaptureControl : public QCameraImageCaptureControl { Q_OBJECT public: + struct CaptureRequest { + int captureId; + QSemaphore *previewReady; + }; + AVFImageCaptureControl(AVFCameraService *service, QObject *parent = 0); ~AVFImageCaptureControl(); @@ -64,8 +68,11 @@ public: private Q_SLOTS: void updateCaptureConnection(); void updateReadyStatus(); + void onNewViewfinderFrame(const QVideoFrame &frame); private: + void makeCapturePreview(CaptureRequest request, const QVideoFrame &frame, int rotation); + AVFCameraSession *m_session; AVFCameraControl *m_cameraControl; bool m_ready; @@ -73,8 +80,13 @@ private: AVCaptureStillImageOutput *m_stillImageOutput; AVCaptureConnection *m_videoConnection; AVFStorageLocation m_storageLocation; + + QMutex m_requestsMutex; + QQueue<CaptureRequest> m_captureRequests; }; +Q_DECLARE_TYPEINFO(AVFImageCaptureControl::CaptureRequest, Q_PRIMITIVE_TYPE); + QT_END_NAMESPACE #endif diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm index c28ccef8e..edaaf8ce3 100644 --- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm +++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm @@ -33,14 +33,15 @@ #include "avfcameradebug.h" #include "avfimagecapturecontrol.h" -#include "avfcamerasession.h" #include "avfcameraservice.h" #include "avfcameracontrol.h" #include <QtCore/qurl.h> #include <QtCore/qfile.h> #include <QtCore/qbuffer.h> +#include <QtConcurrent/qtconcurrentrun.h> #include <QtGui/qimagereader.h> +#include <private/qvideoframe_p.h> QT_USE_NAMESPACE @@ -65,6 +66,10 @@ AVFImageCaptureControl::AVFImageCaptureControl(AVFCameraService *service, QObjec connect(m_cameraControl, SIGNAL(statusChanged(QCamera::Status)), SLOT(updateReadyStatus())); connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(updateCaptureConnection())); + + connect(m_session, &AVFCameraSession::newViewfinderFrame, + this, &AVFImageCaptureControl::onNewViewfinderFrame, + Qt::DirectConnection); } AVFImageCaptureControl::~AVFImageCaptureControl() @@ -106,9 +111,18 @@ int AVFImageCaptureControl::capture(const QString &fileName) qDebugCamera() << "Capture image to" << actualFileName; - int captureId = m_lastCaptureId; + CaptureRequest request = { m_lastCaptureId, new QSemaphore }; + m_requestsMutex.lock(); + m_captureRequests.enqueue(request); + m_requestsMutex.unlock(); + [m_stillImageOutput captureStillImageAsynchronouslyFromConnection:m_videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { + + // Wait for the preview to be generated before saving the JPEG + request.previewReady->acquire(); + delete request.previewReady; + if (error) { QStringList messageParts; messageParts << QString::fromUtf8([[error localizedDescription] UTF8String]); @@ -119,64 +133,66 @@ int AVFImageCaptureControl::capture(const QString &fileName) qDebugCamera() << "Image capture failed:" << errorMessage; QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, - Q_ARG(int, captureId), + Q_ARG(int, request.captureId), Q_ARG(int, QCameraImageCapture::ResourceError), Q_ARG(QString, errorMessage)); } else { - qDebugCamera() << "Image captured:" << actualFileName; - //we can't find the exact time the image is exposed, - //but image capture is very fast on desktop, so emit it here - QMetaObject::invokeMethod(this, "imageExposed", Qt::QueuedConnection, - Q_ARG(int, captureId)); + qDebugCamera() << "Image capture completed:" << actualFileName; NSData *nsJpgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; QByteArray jpgData = QByteArray::fromRawData((const char *)[nsJpgData bytes], [nsJpgData length]); - //Generate snap preview as downscalled image - { - QBuffer buffer(&jpgData); - QImageReader imageReader(&buffer); - QSize imgSize = imageReader.size(); - int downScaleSteps = 0; - while (imgSize.width() > 800 && downScaleSteps < 8) { - imgSize.rwidth() /= 2; - imgSize.rheight() /= 2; - downScaleSteps++; - } - - imageReader.setScaledSize(imgSize); - QImage snapPreview = imageReader.read(); - - QMetaObject::invokeMethod(this, "imageCaptured", Qt::QueuedConnection, - Q_ARG(int, captureId), - Q_ARG(QImage, snapPreview)); - } - - qDebugCamera() << "Image captured" << actualFileName; - QFile f(actualFileName); if (f.open(QFile::WriteOnly)) { if (f.write(jpgData) != -1) { QMetaObject::invokeMethod(this, "imageSaved", Qt::QueuedConnection, - Q_ARG(int, captureId), + Q_ARG(int, request.captureId), Q_ARG(QString, actualFileName)); } else { QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, - Q_ARG(int, captureId), + Q_ARG(int, request.captureId), Q_ARG(int, QCameraImageCapture::OutOfSpaceError), Q_ARG(QString, f.errorString())); } } else { QString errorMessage = tr("Could not open destination file:\n%1").arg(actualFileName); QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, - Q_ARG(int, captureId), + Q_ARG(int, request.captureId), Q_ARG(int, QCameraImageCapture::ResourceError), Q_ARG(QString, errorMessage)); } } }]; - return captureId; + return request.captureId; +} + +void AVFImageCaptureControl::onNewViewfinderFrame(const QVideoFrame &frame) +{ + QMutexLocker locker(&m_requestsMutex); + + if (m_captureRequests.isEmpty()) + return; + + CaptureRequest request = m_captureRequests.dequeue(); + Q_EMIT imageExposed(request.captureId); + + QtConcurrent::run(this, &AVFImageCaptureControl::makeCapturePreview, + request, + frame, + 0 /* rotation */); +} + +void AVFImageCaptureControl::makeCapturePreview(CaptureRequest request, + const QVideoFrame &frame, + int rotation) +{ + QTransform transform; + transform.rotate(rotation); + + Q_EMIT imageCaptured(request.captureId, qt_imageFromVideoFrame(frame).transformed(transform)); + + request.previewReady->release(); } void AVFImageCaptureControl::cancelCapture() diff --git a/src/plugins/directshow/player/directshowplayercontrol.cpp b/src/plugins/directshow/player/directshowplayercontrol.cpp index a5fed4b95..e988cbdd3 100644 --- a/src/plugins/directshow/player/directshowplayercontrol.cpp +++ b/src/plugins/directshow/player/directshowplayercontrol.cpp @@ -73,7 +73,8 @@ DirectShowPlayerControl::DirectShowPlayerControl(DirectShowPlayerService *servic , m_status(QMediaPlayer::NoMedia) , m_error(QMediaPlayer::NoError) , m_streamTypes(0) - , m_muteVolume(-1) + , m_volume(100) + , m_muted(false) , m_position(0) , m_pendingPosition(-1) , m_duration(0) @@ -113,6 +114,11 @@ qint64 DirectShowPlayerControl::position() const void DirectShowPlayerControl::setPosition(qint64 position) { + if (m_status == QMediaPlayer::EndOfMedia) { + m_status = QMediaPlayer::LoadedMedia; + emit mediaStatusChanged(m_status); + } + if (m_state == QMediaPlayer::StoppedState && m_pendingPosition != position) { m_pendingPosition = position; emit positionChanged(m_pendingPosition); @@ -125,63 +131,47 @@ void DirectShowPlayerControl::setPosition(qint64 position) int DirectShowPlayerControl::volume() const { - if (m_muteVolume >= 0) { - return m_muteVolume; - } else if (m_audio) { - long dB = 0; - - m_audio->get_Volume(&dB); - - return decibelsToVolume(dB); - } else { - return 0; - } + return m_volume; } void DirectShowPlayerControl::setVolume(int volume) { int boundedVolume = qBound(0, volume, 100); - if (m_muteVolume >= 0) { - m_muteVolume = boundedVolume; + if (m_volume == boundedVolume) + return; + + m_volume = boundedVolume; - emit volumeChanged(m_muteVolume); - } else if (m_audio) { - m_audio->put_Volume(volumeToDecibels(volume)); + if (!m_muted) + setVolumeHelper(m_volume); - emit volumeChanged(boundedVolume); - } + emit volumeChanged(m_volume); } bool DirectShowPlayerControl::isMuted() const { - return m_muteVolume >= 0; + return m_muted; } void DirectShowPlayerControl::setMuted(bool muted) { - if (muted && m_muteVolume < 0) { - if (m_audio) { - long dB = 0; + if (m_muted == muted) + return; - m_audio->get_Volume(&dB); + m_muted = muted; - m_muteVolume = decibelsToVolume(dB); + setVolumeHelper(m_muted ? 0 : m_volume); - m_audio->put_Volume(-10000); - } else { - m_muteVolume = 0; - } + emit mutedChanged(m_muted); +} - emit mutedChanged(muted); - } else if (!muted && m_muteVolume >= 0) { - if (m_audio) { - m_audio->put_Volume(volumeToDecibels(m_muteVolume)); - } - m_muteVolume = -1; +void DirectShowPlayerControl::setVolumeHelper(int volume) +{ + if (!m_audio) + return; - emit mutedChanged(muted); - } + m_audio->put_Volume(volumeToDecibels(volume)); } int DirectShowPlayerControl::bufferStatus() const @@ -235,6 +225,8 @@ const QIODevice *DirectShowPlayerControl::mediaStream() const void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream) { + m_pendingPosition = -1; + m_media = media; m_stream = stream; @@ -248,30 +240,35 @@ void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *st void DirectShowPlayerControl::play() { - if (m_status == QMediaPlayer::NoMedia) - return; - if (m_status == QMediaPlayer::InvalidMedia) { - setMedia(m_media, m_stream); - if (m_error != QMediaPlayer::NoError) - return; - } - m_service->play(); - if (m_pendingPosition != -1) - setPosition(m_pendingPosition); - emit stateChanged(m_state = QMediaPlayer::PlayingState); + playOrPause(QMediaPlayer::PlayingState); } void DirectShowPlayerControl::pause() { - if (m_status == QMediaPlayer::NoMedia) + playOrPause(QMediaPlayer::PausedState); +} + +void DirectShowPlayerControl::playOrPause(QMediaPlayer::State state) +{ + if (m_status == QMediaPlayer::NoMedia || state == QMediaPlayer::StoppedState) return; if (m_status == QMediaPlayer::InvalidMedia) { setMedia(m_media, m_stream); if (m_error != QMediaPlayer::NoError) return; } - m_service->pause(); - emit stateChanged(m_state = QMediaPlayer::PausedState); + + m_state = state; + + if (m_pendingPosition != -1) + setPosition(m_pendingPosition); + + if (state == QMediaPlayer::PausedState) + m_service->pause(); + else + m_service->play(); + + emit stateChanged(m_state); } void DirectShowPlayerControl::stop() @@ -389,6 +386,7 @@ void DirectShowPlayerControl::updateAudioOutput(IBaseFilter *filter) m_audio->Release(); m_audio = com_cast<IBasicAudio>(filter, IID_IBasicAudio); + setVolumeHelper(m_muted ? 0 : m_volume); } void DirectShowPlayerControl::updateError(QMediaPlayer::Error error, const QString &errorString) diff --git a/src/plugins/directshow/player/directshowplayercontrol.h b/src/plugins/directshow/player/directshowplayercontrol.h index a42d3c7b1..ab842f511 100644 --- a/src/plugins/directshow/player/directshowplayercontrol.h +++ b/src/plugins/directshow/player/directshowplayercontrol.h @@ -114,8 +114,11 @@ private: PropertiesChanged = QEvent::User }; + void playOrPause(QMediaPlayer::State state); + void scheduleUpdate(int properties); void emitPropertyChanges(); + void setVolumeHelper(int volume); DirectShowPlayerService *m_service; IBasicAudio *m_audio; @@ -125,7 +128,8 @@ private: QMediaPlayer::MediaStatus m_status; QMediaPlayer::Error m_error; int m_streamTypes; - int m_muteVolume; + int m_volume; + bool m_muted; qint64 m_position; qint64 m_pendingPosition; qint64 m_duration; diff --git a/src/plugins/directshow/player/directshowplayerservice.cpp b/src/plugins/directshow/player/directshowplayerservice.cpp index 67aea6e9a..b73fa5c4c 100644 --- a/src/plugins/directshow/player/directshowplayerservice.cpp +++ b/src/plugins/directshow/player/directshowplayerservice.cpp @@ -98,6 +98,7 @@ DirectShowPlayerService::DirectShowPlayerService(QObject *parent) , m_videoOutput(0) , m_rate(1.0) , m_position(0) + , m_seekPosition(-1) , m_duration(0) , m_buffering(false) , m_seekable(false) @@ -217,6 +218,7 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream m_error = QMediaPlayer::NoError; m_errorString = QString(); m_position = 0; + m_seekPosition = -1; m_duration = 0; m_streamTypes = 0; m_executedTasks = 0; @@ -665,8 +667,10 @@ void DirectShowPlayerService::play() if (m_executedTasks & Render) { if (m_executedTasks & Stop) { m_atEnd = false; - m_position = 0; - m_pendingTasks |= Seek; + if (m_seekPosition == -1) { + m_seekPosition = 0; + m_pendingTasks |= Seek; + } m_executedTasks ^= Stop; } @@ -709,8 +713,10 @@ void DirectShowPlayerService::pause() if (m_executedTasks & Render) { if (m_executedTasks & Stop) { m_atEnd = false; - m_position = 0; - m_pendingTasks |= Seek; + if (m_seekPosition == -1) { + m_seekPosition = 0; + m_pendingTasks |= Seek; + } m_executedTasks ^= Stop; } @@ -780,7 +786,7 @@ void DirectShowPlayerService::doStop(QMutexLocker *locker) control->Release(); } - m_position = 0; + m_seekPosition = 0; m_pendingTasks |= Seek; m_executedTasks &= ~(Play | Pause); @@ -884,7 +890,7 @@ void DirectShowPlayerService::seek(qint64 position) { QMutexLocker locker(&m_mutex); - m_position = position; + m_seekPosition = position; m_pendingTasks |= Seek; @@ -894,8 +900,11 @@ void DirectShowPlayerService::seek(qint64 position) void DirectShowPlayerService::doSeek(QMutexLocker *locker) { + if (m_seekPosition == -1) + return; + if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) { - LONGLONG seekPosition = LONGLONG(m_position) * qt_directShowTimeScale; + LONGLONG seekPosition = LONGLONG(m_seekPosition) * qt_directShowTimeScale; // Cache current values as we can't query IMediaSeeking during a seek due to the // possibility of a deadlock when flushing the VideoSurfaceFilter. @@ -919,11 +928,11 @@ void DirectShowPlayerService::doSeek(QMutexLocker *locker) m_position = currentPosition / qt_directShowTimeScale; seeking->Release(); - } else { - m_position = 0; + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PositionChange))); } - QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PositionChange))); + m_seekPosition = -1; } int DirectShowPlayerService::bufferStatus() const diff --git a/src/plugins/directshow/player/directshowplayerservice.h b/src/plugins/directshow/player/directshowplayerservice.h index c9d10351e..f4da103dc 100644 --- a/src/plugins/directshow/player/directshowplayerservice.h +++ b/src/plugins/directshow/player/directshowplayerservice.h @@ -194,6 +194,7 @@ private: int m_streamTypes; qreal m_rate; qint64 m_position; + qint64 m_seekPosition; qint64 m_duration; bool m_buffering; bool m_seekable; diff --git a/src/plugins/directshow/player/videosurfacefilter.cpp b/src/plugins/directshow/player/videosurfacefilter.cpp index 2f52e33de..901d2e908 100644 --- a/src/plugins/directshow/player/videosurfacefilter.cpp +++ b/src/plugins/directshow/player/videosurfacefilter.cpp @@ -147,6 +147,14 @@ HRESULT VideoSurfaceFilter::Stop() m_sampleScheduler.stop(); + if (thread() == QThread::currentThread()) { + flush(); + } else { + QMutexLocker locker(&m_mutex); + m_loop->postEvent(this, new QEvent(QEvent::Type(FlushSurface))); + m_wait.wait(&m_mutex); + } + return S_OK; } @@ -606,10 +614,24 @@ void VideoSurfaceFilter::sampleReady() IMediaSample *sample = m_sampleScheduler.takeSample(&eos); if (sample) { - m_surface->present(QVideoFrame( - new MediaSampleVideoBuffer(sample, m_bytesPerLine), - m_surfaceFormat.frameSize(), - m_surfaceFormat.pixelFormat())); + QVideoFrame frame(new MediaSampleVideoBuffer(sample, m_bytesPerLine), + m_surfaceFormat.frameSize(), + m_surfaceFormat.pixelFormat()); + + if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) { + LONGLONG position = 0; + seeking->GetCurrentPosition(&position); + seeking->Release(); + + frame.setStartTime(position * 0.1); + + REFERENCE_TIME startTime = -1; + REFERENCE_TIME endTime = -1; + if (sample->GetTime(&startTime, &endTime) == S_OK) + frame.setEndTime(frame.startTime() + (endTime - startTime) * 0.1); + } + + m_surface->present(frame); sample->Release(); diff --git a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecoderserviceplugin.cpp b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecoderserviceplugin.cpp index 6afee9433..f919bb1f7 100644 --- a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecoderserviceplugin.cpp +++ b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecoderserviceplugin.cpp @@ -70,9 +70,15 @@ QMultimedia::SupportEstimate QGstreamerAudioDecoderServicePlugin::hasSupport(con static bool isDecoderOrDemuxer(GstElementFactory *factory) { +#if GST_CHECK_VERSION(0, 10, 31) return gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_DEMUXER) - || gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_DECODER - | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO); + || gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_DECODER + | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO); +#else + return (factory + && (qstrcmp(factory->details.klass, "Codec/Decoder/Audio") == 0 + || qstrcmp(factory->details.klass, "Codec/Demux") == 0)); +#endif } void QGstreamerAudioDecoderServicePlugin::updateSupportedMimeTypes() const diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.cpp index 0018209c2..fca38ecf8 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.cpp +++ b/src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.cpp @@ -77,9 +77,7 @@ static const QGstreamerMetaDataKeyLookup *qt_gstreamerMetaDataKeys() metadataKeys->insert(QMediaMetaData::AlbumTitle, GST_TAG_ALBUM); metadataKeys->insert(QMediaMetaData::AlbumArtist, GST_TAG_ARTIST); metadataKeys->insert(QMediaMetaData::ContributingArtist, GST_TAG_PERFORMER); -#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19) metadataKeys->insert(QMediaMetaData::Composer, GST_TAG_COMPOSER); -#endif //metadataKeys->insert(QMediaMetaData::Conductor, 0); //metadataKeys->insert(QMediaMetaData::Lyrics, 0); //metadataKeys->insert(QMediaMetaData::Mood, 0); diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp index a9c66f836..8cbdb6717 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp +++ b/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp @@ -113,8 +113,15 @@ QMultimedia::SupportEstimate QGstreamerCaptureServicePlugin::hasSupport(const QS static bool isEncoderOrMuxer(GstElementFactory *factory) { +#if GST_CHECK_VERSION(0, 10, 31) return gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_MUXER) || gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_ENCODER); +#else + return (factory + && (qstrcmp(factory->details.klass, "Codec/Encoder/Audio") == 0 + || qstrcmp(factory->details.klass, "Codec/Encoder/Video") == 0 + || qstrcmp(factory->details.klass, "Codec/Muxer") == 0 )); +#endif } void QGstreamerCaptureServicePlugin::updateSupportedMimeTypes() const diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp index 77d8987f9..31ffa5065 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp +++ b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp @@ -628,12 +628,12 @@ bool QGstreamerCaptureSession::rebuildGraph(QGstreamerCaptureSession::PipelineMo } dumpGraph( QString("rebuild_graph_%1_%2").arg(m_pipelineMode).arg(newMode) ); +#ifdef QT_GST_CAPTURE_DEBUG if (m_encodeBin) { QString fileName = QString("rebuild_graph_encode_%1_%2").arg(m_pipelineMode).arg(newMode); -#if !(GST_DISABLE_GST_DEBUG) && (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19) - _gst_debug_bin_to_dot_file(GST_BIN(m_encodeBin), GST_DEBUG_GRAPH_SHOW_ALL, fileName.toLatin1()); -#endif + GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(m_encodeBin), GST_DEBUG_GRAPH_SHOW_ALL, fileName.toLatin1()); } +#endif if (ok) { addAudioBufferProbe(); @@ -657,12 +657,12 @@ bool QGstreamerCaptureSession::rebuildGraph(QGstreamerCaptureSession::PipelineMo void QGstreamerCaptureSession::dumpGraph(const QString &fileName) { -#if !(GST_DISABLE_GST_DEBUG) && (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19) - _gst_debug_bin_to_dot_file(GST_BIN(m_pipeline), - GstDebugGraphDetails(/*GST_DEBUG_GRAPH_SHOW_ALL |*/ GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES), - fileName.toLatin1()); +#ifdef QT_GST_CAPTURE_DEBUG + GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(m_pipeline), + GstDebugGraphDetails(/*GST_DEBUG_GRAPH_SHOW_ALL |*/ GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES), + fileName.toLatin1()); #else - Q_UNUSED(fileName); + Q_UNUSED(fileName) #endif } diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp b/src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp index ac0fe2a77..fdf43062f 100644 --- a/src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp +++ b/src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp @@ -76,13 +76,10 @@ static const QGstreamerMetaDataKeyLookup *qt_gstreamerMetaDataKeys() // Music metadataKeys->insert(GST_TAG_ALBUM, QMediaMetaData::AlbumTitle); -#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 25) +#if GST_CHECK_VERSION(0, 10, 25) metadataKeys->insert(GST_TAG_ALBUM_ARTIST, QMediaMetaData::AlbumArtist); #endif metadataKeys->insert(GST_TAG_ARTIST, QMediaMetaData::ContributingArtist); -#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19) - metadataKeys->insert(GST_TAG_COMPOSER, QMediaMetaData::Composer); -#endif //metadataKeys->insert(0, QMediaMetaData::Conductor); //metadataKeys->insert(0, QMediaMetaData::Lyrics); //metadataKeys->insert(0, QMediaMetaData::Mood); diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerplayerserviceplugin.cpp b/src/plugins/gstreamer/mediaplayer/qgstreamerplayerserviceplugin.cpp index 004d561ae..b895c4d86 100644 --- a/src/plugins/gstreamer/mediaplayer/qgstreamerplayerserviceplugin.cpp +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerplayerserviceplugin.cpp @@ -83,8 +83,15 @@ QMultimedia::SupportEstimate QGstreamerPlayerServicePlugin::hasSupport(const QSt static bool isDecoderOrDemuxer(GstElementFactory *factory) { +#if GST_CHECK_VERSION(0, 10 ,31) return gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_DEMUXER) || gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_DECODER); +#else + return (factory + && (qstrcmp(factory->details.klass, "Codec/Decoder/Audio") == 0 + || qstrcmp(factory->details.klass, "Codec/Decoder/Video") == 0 + || qstrcmp(factory->details.klass, "Codec/Demux") == 0 )); +#endif } void QGstreamerPlayerServicePlugin::updateSupportedMimeTypes() const diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp b/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp index 4dce34113..c3d20e790 100644 --- a/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp @@ -388,7 +388,7 @@ QMediaTimeRange QGstreamerPlayerSession::availablePlaybackRanges() const if (duration() <= 0) return ranges; -#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 31) +#if GST_CHECK_VERSION(0, 10, 31) //GST_FORMAT_TIME would be more appropriate, but unfortunately it's not supported. //with GST_FORMAT_PERCENT media is treated as encoded with constant bitrate. GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT); @@ -1637,7 +1637,7 @@ void QGstreamerPlayerSession::updateMuted() } } -#if (GST_VERSION_MAJOR == 0) && ((GST_VERSION_MINOR < 10) || (GST_VERSION_MICRO < 33)) +#if !GST_CHECK_VERSION(0, 10, 33) static gboolean factory_can_src_any_caps (GstElementFactory *factory, const GstCaps *caps) { GList *templates; @@ -1653,7 +1653,7 @@ static gboolean factory_can_src_any_caps (GstElementFactory *factory, const GstC if (templ->direction == GST_PAD_SRC) { GstCaps *templcaps = gst_static_caps_get(&templ->static_caps); - if (gst_caps_can_intersect(caps, templcaps)) { + if (qt_gst_caps_can_intersect(caps, templcaps)) { gst_caps_unref(templcaps); return TRUE; } @@ -1685,7 +1685,7 @@ GstAutoplugSelectResult QGstreamerPlayerSession::handleAutoplugSelect(GstBin *bi GstCaps *sinkCaps = gst_pad_get_caps(sinkPad); #endif -#if (GST_VERSION_MAJOR == 0) && ((GST_VERSION_MINOR < 10) || (GST_VERSION_MICRO < 33)) +#if !GST_CHECK_VERSION(0, 10, 33) if (!factory_can_src_any_caps(factory, sinkCaps)) #else if (!gst_element_factory_can_src_any_caps(factory, sinkCaps)) diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp index 3489048d8..7a926ad60 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ b/src/plugins/winrt/qwinrtcameracontrol.cpp @@ -43,8 +43,8 @@ #include "qwinrtcameralockscontrol.h" #include <QtCore/qfunctions_winrt.h> -#include <QtCore/QCoreApplication> #include <QtCore/QPointer> +#include <QtGui/QGuiApplication> #include <mfapi.h> #include <mferror.h> @@ -524,6 +524,8 @@ public: QPointer<QWinRTImageEncoderControl> imageEncoderControl; QPointer<QWinRTCameraFocusControl> cameraFocusControl; QPointer<QWinRTCameraLocksControl> cameraLocksControl; + QAtomicInt framesMapped; + QEventLoop *delayClose; }; QWinRTCameraControl::QWinRTCameraControl(QObject *parent) @@ -531,6 +533,7 @@ QWinRTCameraControl::QWinRTCameraControl(QObject *parent) { Q_D(QWinRTCameraControl); + d->delayClose = nullptr; d->state = QCamera::UnloadedState; d->status = QCamera::UnloadedStatus; d->captureMode = QCamera::CaptureStillImage; @@ -544,6 +547,11 @@ QWinRTCameraControl::QWinRTCameraControl(QObject *parent) d->imageEncoderControl = new QWinRTImageEncoderControl(this); d->cameraFocusControl = new QWinRTCameraFocusControl(this); d->cameraLocksControl = new QWinRTCameraLocksControl(this); + + if (qGuiApp) { + connect(qGuiApp, &QGuiApplication::applicationStateChanged, + this, &QWinRTCameraControl::onApplicationStateChanged); + } } QWinRTCameraControl::~QWinRTCameraControl() @@ -612,6 +620,14 @@ void QWinRTCameraControl::setState(QCamera::State state) case QCamera::UnloadedState: { // Stop the camera if it is running (transition to LoadedState) if (d->status == QCamera::ActiveStatus) { + if (d->framesMapped > 0) { + qWarning("%d QVideoFrame(s) mapped when closing down camera. Camera will wait for unmap before closing down.", + d->framesMapped); + if (!d->delayClose) + d->delayClose = new QEventLoop(this); + d->delayClose->exec(); + } + ComPtr<IAsyncAction> op; hr = d->capturePreview->StopPreviewAsync(&op); RETURN_VOID_AND_EMIT_ERROR("Failed to stop camera preview"); @@ -767,6 +783,25 @@ void QWinRTCameraControl::onBufferRequested() d->mediaSink->RequestSample(); } +void QWinRTCameraControl::onApplicationStateChanged(Qt::ApplicationState state) +{ + Q_D(QWinRTCameraControl); + static QCamera::State savedState = d->state; + switch (state) { + case Qt::ApplicationInactive: + if (d->state != QCamera::UnloadedState) { + savedState = d->state; + setState(QCamera::UnloadedState); + } + break; + case Qt::ApplicationActive: + setState(QCamera::State(savedState)); + break; + default: + break; + } +} + HRESULT QWinRTCameraControl::initialize() { Q_D(QWinRTCameraControl); @@ -1119,6 +1154,8 @@ bool QWinRTCameraControl::focus() return false; ComPtr<IAsyncAction> op; HRESULT hr = d->focusControl->FocusAsync(&op); + if (HRESULT_CODE(hr) == ERROR_OPERATION_IN_PROGRESS) + return true; Q_ASSERT_SUCCEEDED(hr); hr = QWinRTFunctions::await(op, QWinRTFunctions::ProcessThreadEvents); Q_ASSERT_SUCCEEDED(hr); @@ -1208,6 +1245,21 @@ bool QWinRTCameraControl::unlockFocus() #endif // !Q_OS_WINPHONE +void QWinRTCameraControl::frameMapped() +{ + Q_D(QWinRTCameraControl); + ++d->framesMapped; +} + +void QWinRTCameraControl::frameUnmapped() +{ + Q_D(QWinRTCameraControl); + --d->framesMapped; + Q_ASSERT(d->framesMapped >= 0); + if (!d->framesMapped && d->delayClose && d->delayClose->isRunning()) + d->delayClose->exit(); +} + HRESULT QWinRTCameraControl::onCaptureFailed(IMediaCapture *, IMediaCaptureFailedEventArgs *args) { HRESULT hr; diff --git a/src/plugins/winrt/qwinrtcameracontrol.h b/src/plugins/winrt/qwinrtcameracontrol.h index ac1c922a4..b3c86adf9 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.h +++ b/src/plugins/winrt/qwinrtcameracontrol.h @@ -99,9 +99,12 @@ public: void emitError(int errorCode, const QString &errorString); bool lockFocus(); bool unlockFocus(); + void frameMapped(); + void frameUnmapped(); private slots: void onBufferRequested(); + void onApplicationStateChanged(Qt::ApplicationState state); private: HRESULT enumerateDevices(); diff --git a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp index 7afef7669..7313ae7a2 100644 --- a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp +++ b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp @@ -38,6 +38,7 @@ #include <QtCore/qfunctions_winrt.h> #include <QtCore/QSize> +#include <QtCore/QPointer> #include <QtCore/QVector> #include <QVideoFrame> @@ -45,6 +46,8 @@ #include <mfapi.h> #include <wrl.h> +#include "qwinrtcameracontrol.h" + #ifdef Q_OS_WINPHONE #include <Windows.Security.ExchangeActiveSyncProvisioning.h> using namespace ABI::Windows::Security::ExchangeActiveSyncProvisioning; @@ -68,12 +71,14 @@ static bool blacklisted(const wchar_t (&blackListName)[n], const HString &device class QWinRTCameraVideoBuffer : public QAbstractVideoBuffer { public: - QWinRTCameraVideoBuffer(IMF2DBuffer *buffer, int size) + QWinRTCameraVideoBuffer(IMF2DBuffer *buffer, int size, QWinRTCameraControl *control) : QAbstractVideoBuffer(NoHandle) , currentMode(NotMapped) , buffer(buffer) , size(size) + , control(control) { + Q_ASSERT(control); } ~QWinRTCameraVideoBuffer() @@ -88,13 +93,14 @@ public: uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) Q_DECL_OVERRIDE { - if (currentMode != NotMapped || mode == NotMapped) + if (currentMode != NotMapped || mode == NotMapped || control && control->state() != QCamera::ActiveState) return nullptr; BYTE *bytes; LONG stride; HRESULT hr = buffer->Lock2D(&bytes, &stride); RETURN_IF_FAILED("Failed to lock camera frame buffer", nullptr); + control->frameMapped(); if (bytesPerLine) *bytesPerLine = stride; @@ -111,12 +117,15 @@ public: HRESULT hr = buffer->Unlock2D(); RETURN_VOID_IF_FAILED("Failed to unlock camera frame buffer"); currentMode = NotMapped; + if (control) + control->frameUnmapped(); } private: ComPtr<IMF2DBuffer> buffer; MapMode currentMode; int size; + QPointer<QWinRTCameraControl> control; }; class D3DVideoBlitter @@ -331,7 +340,9 @@ bool QWinRTCameraVideoRendererControl::dequeueFrame(QVideoFrame *frame) return false; } - QWinRTCameraVideoBuffer *videoBuffer = new QWinRTCameraVideoBuffer(buffer.Get(), d->cameraSampleSize); + QWinRTCameraVideoBuffer *videoBuffer = new QWinRTCameraVideoBuffer(buffer.Get(), + d->cameraSampleSize, + static_cast<QWinRTCameraControl *>(parent())); *frame = QVideoFrame(videoBuffer, size(), d->cameraSampleformat); emit bufferRequested(); @@ -350,7 +361,9 @@ void QWinRTCameraVideoRendererControl::queueBuffer(IMF2DBuffer *buffer) } if (d->videoProbesCounter > 0 && d->cameraSampleformat != QVideoFrame::Format_Invalid) { - QWinRTCameraVideoBuffer *videoBuffer = new QWinRTCameraVideoBuffer(buffer, d->cameraSampleSize); + QWinRTCameraVideoBuffer *videoBuffer = new QWinRTCameraVideoBuffer(buffer, + d->cameraSampleSize, + static_cast<QWinRTCameraControl *>(parent())); QVideoFrame frame(videoBuffer, size(), d->cameraSampleformat); emit videoFrameProbed(frame); } diff --git a/src/plugins/winrt/qwinrtmediaplayercontrol.cpp b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp index 8954d4445..ed2dbb943 100644 --- a/src/plugins/winrt/qwinrtmediaplayercontrol.cpp +++ b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp @@ -51,7 +51,6 @@ #include <mfapi.h> #include <mfmediaengine.h> -#include <comdef.h> #include <wrl.h> using namespace Microsoft::WRL; diff --git a/tests/auto/integration/qmediaplayerbackend/BLACKLIST b/tests/auto/integration/qmediaplayerbackend/BLACKLIST index 0d2fe2872..dd6dd14b8 100644 --- a/tests/auto/integration/qmediaplayerbackend/BLACKLIST +++ b/tests/auto/integration/qmediaplayerbackend/BLACKLIST @@ -4,6 +4,7 @@ osx-10.8 osx-10.9 osx-10.10 windows 32bit developer-build +windows 64bit developer-build [construction] opensuse-13.1 64bit |