diff options
author | Dmytro Poplavskiy <dmytro.poplavskiy@nokia.com> | 2010-03-29 00:35:18 (GMT) |
---|---|---|
committer | Dmytro Poplavskiy <dmytro.poplavskiy@nokia.com> | 2010-03-29 00:35:18 (GMT) |
commit | d2a394ea9d433070ea0e8817b27debd9cfc8e7cd (patch) | |
tree | 4c0c2ac3ec356587e19b4f4b398a11b16ae04fab /src | |
parent | fd330a5a6009c17e28fb9eb36b5bffbc19c5df68 (diff) | |
download | Qt-d2a394ea9d433070ea0e8817b27debd9cfc8e7cd.zip Qt-d2a394ea9d433070ea0e8817b27debd9cfc8e7cd.tar.gz Qt-d2a394ea9d433070ea0e8817b27debd9cfc8e7cd.tar.bz2 |
QuickTime media backend: Render CIImage based video frames directly with
OpenGL paint engine.
This makes video rendering with QGraphicsVideoItem much faster on
64 bits systems.
Reviewed-by: Justin McPherson
Diffstat (limited to 'src')
-rw-r--r-- | src/multimedia/base/base.pri | 8 | ||||
-rw-r--r-- | src/multimedia/base/qpaintervideosurface.cpp | 31 | ||||
-rw-r--r-- | src/multimedia/base/qpaintervideosurface_mac.mm | 274 | ||||
-rw-r--r-- | src/multimedia/base/qpaintervideosurface_mac_p.h | 100 | ||||
-rw-r--r-- | src/multimedia/base/qpaintervideosurface_p.h | 22 | ||||
-rw-r--r-- | src/plugins/mediaservices/qt7/qt7.pro | 2 | ||||
-rw-r--r-- | src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.h | 90 | ||||
-rw-r--r-- | src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.mm | 104 | ||||
-rw-r--r-- | src/plugins/mediaservices/qt7/qt7movierenderer.mm | 13 | ||||
-rw-r--r-- | src/plugins/mediaservices/qt7/qt7movieviewrenderer.h | 1 | ||||
-rw-r--r-- | src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm | 81 |
11 files changed, 660 insertions, 66 deletions
diff --git a/src/multimedia/base/base.pri b/src/multimedia/base/base.pri index 5aebbf0..49eca49 100644 --- a/src/multimedia/base/base.pri +++ b/src/multimedia/base/base.pri @@ -60,4 +60,10 @@ SOURCES += \ $$PWD/qpaintervideosurface.cpp \ $$PWD/qmediatimerange.cpp - +mac { + HEADERS += $$PWD/qpaintervideosurface_mac_p.h + OBJECTIVE_SOURCES += $$PWD/qpaintervideosurface_mac.mm + + LIBS += -framework AppKit -framework QuartzCore -framework QTKit + +} diff --git a/src/multimedia/base/qpaintervideosurface.cpp b/src/multimedia/base/qpaintervideosurface.cpp index 695dc73..b8028d8f 100644 --- a/src/multimedia/base/qpaintervideosurface.cpp +++ b/src/multimedia/base/qpaintervideosurface.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qpaintervideosurface_p.h" +#include "qpaintervideosurface_mac_p.h" #include <qmath.h> @@ -56,28 +57,6 @@ QT_BEGIN_NAMESPACE -class QVideoSurfacePainter -{ -public: - virtual ~QVideoSurfacePainter(); - - virtual QList<QVideoFrame::PixelFormat> supportedPixelFormats( - QAbstractVideoBuffer::HandleType handleType) const = 0; - - virtual bool isFormatSupported( - const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const = 0; - - virtual QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format) = 0; - virtual void stop() = 0; - - virtual QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame) = 0; - - virtual QAbstractVideoSurface::Error paint( - const QRectF &target, QPainter *painter, const QRectF &source) = 0; - - virtual void updateColors(int brightness, int contrast, int hue, int saturation) = 0; -}; - QVideoSurfacePainter::~QVideoSurfacePainter() { } @@ -1544,6 +1523,14 @@ void QPainterVideoSurface::createPainter() { Q_ASSERT(!m_painter); +#ifdef Q_WS_MAC + if (m_glContext) + m_glContext->makeCurrent(); + + m_painter = new QVideoSurfaceCoreGraphicsPainter(m_glContext != 0); + return; +#endif + #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) switch (m_shaderType) { #ifndef QT_OPENGL_ES diff --git a/src/multimedia/base/qpaintervideosurface_mac.mm b/src/multimedia/base/qpaintervideosurface_mac.mm new file mode 100644 index 0000000..899b98f --- /dev/null +++ b/src/multimedia/base/qpaintervideosurface_mac.mm @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpaintervideosurface_mac_p.h" + +#include <QtCore/qdatetime.h> + +#include <qmath.h> + +#include <qpainter.h> +#include <qvariant.h> +#include <QtMultimedia/qvideosurfaceformat.h> + +#include <QtDebug> + +#include <QuartzCore/CIContext.h> + + +QT_BEGIN_NAMESPACE + +extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); //qpaintdevice_mac.cpp + +QVideoSurfaceCoreGraphicsPainter::QVideoSurfaceCoreGraphicsPainter(bool glSupported) + : ciContext(0) + , m_imageFormat(QImage::Format_Invalid) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) +{ + //qDebug() << "QVideoSurfaceCoreGraphicsPainter, GL supported:" << glSupported; + ciContext = 0; + m_imagePixelFormats + << QVideoFrame::Format_RGB32; + + m_supportedHandles + << QAbstractVideoBuffer::NoHandle + << QAbstractVideoBuffer::CoreImageHandle; + + if (glSupported) + m_supportedHandles << QAbstractVideoBuffer::GLTextureHandle; +} + +QVideoSurfaceCoreGraphicsPainter::~QVideoSurfaceCoreGraphicsPainter() +{ + [(CIContext*)ciContext release]; +} + +QList<QVideoFrame::PixelFormat> QVideoSurfaceCoreGraphicsPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + return m_supportedHandles.contains(handleType) + ? m_imagePixelFormats + : QList<QVideoFrame::PixelFormat>(); +} + +bool QVideoSurfaceCoreGraphicsPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + return m_supportedHandles.contains(format.handleType()) + && m_imagePixelFormats.contains(format.pixelFormat()) + && !format.frameSize().isEmpty(); +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::start(const QVideoSurfaceFormat &format) +{ + m_frame = QVideoFrame(); + m_imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + m_imageSize = format.frameSize(); + m_scanLineDirection = format.scanLineDirection(); + + return m_supportedHandles.contains(format.handleType()) + && m_imageFormat != QImage::Format_Invalid + && !m_imageSize.isEmpty() + ? QAbstractVideoSurface::NoError + : QAbstractVideoSurface::UnsupportedFormatError; +} + +void QVideoSurfaceCoreGraphicsPainter::stop() +{ + m_frame = QVideoFrame(); +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + return QAbstractVideoSurface::NoError; +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (m_frame.handleType() == QAbstractVideoBuffer::CoreImageHandle) { + if (painter->paintEngine()->type() == QPaintEngine::CoreGraphics ) { + + CIImage *img = (CIImage*)(m_frame.handle().value<void*>()); + + if (img) { + CGContextRef cgContext = qt_mac_cg_context(painter->device()); + + if (cgContext) { + painter->beginNativePainting(); + + CGRect sRect = CGRectMake(source.x(), source.y(), source.width(), source.height()); + CGRect dRect = CGRectMake(target.x(), target.y(), target.width(), target.height()); + + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img]; + + if (m_scanLineDirection == QVideoSurfaceFormat::TopToBottom) { + CGContextSaveGState( cgContext ); + CGContextTranslateCTM(cgContext, 0, dRect.origin.y + CGRectGetMaxY(dRect)); + CGContextScaleCTM(cgContext, 1, -1); + + CGContextDrawImage(cgContext, dRect, [bitmap CGImage]); + + CGContextRestoreGState(cgContext); + } else { + CGContextDrawImage(cgContext, dRect, [bitmap CGImage]); + } + + [bitmap release]; + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + } + } else if (painter->paintEngine()->type() == QPaintEngine::OpenGL2 || + painter->paintEngine()->type() == QPaintEngine::OpenGL) { + CIImage *img = (CIImage*)(m_frame.handle().value<void*>()); + + if (img) { + CGLContextObj cglContext = CGLGetCurrentContext(); + + if (cglContext) { + + if (!ciContext) { + CGLContextObj cglContext = CGLGetCurrentContext(); + NSOpenGLPixelFormat *nsglPixelFormat = [NSOpenGLView defaultPixelFormat]; + CGLPixelFormatObj cglPixelFormat = static_cast<CGLPixelFormatObj>([nsglPixelFormat CGLPixelFormatObj]); + + ciContext = [CIContext contextWithCGLContext:cglContext + pixelFormat:cglPixelFormat + options:nil]; + + [(CIContext*)ciContext retain]; + } + + CGRect sRect = CGRectMake(source.x(), source.y(), source.width(), source.height()); + CGRect dRect = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom ? + CGRectMake(target.x(), target.y()+target.height(), target.width(), -target.height()) : + CGRectMake(target.x(), target.y(), target.width(), target.height()); + + + painter->beginNativePainting(); + + [(CIContext*)ciContext drawImage:img inRect:dRect fromRect:sRect]; + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + } + } + } + + if (m_frame.handleType() == QAbstractVideoBuffer::GLTextureHandle && + (painter->paintEngine()->type() == QPaintEngine::OpenGL2 || + painter->paintEngine()->type() == QPaintEngine::OpenGL)) { + + painter->beginNativePainting(); + GLuint texture = m_frame.handle().toUInt(); + + glDisable(GL_CULL_FACE); + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + const float txLeft = source.left() / m_frame.width(); + const float txRight = source.right() / m_frame.width(); + const float txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.top() / m_frame.height() + : source.bottom() / m_frame.height(); + const float txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.bottom() / m_frame.height() + : source.top() / m_frame.height(); + + glBegin(GL_QUADS); + QRectF rect = target; + glTexCoord2f(txLeft, txBottom); + glVertex2f(rect.topLeft().x(), rect.topLeft().y()); + glTexCoord2f(txRight, txBottom); + glVertex2f(rect.topRight().x() + 1, rect.topRight().y()); + glTexCoord2f(txRight, txTop); + glVertex2f(rect.bottomRight().x() + 1, rect.bottomRight().y() + 1); + glTexCoord2f(txLeft, txTop); + glVertex2f(rect.bottomLeft().x(), rect.bottomLeft().y() + 1); + glEnd(); + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + + //fallback case, software rendering + if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + QImage image( + m_frame.bits(), + m_imageSize.width(), + m_imageSize.height(), + m_frame.bytesPerLine(), + m_imageFormat); + + if (m_scanLineDirection == QVideoSurfaceFormat::BottomToTop) { + const QTransform oldTransform = painter->transform(); + + painter->scale(1, -1); + painter->translate(0, -target.bottom()); + painter->drawImage( + QRectF(target.x(), 0, target.width(), target.height()), image, source); + painter->setTransform(oldTransform); + } else { + painter->drawImage(target, image, source); + } + + m_frame.unmap(); + } else { + painter->fillRect(target, Qt::black); + } + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceCoreGraphicsPainter::updateColors(int, int, int, int) +{ +} + +QT_END_NAMESPACE diff --git a/src/multimedia/base/qpaintervideosurface_mac_p.h b/src/multimedia/base/qpaintervideosurface_mac_p.h new file mode 100644 index 0000000..64442ed --- /dev/null +++ b/src/multimedia/base/qpaintervideosurface_mac_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTERVIDEOSURFACE_MAC_P_H +#define QPAINTERVIDEOSURFACE_MAC_P_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. +// + +#include "qpaintervideosurface_p.h" +#include <QtMultimedia/qvideosurfaceformat.h> +#include <QtMultimedia/qvideoframe.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QVideoSurfaceCoreGraphicsPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceCoreGraphicsPainter(bool glSupported); + ~QVideoSurfaceCoreGraphicsPainter(); + + QList<QVideoFrame::PixelFormat> supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + + void updateColors(int brightness, int contrast, int hue, int saturation); + +private: + void* ciContext; + QList<QVideoFrame::PixelFormat> m_imagePixelFormats; + QVideoFrame m_frame; + QSize m_imageSize; + QImage::Format m_imageFormat; + QVector<QAbstractVideoBuffer::HandleType> m_supportedHandles; + QVideoSurfaceFormat::Direction m_scanLineDirection; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qpaintervideosurface_p.h b/src/multimedia/base/qpaintervideosurface_p.h index d4b6740..caba3ba 100644 --- a/src/multimedia/base/qpaintervideosurface_p.h +++ b/src/multimedia/base/qpaintervideosurface_p.h @@ -67,8 +67,28 @@ QT_BEGIN_NAMESPACE class QGLContext; +class QVideoSurfacePainter +{ +public: + virtual ~QVideoSurfacePainter(); + + virtual QList<QVideoFrame::PixelFormat> supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const = 0; + + virtual bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const = 0; + + virtual QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format) = 0; + virtual void stop() = 0; + + virtual QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame) = 0; + + virtual QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source) = 0; + + virtual void updateColors(int brightness, int contrast, int hue, int saturation) = 0; +}; -class QVideoSurfacePainter; class Q_MULTIMEDIA_EXPORT QPainterVideoSurface : public QAbstractVideoSurface { Q_OBJECT diff --git a/src/plugins/mediaservices/qt7/qt7.pro b/src/plugins/mediaservices/qt7/qt7.pro index 6624d13..8791d73 100644 --- a/src/plugins/mediaservices/qt7/qt7.pro +++ b/src/plugins/mediaservices/qt7/qt7.pro @@ -25,6 +25,7 @@ HEADERS += \ qt7movieviewrenderer.h \ qt7serviceplugin.h \ qt7movierenderer.h \ + qt7ciimagevideobuffer.h \ qcvdisplaylink.h OBJECTIVE_SOURCES += \ @@ -35,6 +36,7 @@ OBJECTIVE_SOURCES += \ qt7movieviewrenderer.mm \ qt7movierenderer.mm \ qt7videooutputcontrol.mm \ + qt7ciimagevideobuffer.mm \ qcvdisplaylink.mm include(mediaplayer/mediaplayer.pri) diff --git a/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.h b/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.h new file mode 100644 index 0000000..669724f --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7CIIMAGEVIDEOBUFFER_H +#define QT7CIIMAGEVIDEOBUFFER_H + +#include "qt7backend.h" +#import <QTKit/QTKit.h> + +#include <QtCore/qvariant.h> +#include <QtMultimedia/qabstractvideobuffer.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_HEADER + +QT_BEGIN_NAMESPACE + +class QT7CIImageVideoBuffer : public QAbstractVideoBuffer +{ +public: + QT7CIImageVideoBuffer(CIImage *image); + + virtual ~QT7CIImageVideoBuffer(); + + MapMode mapMode() const; + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); + void unmap(); + QVariant handle() const; + +private: + CIImage *m_image; + NSBitmapImageRep *m_buffer; + MapMode m_mode; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.mm b/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.mm new file mode 100644 index 0000000..3778b58 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.mm @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7ciimagevideobuffer.h" + +QT7CIImageVideoBuffer::QT7CIImageVideoBuffer(CIImage *image) + : QAbstractVideoBuffer(CoreImageHandle) + , m_image(image) + , m_buffer(0) + , m_mode(NotMapped) +{ + [m_image retain]; +} + +QT7CIImageVideoBuffer::~QT7CIImageVideoBuffer() +{ + [m_image release]; + [m_buffer release]; +} + +QAbstractVideoBuffer::MapMode QT7CIImageVideoBuffer::mapMode() const +{ + return m_mode; +} + +uchar *QT7CIImageVideoBuffer::map(QAbstractVideoBuffer::MapMode mode, int *numBytes, int *bytesPerLine) +{ + if (mode == NotMapped || m_mode != NotMapped || !m_image) + return 0; + + if (!m_buffer) { + //swap R and B channels + CIFilter *colorSwapFilter = [CIFilter filterWithName: @"CIColorMatrix" keysAndValues: + @"inputImage", m_image, + @"inputRVector", [CIVector vectorWithX: 0 Y: 0 Z: 1 W: 0], + @"inputGVector", [CIVector vectorWithX: 0 Y: 1 Z: 0 W: 0], + @"inputBVector", [CIVector vectorWithX: 1 Y: 0 Z: 0 W: 0], + @"inputAVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 1], + @"inputBiasVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 0], + nil]; + CIImage *img = [colorSwapFilter valueForKey: @"outputImage"]; + + m_buffer = [[NSBitmapImageRep alloc] initWithCIImage:img]; + } + + if (numBytes) + *numBytes = [m_buffer bytesPerPlane]; + + if (bytesPerLine) + *bytesPerLine = [m_buffer bytesPerRow]; + + m_mode = mode; + + return [m_buffer bitmapData]; +} + +void QT7CIImageVideoBuffer::unmap() +{ + m_mode = NotMapped; +} + +QVariant QT7CIImageVideoBuffer::handle() const +{ + return QVariant::fromValue<void*>(m_image); +} + diff --git a/src/plugins/mediaservices/qt7/qt7movierenderer.mm b/src/plugins/mediaservices/qt7/qt7movierenderer.mm index 1c1f5e4..a6d9d8d 100644 --- a/src/plugins/mediaservices/qt7/qt7movierenderer.mm +++ b/src/plugins/mediaservices/qt7/qt7movierenderer.mm @@ -46,6 +46,7 @@ #include "qt7playercontrol.h" #include "qt7movierenderer.h" #include "qt7playersession.h" +#include "qt7ciimagevideobuffer.h" #include "qcvdisplaylink.h" #include <QtCore/qdebug.h> #include <QtCore/qcoreapplication.h> @@ -64,7 +65,7 @@ class CVGLTextureVideoBuffer : public QAbstractVideoBuffer { public: CVGLTextureVideoBuffer(CVOpenGLTextureRef buffer) - : QAbstractVideoBuffer(NoHandle) + : QAbstractVideoBuffer(GLTextureHandle) , m_buffer(buffer) , m_mode(NotMapped) { @@ -82,11 +83,6 @@ public: return QVariant(int(id)); } - HandleType handleType() const - { - return GLTextureHandle; - } - MapMode mapMode() const { return m_mode; } uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) @@ -447,15 +443,14 @@ void QT7MovieRenderer::updateVideoFrame(const CVTimeStamp &ts) OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, NULL, &ts, &imageBuffer); if (status == noErr && imageBuffer) { - //qDebug() << "render video frame"; QAbstractVideoBuffer *buffer = 0; if (m_usingGLContext) { - buffer = new CVGLTextureVideoBuffer((CVOpenGLTextureRef)imageBuffer); + buffer = new QT7CIImageVideoBuffer([CIImage imageWithCVImageBuffer:imageBuffer]); CVOpenGLTextureRelease((CVOpenGLTextureRef)imageBuffer); - //qDebug() << "render GL video frame" << buffer->handle(); } else { buffer = new CVPixelBufferVideoBuffer((CVPixelBufferRef)imageBuffer); + //buffer = new QT7CIImageVideoBuffer( [CIImage imageWithCVImageBuffer:imageBuffer] ); CVPixelBufferRelease((CVPixelBufferRef)imageBuffer); } diff --git a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h index 336006c..0126360 100644 --- a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h +++ b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h @@ -87,6 +87,7 @@ private: QSize m_nativeSize; QAbstractVideoSurface *m_surface; QVideoFrame m_currentFrame; + bool m_pendingRenderEvent; QMutex m_mutex; }; diff --git a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm index 5047853..5f11479 100644 --- a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm +++ b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm @@ -46,6 +46,7 @@ #include "qt7playercontrol.h" #include "qt7movieviewrenderer.h" #include "qt7playersession.h" +#include "qt7ciimagevideobuffer.h" #include <QtCore/qdebug.h> #include <QtCore/qcoreevent.h> #include <QtCore/qcoreapplication.h> @@ -113,6 +114,7 @@ QT_END_NAMESPACE - (HiddenQTMovieView *) initWithRenderer:(QT7MovieViewRenderer *)renderer; - (void) setRenderer:(QT7MovieViewRenderer *)renderer; - (void) setDrawRect:(const QRect &)rect; +- (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img; @end @implementation HiddenQTMovieView @@ -163,33 +165,37 @@ QT_END_NAMESPACE // before the image will be drawn. Q_UNUSED(view); if (m_renderer) { - NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img]; CGRect bounds = [img extent]; int w = bounds.size.width; int h = bounds.size.height; - // Swap red and blue (same as QImage::rgbSwapped, but without copy) - uchar *data = [bitmap bitmapData]; - //qDebug() << data << w << h; - int bytesPerLine = [bitmap bytesPerRow]; - for (int i=0; i<h; ++i) { - quint32 *p = (quint32*)data; - data += bytesPerLine; - quint32 *end = p + w; - while (p < end) { - *p = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00); - p++; - } - } + QVideoFrame frame; - QVideoFrame frame( new NSBitmapVideoBuffer(bitmap), QSize(w,h), QVideoFrame::Format_RGB32 ); + QAbstractVideoSurface *surface = m_renderer->surface(); + if (!surface || !surface->isActive()) + return img; - //static int i=0; - //i++; - //QImage img([bitmap bitmapData], w, h, QImage::Format_RGB32); - //img.save(QString("img%1.jpg").arg(i)); - - [bitmap release]; + if (surface->surfaceFormat().handleType() == QAbstractVideoBuffer::CoreImageHandle) { + //surface supports rendering of opengl based CIImage + frame = QVideoFrame(new QT7CIImageVideoBuffer(img), QSize(w,h), QVideoFrame::Format_RGB32 ); + } else { + //Swap R and B colors + CIFilter *colorSwapFilter = [CIFilter filterWithName: @"CIColorMatrix" keysAndValues: + @"inputImage", img, + @"inputRVector", [CIVector vectorWithX: 0 Y: 0 Z: 1 W: 0], + @"inputGVector", [CIVector vectorWithX: 0 Y: 1 Z: 0 W: 0], + @"inputBVector", [CIVector vectorWithX: 1 Y: 0 Z: 0 W: 0], + @"inputAVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 1], + @"inputBiasVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 0], + nil]; + CIImage *img = [colorSwapFilter valueForKey: @"outputImage"]; + NSBitmapImageRep *bitmap =[[NSBitmapImageRep alloc] initWithCIImage:img]; + //requesting the bitmap data is slow, + //but it's better to do it here to avoid blocking the main thread for a long. + [bitmap bitmapData]; + frame = QVideoFrame(new NSBitmapVideoBuffer(bitmap), QSize(w,h), QVideoFrame::Format_RGB32 ); + [bitmap release]; + } if (m_renderer) m_renderer->renderFrame(frame); @@ -230,7 +236,8 @@ QT7MovieViewRenderer::QT7MovieViewRenderer(QObject *parent) :QT7VideoRendererControl(parent), m_movie(0), m_movieView(0), - m_surface(0) + m_surface(0), + m_pendingRenderEvent(false) { } @@ -267,11 +274,15 @@ void QT7MovieViewRenderer::setupVideoOutput() } [movieView setMovie:(QTMovie*)m_movie]; - //[movieView setDrawRect:QRect(QPoint(0,0), m_nativeSize)]; + [movieView setDrawRect:QRect(QPoint(0,0), m_nativeSize)]; } if (m_surface && !m_nativeSize.isEmpty()) { - QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32); + bool coreImageFrameSupported = !m_surface->supportedPixelFormats(QAbstractVideoBuffer::CoreImageHandle).isEmpty() && + !m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty(); + + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32, + coreImageFrameSupported ? QAbstractVideoBuffer::CoreImageHandle : QAbstractVideoBuffer::NoHandle); if (m_surface->isActive() && m_surface->surfaceFormat() != format) { // qDebug() << "Surface format was changed, stop the surface."; @@ -279,10 +290,11 @@ void QT7MovieViewRenderer::setupVideoOutput() } if (!m_surface->isActive()) { -// qDebug() << "Starting the surface with format" << format; - m_surface->start(format); -// if (!m_surface->start(format)) -// qDebug() << "failed to start video surface" << m_surface->error(); + //qDebug() << "Starting the surface with format" << format; + if (!m_surface->start(format)) { + qWarning() << "Failed to start video surface" << m_surface->error(); + qWarning() << "Surface format:" << format; + } } } } @@ -330,18 +342,21 @@ void QT7MovieViewRenderer::setSurface(QAbstractVideoSurface *surface) void QT7MovieViewRenderer::renderFrame(const QVideoFrame &frame) { - { - QMutexLocker locker(&m_mutex); - m_currentFrame = frame; - } - qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority); + QMutexLocker locker(&m_mutex); + m_currentFrame = frame; + + if (!m_pendingRenderEvent) + qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority); + + m_pendingRenderEvent = true; } bool QT7MovieViewRenderer::event(QEvent *event) { if (event->type() == QEvent::User) { QMutexLocker locker(&m_mutex); + m_pendingRenderEvent = false; if (m_surface->isActive()) m_surface->present(m_currentFrame); } |