src/multimedia/qgraphicsvideoitem_maemo5.cpp
changeset 0 876b1a06bc25
child 5 603d3f8b6302
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QtCore/qpointer.h>
       
    43 #include <QtCore/qdatetime.h>
       
    44 #include <QtCore/qbasictimer.h>
       
    45 #include <QtCore/qcoreevent.h>
       
    46 #include <QtGui/qgraphicsscene.h>
       
    47 #include <QtGui/qgraphicsview.h>
       
    48 #include <QtGui/qscrollbar.h>
       
    49 #include <QtGui/qx11info_x11.h>
       
    50 
       
    51 #include "qgraphicsvideoitem.h"
       
    52 
       
    53 #include <qmediaobject.h>
       
    54 #include <qmediaservice.h>
       
    55 #include <qpaintervideosurface_p.h>
       
    56 #include <qvideorenderercontrol.h>
       
    57 
       
    58 #include <qvideosurfaceformat.h>
       
    59 
       
    60 #include "qxvideosurface_maemo5_p.h"
       
    61 
       
    62 
       
    63 QT_BEGIN_NAMESPACE
       
    64 
       
    65 //update overlay geometry slightly later,
       
    66 //to ensure color key is alredy replaced with static frame
       
    67 #define GEOMETRY_UPDATE_DELAY 20
       
    68 //this is necessary to prevent flickering, see maemo bug 8798
       
    69 //on geometry changes, the color key is replaced with static image frame
       
    70 //until the overlay is re-initialized
       
    71 #define SOFTWARE_RENDERING_DURATION 150
       
    72 
       
    73 #ifdef  __ARM_NEON__
       
    74 
       
    75 /*
       
    76 * ARM NEON optimized implementation of UYVY -> RGB16 convertor
       
    77 */
       
    78 static void uyvy422_to_rgb16_line_neon (uint8_t * dst, const uint8_t * src, int n)
       
    79 {
       
    80      /* and this is the NEON code itself */
       
    81      static __attribute__ ((aligned (16))) uint16_t acc_r[8] = {
       
    82        22840, 22840, 22840, 22840, 22840, 22840, 22840, 22840,
       
    83      };
       
    84      static __attribute__ ((aligned (16))) uint16_t acc_g[8] = {
       
    85        17312, 17312, 17312, 17312, 17312, 17312, 17312, 17312,
       
    86      };
       
    87      static __attribute__ ((aligned (16))) uint16_t acc_b[8] = {
       
    88        28832, 28832, 28832, 28832, 28832, 28832, 28832, 28832,
       
    89      };
       
    90      /*
       
    91       * Registers:
       
    92       * q0, q1 : d0, d1, d2, d3  - are used for initial loading of YUV data
       
    93       * q2     : d4, d5          - are used for storing converted RGB data
       
    94       * q3     : d6, d7          - are used for temporary storage
       
    95       *
       
    96       * q6     : d12, d13        - are used for converting to RGB16
       
    97       * q7     : d14, d15        - are used for storing RGB16 data
       
    98       * q4-q5 - reserved
       
    99       *
       
   100       * q8, q9 : d16, d17, d18, d19  - are used for expanded Y data
       
   101       * q10    : d20, d21
       
   102       * q11    : d22, d23
       
   103       * q12    : d24, d25
       
   104       * q13    : d26, d27
       
   105       * q13, q14, q15            - various constants (#16, #149, #204, #50, #104, #154)
       
   106       */
       
   107      asm volatile (".macro convert_macroblock size\n"
       
   108          /* load up to 16 source pixels in UYVY format */
       
   109          ".if \\size == 16\n"
       
   110          "pld [%[src], #128]\n"
       
   111          "vld1.32 {d0, d1, d2, d3}, [%[src]]!\n"
       
   112          ".elseif \\size == 8\n"
       
   113          "vld1.32 {d0, d1}, [%[src]]!\n"
       
   114          ".elseif \\size == 4\n"
       
   115          "vld1.32 {d0}, [%[src]]!\n"
       
   116          ".elseif \\size == 2\n"
       
   117          "vld1.32 {d0[0]}, [%[src]]!\n"
       
   118          ".else\n" ".error \"unsupported macroblock size\"\n" ".endif\n"
       
   119          /* convert from 'packed' to 'planar' representation */
       
   120          "vuzp.8      d0, d1\n"    /* d1 - separated Y data (first 8 bytes) */
       
   121          "vuzp.8      d2, d3\n"    /* d3 - separated Y data (next 8 bytes) */
       
   122          "vuzp.8      d0, d2\n"    /* d0 - separated U data, d2 - separated V data */
       
   123          /* split even and odd Y color components */
       
   124          "vuzp.8      d1, d3\n"    /* d1 - evenY, d3 - oddY */
       
   125          /* clip upper and lower boundaries */
       
   126          "vqadd.u8    q0, q0, q4\n"
       
   127          "vqadd.u8    q1, q1, q4\n"
       
   128          "vqsub.u8    q0, q0, q5\n"
       
   129          "vqsub.u8    q1, q1, q5\n"
       
   130          "vshr.u8     d4, d2, #1\n"    /* d4 = V >> 1 */
       
   131          "vmull.u8    q8, d1, d27\n"       /* q8 = evenY * 149 */
       
   132          "vmull.u8    q9, d3, d27\n"       /* q9 = oddY * 149 */
       
   133          "vld1.16     {d20, d21}, [%[acc_r], :128]\n"      /* q10 - initialize accumulator for red */
       
   134          "vsubw.u8    q10, q10, d4\n"      /* red acc -= (V >> 1) */
       
   135          "vmlsl.u8    q10, d2, d28\n"      /* red acc -= V * 204 */
       
   136          "vld1.16     {d22, d23}, [%[acc_g], :128]\n"      /* q11 - initialize accumulator for green */
       
   137          "vmlsl.u8    q11, d2, d30\n"      /* green acc -= V * 104 */
       
   138          "vmlsl.u8    q11, d0, d29\n"      /* green acc -= U * 50 */
       
   139          "vld1.16     {d24, d25}, [%[acc_b], :128]\n"      /* q12 - initialize accumulator for blue */
       
   140          "vmlsl.u8    q12, d0, d30\n"      /* blue acc -= U * 104 */
       
   141          "vmlsl.u8    q12, d0, d31\n"      /* blue acc -= U * 154 */
       
   142          "vhsub.s16   q3, q8, q10\n"       /* calculate even red components */
       
   143          "vhsub.s16   q10, q9, q10\n"      /* calculate odd red components */
       
   144          "vqshrun.s16 d0, q3, #6\n"        /* right shift, narrow and saturate even red components */
       
   145          "vqshrun.s16 d3, q10, #6\n"       /* right shift, narrow and saturate odd red components */
       
   146          "vhadd.s16   q3, q8, q11\n"       /* calculate even green components */
       
   147          "vhadd.s16   q11, q9, q11\n"      /* calculate odd green components */
       
   148          "vqshrun.s16 d1, q3, #6\n"        /* right shift, narrow and saturate even green components */
       
   149          "vqshrun.s16 d4, q11, #6\n"       /* right shift, narrow and saturate odd green components */
       
   150          "vhsub.s16   q3, q8, q12\n"       /* calculate even blue components */
       
   151          "vhsub.s16   q12, q9, q12\n"      /* calculate odd blue components */
       
   152          "vqshrun.s16 d2, q3, #6\n"        /* right shift, narrow and saturate even blue components */
       
   153          "vqshrun.s16 d5, q12, #6\n"       /* right shift, narrow and saturate odd blue components */
       
   154          "vzip.8      d0, d3\n"    /* join even and odd red components */
       
   155          "vzip.8      d1, d4\n"    /* join even and odd green components */
       
   156          "vzip.8      d2, d5\n"    /* join even and odd blue components */
       
   157          "vshll.u8     q7, d0, #8\n" //red
       
   158          "vshll.u8     q6, d1, #8\n" //greed
       
   159          "vsri.u16   q7, q6, #5\n"
       
   160          "vshll.u8     q6, d2, #8\n" //blue
       
   161          "vsri.u16   q7, q6, #11\n" //now there is rgb16 in q7
       
   162          ".if \\size == 16\n"
       
   163          "vst1.16 {d14, d15}, [%[dst]]!\n"
       
   164          //"vst3.8  {d0, d1, d2}, [%[dst]]!\n"
       
   165          "vshll.u8     q7, d3, #8\n" //red
       
   166          "vshll.u8     q6, d4, #8\n" //greed
       
   167          "vsri.u16   q7, q6, #5\n"
       
   168          "vshll.u8     q6, d5, #8\n" //blue
       
   169          "vsri.u16   q7, q6, #11\n" //now there is rgb16 in q7
       
   170          //"vst3.8  {d3, d4, d5}, [%[dst]]!\n"
       
   171          "vst1.16 {d14, d15}, [%[dst]]!\n"
       
   172          ".elseif \\size == 8\n"
       
   173          "vst1.16 {d14, d15}, [%[dst]]!\n"
       
   174          //"vst3.8  {d0, d1, d2}, [%[dst]]!\n"
       
   175          ".elseif \\size == 4\n"
       
   176          "vst1.8 {d14}, [%[dst]]!\n"
       
   177          ".elseif \\size == 2\n"
       
   178          "vst1.8 {d14[0]}, [%[dst]]!\n"
       
   179          "vst1.8 {d14[1]}, [%[dst]]!\n"
       
   180          ".else\n"
       
   181          ".error \"unsupported macroblock size\"\n"
       
   182          ".endif\n"
       
   183          ".endm\n"
       
   184          "vmov.u8     d8, #15\n"  /* add this to U/V to saturate upper boundary */
       
   185          "vmov.u8     d9, #20\n"   /* add this to Y to saturate upper boundary */
       
   186          "vmov.u8     d10, #31\n"  /* sub this from U/V to saturate lower boundary */
       
   187          "vmov.u8     d11, #36\n"  /* sub this from Y to saturate lower boundary */
       
   188          "vmov.u8     d26, #16\n"
       
   189          "vmov.u8     d27, #149\n"
       
   190          "vmov.u8     d28, #204\n"
       
   191          "vmov.u8     d29, #50\n"
       
   192          "vmov.u8     d30, #104\n"
       
   193          "vmov.u8     d31, #154\n"
       
   194          "subs        %[n], %[n], #16\n"
       
   195          "blt         2f\n"
       
   196          "1:\n"
       
   197          "convert_macroblock 16\n"
       
   198          "subs        %[n], %[n], #16\n"
       
   199          "bge         1b\n"
       
   200          "2:\n"
       
   201          "tst         %[n], #8\n"
       
   202          "beq         3f\n"
       
   203          "convert_macroblock 8\n"
       
   204          "3:\n"
       
   205          "tst         %[n], #4\n"
       
   206          "beq         4f\n"
       
   207          "convert_macroblock 4\n"
       
   208          "4:\n"
       
   209          "tst         %[n], #2\n"
       
   210          "beq         5f\n"
       
   211          "convert_macroblock 2\n"
       
   212          "5:\n"
       
   213          ".purgem convert_macroblock\n":[src] "+&r" (src),[dst] "+&r" (dst),
       
   214          [n] "+&r" (n)
       
   215          :[acc_r] "r" (&acc_r[0]),[acc_g] "r" (&acc_g[0]),[acc_b] "r" (&acc_b[0])
       
   216          :"cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
       
   217          "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
       
   218          "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31");
       
   219 }
       
   220 
       
   221 #endif
       
   222 
       
   223 class QGraphicsVideoItemPrivate
       
   224 {
       
   225 public:
       
   226     QGraphicsVideoItemPrivate()
       
   227         : q_ptr(0)
       
   228         , surface(0)
       
   229         , mediaObject(0)
       
   230         , service(0)
       
   231         , rendererControl(0)
       
   232         , savedViewportUpdateMode(QGraphicsView::FullViewportUpdate)
       
   233         , aspectRatioMode(Qt::KeepAspectRatio)
       
   234         , rect(0.0, 0.0, 320, 240)
       
   235         , softwareRenderingEnabled(false)
       
   236     {
       
   237     }
       
   238 
       
   239     QGraphicsVideoItem *q_ptr;
       
   240 
       
   241     QXVideoSurface *surface;
       
   242     QMediaObject *mediaObject;
       
   243     QMediaService *service;
       
   244     QVideoRendererControl *rendererControl;
       
   245     QPointer<QGraphicsView> currentView;
       
   246     QGraphicsView::ViewportUpdateMode savedViewportUpdateMode;
       
   247 
       
   248     Qt::AspectRatioMode aspectRatioMode;
       
   249     QRectF rect;
       
   250     QRectF boundingRect;
       
   251     QRectF sourceRect;
       
   252     QSizeF nativeSize;
       
   253 
       
   254     QPixmap lastFrame;
       
   255     QBasicTimer softwareRenderingTimer;
       
   256     QBasicTimer geometryUpdateTimer;
       
   257     bool softwareRenderingEnabled;
       
   258     QRect overlayRect;
       
   259 
       
   260     void clearService();
       
   261     void updateRects();
       
   262     void updateLastFrame();
       
   263 
       
   264     void _q_present();
       
   265     void _q_formatChanged(const QVideoSurfaceFormat &format);
       
   266     void _q_serviceDestroyed();
       
   267     void _q_mediaObjectDestroyed();
       
   268 };
       
   269 
       
   270 void QGraphicsVideoItemPrivate::clearService()
       
   271 {
       
   272     if (rendererControl) {
       
   273         surface->stop();
       
   274         rendererControl->setSurface(0);
       
   275         service->releaseControl(rendererControl);
       
   276         rendererControl = 0;
       
   277     }
       
   278 
       
   279     if (service) {
       
   280         QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed()));
       
   281         service = 0;
       
   282     }
       
   283 }
       
   284 
       
   285 void QGraphicsVideoItemPrivate::updateRects()
       
   286 {
       
   287     q_ptr->prepareGeometryChange();
       
   288 
       
   289     if (nativeSize.isEmpty()) {
       
   290         boundingRect = QRectF();
       
   291     } else if (aspectRatioMode == Qt::IgnoreAspectRatio) {
       
   292         boundingRect = rect;
       
   293         sourceRect = QRectF(0, 0, 1, 1);
       
   294     } else if (aspectRatioMode == Qt::KeepAspectRatio) {
       
   295         QSizeF size = nativeSize;
       
   296         size.scale(rect.size(), Qt::KeepAspectRatio);
       
   297 
       
   298         boundingRect = QRectF(0, 0, size.width(), size.height());
       
   299         boundingRect.moveCenter(rect.center());
       
   300 
       
   301         sourceRect = QRectF(0, 0, 1, 1);
       
   302     } else if (aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
       
   303         boundingRect = rect;
       
   304 
       
   305         QSizeF size = rect.size();
       
   306         size.scale(nativeSize, Qt::KeepAspectRatio);
       
   307 
       
   308         sourceRect = QRectF(
       
   309                 0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height());
       
   310         sourceRect.moveCenter(QPointF(0.5, 0.5));
       
   311     }
       
   312 }
       
   313 
       
   314 void QGraphicsVideoItemPrivate::updateLastFrame()
       
   315 {
       
   316     lastFrame = QPixmap();
       
   317 
       
   318     if (!softwareRenderingEnabled)
       
   319         return;
       
   320 
       
   321     QVideoFrame lastVideoFrame = surface->lastFrame();
       
   322 
       
   323     if (!lastVideoFrame.isValid())
       
   324         return;
       
   325 
       
   326     if (lastVideoFrame.map(QAbstractVideoBuffer::ReadOnly)) {
       
   327 
       
   328 #ifdef  __ARM_NEON__
       
   329         if (lastVideoFrame.pixelFormat() == QVideoFrame::Format_UYVY) {
       
   330             QImage lastImage(lastVideoFrame.size(), QImage::Format_RGB16);
       
   331 
       
   332             const uchar *src = lastVideoFrame.bits();
       
   333             uchar *dst = lastImage.bits();
       
   334             const int srcLineStep = lastVideoFrame.bytesPerLine();
       
   335             const int dstLineStep = lastImage.bytesPerLine();
       
   336             const int h = lastVideoFrame.height();
       
   337             const int w = lastVideoFrame.width();
       
   338 
       
   339             for (int y=0; y<h; y++) {
       
   340                 uyvy422_to_rgb16_line_neon(dst, src, w);
       
   341                 src += srcLineStep;
       
   342                 dst += dstLineStep;
       
   343             }
       
   344             lastFrame = QPixmap::fromImage(
       
   345                 lastImage.scaled(boundingRect.size().toSize(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
       
   346         } else
       
   347 #endif
       
   348         {
       
   349             QImage::Format imgFormat = QVideoFrame::imageFormatFromPixelFormat(lastVideoFrame.pixelFormat());
       
   350 
       
   351             if (imgFormat != QImage::Format_Invalid) {
       
   352                 QImage lastImage(lastVideoFrame.bits(),
       
   353                                  lastVideoFrame.width(),
       
   354                                  lastVideoFrame.height(),
       
   355                                  lastVideoFrame.bytesPerLine(),
       
   356                                  imgFormat);
       
   357 
       
   358                 lastFrame = QPixmap::fromImage(
       
   359                         lastImage.scaled(boundingRect.size().toSize(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
       
   360             }
       
   361         }
       
   362 
       
   363         lastVideoFrame.unmap();
       
   364     }
       
   365 
       
   366 }
       
   367 
       
   368 void QGraphicsVideoItemPrivate::_q_present()
       
   369 {
       
   370     q_ptr->update(boundingRect);
       
   371 }
       
   372 
       
   373 void QGraphicsVideoItemPrivate::_q_formatChanged(const QVideoSurfaceFormat &format)
       
   374 {
       
   375     nativeSize = format.sizeHint();
       
   376     lastFrame = QPixmap();
       
   377 
       
   378     updateRects();
       
   379 
       
   380     emit q_ptr->nativeSizeChanged(nativeSize);
       
   381 }
       
   382 
       
   383 void QGraphicsVideoItemPrivate::_q_serviceDestroyed()
       
   384 {
       
   385     rendererControl = 0;
       
   386     service = 0;
       
   387 
       
   388     surface->stop();
       
   389 }
       
   390 
       
   391 void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed()
       
   392 {
       
   393     mediaObject = 0;
       
   394 
       
   395     clearService();
       
   396 }
       
   397 
       
   398 QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent)
       
   399     : QGraphicsObject(parent)
       
   400     , d_ptr(new QGraphicsVideoItemPrivate)
       
   401 {
       
   402     d_ptr->q_ptr = this;
       
   403     d_ptr->surface = new QXVideoSurface;
       
   404 
       
   405     setCacheMode(NoCache);
       
   406     setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
       
   407     setFlag(QGraphicsItem::ItemSendsGeometryChanges);
       
   408     setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
       
   409 
       
   410     connect(d_ptr->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)),
       
   411             this, SLOT(_q_formatChanged(QVideoSurfaceFormat)));
       
   412 
       
   413     connect(d_ptr->surface, SIGNAL(activeChanged(bool)), this, SLOT(_q_present()));
       
   414 }
       
   415 
       
   416 QGraphicsVideoItem::~QGraphicsVideoItem()
       
   417 {
       
   418     if (d_ptr->rendererControl) {
       
   419         d_ptr->rendererControl->setSurface(0);
       
   420         d_ptr->service->releaseControl(d_ptr->rendererControl);
       
   421     }
       
   422 
       
   423     if (d_ptr->currentView)
       
   424         d_ptr->currentView->setViewportUpdateMode(d_ptr->savedViewportUpdateMode);
       
   425 
       
   426     delete d_ptr->surface;
       
   427     delete d_ptr;
       
   428 }
       
   429 
       
   430 QMediaObject *QGraphicsVideoItem::mediaObject() const
       
   431 {
       
   432     return d_func()->mediaObject;
       
   433 }
       
   434 
       
   435 bool QGraphicsVideoItem::setMediaObject(QMediaObject *object)
       
   436 {
       
   437     Q_D(QGraphicsVideoItem);
       
   438 
       
   439     if (object == d->mediaObject)
       
   440         return true;
       
   441 
       
   442     d->clearService();
       
   443 
       
   444     d->mediaObject = object;
       
   445 
       
   446     if (d->mediaObject) {
       
   447         d->service = d->mediaObject->service();
       
   448 
       
   449         if (d->service) {
       
   450             d->rendererControl = qobject_cast<QVideoRendererControl *>(
       
   451                     d->service->requestControl(QVideoRendererControl_iid));
       
   452 
       
   453             if (d->rendererControl != 0) {
       
   454                 connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed()));
       
   455                 d->rendererControl->setSurface(d->surface);
       
   456                 return true;
       
   457             }
       
   458 
       
   459         }
       
   460     }
       
   461 
       
   462     return false;
       
   463 }
       
   464 
       
   465 Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const
       
   466 {
       
   467     return d_func()->aspectRatioMode;
       
   468 }
       
   469 
       
   470 void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode)
       
   471 {
       
   472     Q_D(QGraphicsVideoItem);
       
   473 
       
   474     d->aspectRatioMode = mode;
       
   475     d->updateRects();
       
   476 }
       
   477 
       
   478 QPointF QGraphicsVideoItem::offset() const
       
   479 {
       
   480     return d_func()->rect.topLeft();
       
   481 }
       
   482 
       
   483 void QGraphicsVideoItem::setOffset(const QPointF &offset)
       
   484 {
       
   485     Q_D(QGraphicsVideoItem);
       
   486 
       
   487     d->rect.moveTo(offset);
       
   488     d->updateRects();
       
   489 }
       
   490 
       
   491 QSizeF QGraphicsVideoItem::size() const
       
   492 {
       
   493     return d_func()->rect.size();
       
   494 }
       
   495 
       
   496 void QGraphicsVideoItem::setSize(const QSizeF &size)
       
   497 {
       
   498     Q_D(QGraphicsVideoItem);
       
   499 
       
   500     d->rect.setSize(size.isValid() ? size : QSizeF(0, 0));
       
   501     d->updateRects();
       
   502 }
       
   503 
       
   504 QSizeF QGraphicsVideoItem::nativeSize() const
       
   505 {
       
   506     return d_func()->nativeSize;
       
   507 }
       
   508 
       
   509 QRectF QGraphicsVideoItem::boundingRect() const
       
   510 {
       
   511     return d_func()->boundingRect;
       
   512 }
       
   513 
       
   514 void QGraphicsVideoItem::paint(
       
   515         QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
       
   516 {
       
   517     qDebug() << "QGraphicsVideoItem::paint";
       
   518     Q_UNUSED(option);
       
   519     Q_D(QGraphicsVideoItem);
       
   520 
       
   521     QGraphicsView *view = 0;
       
   522     if (scene() && !scene()->views().isEmpty())
       
   523         view = scene()->views().first();
       
   524 
       
   525     //it's necessary to switch vieport update mode to FullViewportUpdate
       
   526     //otherwise the video item area can be just scrolled without notifying overlay
       
   527     //about geometry changes
       
   528     if (view != d->currentView) {
       
   529         if (d->currentView) {
       
   530             d->currentView->setViewportUpdateMode(d->savedViewportUpdateMode);
       
   531         }
       
   532 
       
   533         d->currentView = view;
       
   534         if (view) {
       
   535             d->savedViewportUpdateMode = view->viewportUpdateMode();
       
   536             view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
       
   537         }
       
   538     }
       
   539 
       
   540     QColor colorKey = Qt::black;
       
   541     bool geometryChanged = false;
       
   542 
       
   543     if (d->surface) {
       
   544         if (widget)
       
   545             d->surface->setWinId(widget->winId());
       
   546 
       
   547         QTransform transform = painter->combinedTransform();
       
   548         QRect overlayRect = transform.mapRect(boundingRect()).toRect();
       
   549         QRect currentSurfaceRect = d->surface->displayRect();
       
   550 
       
   551         if (widget) {
       
   552             //workaround for xvideo issue with U/V planes swapped
       
   553             QPoint topLeft = widget->mapToGlobal(overlayRect.topLeft());
       
   554             if ((topLeft.x() & 1) == 0)
       
   555                 overlayRect.moveLeft(overlayRect.left()-1);
       
   556         }
       
   557 
       
   558         d->overlayRect = overlayRect;
       
   559 
       
   560         if (currentSurfaceRect != overlayRect) {
       
   561             if (!d->surface->displayRect().isEmpty()) {
       
   562                 if (d->softwareRenderingEnabled) {
       
   563                     //recalculate scaled frame pixmap if area is resized
       
   564                     if (currentSurfaceRect.size() != overlayRect.size()) {
       
   565                         d->updateLastFrame();
       
   566                         d->surface->setDisplayRect( overlayRect );
       
   567                     }
       
   568                 } else {
       
   569                     d->softwareRenderingEnabled = true;
       
   570                     d->updateLastFrame();
       
   571 
       
   572                     //don't set new geometry right now,
       
   573                     //but with small delay, to ensure the frame is already
       
   574                     //rendered on top of color key
       
   575                     if (!d->geometryUpdateTimer.isActive())
       
   576                         d->geometryUpdateTimer.start(GEOMETRY_UPDATE_DELAY, this);
       
   577                 }
       
   578             } else
       
   579                 d->surface->setDisplayRect( overlayRect );
       
   580 
       
   581             geometryChanged = true;
       
   582             d->softwareRenderingTimer.start(SOFTWARE_RENDERING_DURATION, this);
       
   583 
       
   584             //qDebug() << "set video display rect:" << deviceRect;
       
   585 
       
   586         }
       
   587 
       
   588         colorKey = d->surface->colorKey();
       
   589     }
       
   590 
       
   591 
       
   592     if (!d->softwareRenderingEnabled) {
       
   593         painter->fillRect(d->boundingRect, colorKey);
       
   594     } else {
       
   595         if (!d->lastFrame.isNull()) {
       
   596             painter->drawPixmap(d->boundingRect.topLeft(), d->lastFrame );
       
   597 
       
   598         } else
       
   599             painter->fillRect(d->boundingRect, Qt::black);
       
   600     }
       
   601 }
       
   602 
       
   603 QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value)
       
   604 {
       
   605     Q_D(QGraphicsVideoItem);
       
   606 
       
   607     if (change == ItemScenePositionHasChanged) {
       
   608         update(boundingRect());
       
   609     } else {
       
   610         return QGraphicsItem::itemChange(change, value);
       
   611     }
       
   612 
       
   613     return value;
       
   614 }
       
   615 
       
   616 void QGraphicsVideoItem::timerEvent(QTimerEvent *event)
       
   617 {
       
   618     Q_D(QGraphicsVideoItem);
       
   619 
       
   620     if (event->timerId() == d->softwareRenderingTimer.timerId() && d->softwareRenderingEnabled) {
       
   621         d->softwareRenderingTimer.stop();
       
   622         d->softwareRenderingEnabled = false;
       
   623         d->updateLastFrame();
       
   624         // repaint last frame, to ensure geometry change is applyed in paused state
       
   625         d->surface->repaintLastFrame();
       
   626         d->_q_present();
       
   627     } else if ((event->timerId() == d->geometryUpdateTimer.timerId())) {
       
   628         d->geometryUpdateTimer.stop();
       
   629         //slightly delayed geometry update,
       
   630         //to avoid flicker at the first geometry change
       
   631         d->surface->setDisplayRect( d->overlayRect );
       
   632     }
       
   633 
       
   634     QGraphicsObject::timerEvent(event);
       
   635 }
       
   636 
       
   637 #include "moc_qgraphicsvideoitem.cpp"
       
   638 QT_END_NAMESPACE