qtmobility/src/multimedia/qgraphicsvideoitem_maemo5.cpp
changeset 4 90517678cc4f
parent 1 2b40d63a9c3d
child 5 453da2cfceef
equal deleted inserted replaced
1:2b40d63a9c3d 4:90517678cc4f
    38 ** $QT_END_LICENSE$
    38 ** $QT_END_LICENSE$
    39 **
    39 **
    40 ****************************************************************************/
    40 ****************************************************************************/
    41 
    41 
    42 #include <QtCore/qpointer.h>
    42 #include <QtCore/qpointer.h>
       
    43 #include <QtCore/qdatetime.h>
       
    44 #include <QtCore/qbasictimer.h>
       
    45 #include <QtCore/qcoreevent.h>
    43 #include <QtGui/qgraphicsscene.h>
    46 #include <QtGui/qgraphicsscene.h>
    44 #include <QtGui/qgraphicsview.h>
    47 #include <QtGui/qgraphicsview.h>
    45 #include <QtGui/qscrollbar.h>
    48 #include <QtGui/qscrollbar.h>
    46 #include <QtGui/qx11info_x11.h>
    49 #include <QtGui/qx11info_x11.h>
    47 
    50 
    48 #include <qgraphicsvideoitem.h>
    51 #include "qgraphicsvideoitem.h"
    49 
    52 
    50 #include <qmediaobject.h>
    53 #include "qmediaobject.h"
    51 #include <qmediaservice.h>
    54 #include "qmediaservice.h"
    52 #include <qpaintervideosurface_p.h>
    55 #include "qpaintervideosurface_p.h"
    53 #include <qvideooutputcontrol.h>
    56 #include "qvideooutputcontrol.h"
    54 #include <qvideorenderercontrol.h>
    57 #include "qvideorenderercontrol.h"
    55 
    58 
    56 #include <QtMultimedia/qvideosurfaceformat.h>
    59 #include <QtMultimedia/qvideosurfaceformat.h>
    57 
    60 
    58 #include <qxvideosurface_maemo5_p.h>
    61 #include "qxvideosurface_maemo5_p.h"
       
    62 
    59 
    63 
    60 QTM_BEGIN_NAMESPACE
    64 QTM_BEGIN_NAMESPACE
       
    65 
       
    66 //update overlay geometry slightly later,
       
    67 //to ensure color key is alredy replaced with static frame
       
    68 #define GEOMETRY_UPDATE_DELAY 20
       
    69 //this is necessary to prevent flickering, see maemo bug 8798
       
    70 //on geometry changes, the color key is replaced with static image frame
       
    71 //until the overlay is re-initialized
       
    72 #define SOFTWARE_RENDERING_DURATION 150
       
    73 
       
    74 #ifdef  __ARM_NEON__
       
    75 
       
    76 /*
       
    77 * ARM NEON optimized implementation of UYVY -> RGB16 convertor
       
    78 */
       
    79 static void uyvy422_to_rgb16_line_neon (uint8_t * dst, const uint8_t * src, int n)
       
    80 {
       
    81      /* and this is the NEON code itself */
       
    82      static __attribute__ ((aligned (16))) uint16_t acc_r[8] = {
       
    83        22840, 22840, 22840, 22840, 22840, 22840, 22840, 22840,
       
    84      };
       
    85      static __attribute__ ((aligned (16))) uint16_t acc_g[8] = {
       
    86        17312, 17312, 17312, 17312, 17312, 17312, 17312, 17312,
       
    87      };
       
    88      static __attribute__ ((aligned (16))) uint16_t acc_b[8] = {
       
    89        28832, 28832, 28832, 28832, 28832, 28832, 28832, 28832,
       
    90      };
       
    91      /*
       
    92       * Registers:
       
    93       * q0, q1 : d0, d1, d2, d3  - are used for initial loading of YUV data
       
    94       * q2     : d4, d5          - are used for storing converted RGB data
       
    95       * q3     : d6, d7          - are used for temporary storage
       
    96       *
       
    97       * q6     : d12, d13        - are used for converting to RGB16
       
    98       * q7     : d14, d15        - are used for storing RGB16 data
       
    99       * q4-q5 - reserved
       
   100       *
       
   101       * q8, q9 : d16, d17, d18, d19  - are used for expanded Y data
       
   102       * q10    : d20, d21
       
   103       * q11    : d22, d23
       
   104       * q12    : d24, d25
       
   105       * q13    : d26, d27
       
   106       * q13, q14, q15            - various constants (#16, #149, #204, #50, #104, #154)
       
   107       */
       
   108      asm volatile (".macro convert_macroblock size\n"
       
   109          /* load up to 16 source pixels in UYVY format */
       
   110          ".if \\size == 16\n"
       
   111          "pld [%[src], #128]\n"
       
   112          "vld1.32 {d0, d1, d2, d3}, [%[src]]!\n"
       
   113          ".elseif \\size == 8\n"
       
   114          "vld1.32 {d0, d1}, [%[src]]!\n"
       
   115          ".elseif \\size == 4\n"
       
   116          "vld1.32 {d0}, [%[src]]!\n"
       
   117          ".elseif \\size == 2\n"
       
   118          "vld1.32 {d0[0]}, [%[src]]!\n"
       
   119          ".else\n" ".error \"unsupported macroblock size\"\n" ".endif\n"
       
   120          /* convert from 'packed' to 'planar' representation */
       
   121          "vuzp.8      d0, d1\n"    /* d1 - separated Y data (first 8 bytes) */
       
   122          "vuzp.8      d2, d3\n"    /* d3 - separated Y data (next 8 bytes) */
       
   123          "vuzp.8      d0, d2\n"    /* d0 - separated U data, d2 - separated V data */
       
   124          /* split even and odd Y color components */
       
   125          "vuzp.8      d1, d3\n"    /* d1 - evenY, d3 - oddY */
       
   126          /* clip upper and lower boundaries */
       
   127          "vqadd.u8    q0, q0, q4\n"
       
   128          "vqadd.u8    q1, q1, q4\n"
       
   129          "vqsub.u8    q0, q0, q5\n"
       
   130          "vqsub.u8    q1, q1, q5\n"
       
   131          "vshr.u8     d4, d2, #1\n"    /* d4 = V >> 1 */
       
   132          "vmull.u8    q8, d1, d27\n"       /* q8 = evenY * 149 */
       
   133          "vmull.u8    q9, d3, d27\n"       /* q9 = oddY * 149 */
       
   134          "vld1.16     {d20, d21}, [%[acc_r], :128]\n"      /* q10 - initialize accumulator for red */
       
   135          "vsubw.u8    q10, q10, d4\n"      /* red acc -= (V >> 1) */
       
   136          "vmlsl.u8    q10, d2, d28\n"      /* red acc -= V * 204 */
       
   137          "vld1.16     {d22, d23}, [%[acc_g], :128]\n"      /* q11 - initialize accumulator for green */
       
   138          "vmlsl.u8    q11, d2, d30\n"      /* green acc -= V * 104 */
       
   139          "vmlsl.u8    q11, d0, d29\n"      /* green acc -= U * 50 */
       
   140          "vld1.16     {d24, d25}, [%[acc_b], :128]\n"      /* q12 - initialize accumulator for blue */
       
   141          "vmlsl.u8    q12, d0, d30\n"      /* blue acc -= U * 104 */
       
   142          "vmlsl.u8    q12, d0, d31\n"      /* blue acc -= U * 154 */
       
   143          "vhsub.s16   q3, q8, q10\n"       /* calculate even red components */
       
   144          "vhsub.s16   q10, q9, q10\n"      /* calculate odd red components */
       
   145          "vqshrun.s16 d0, q3, #6\n"        /* right shift, narrow and saturate even red components */
       
   146          "vqshrun.s16 d3, q10, #6\n"       /* right shift, narrow and saturate odd red components */
       
   147          "vhadd.s16   q3, q8, q11\n"       /* calculate even green components */
       
   148          "vhadd.s16   q11, q9, q11\n"      /* calculate odd green components */
       
   149          "vqshrun.s16 d1, q3, #6\n"        /* right shift, narrow and saturate even green components */
       
   150          "vqshrun.s16 d4, q11, #6\n"       /* right shift, narrow and saturate odd green components */
       
   151          "vhsub.s16   q3, q8, q12\n"       /* calculate even blue components */
       
   152          "vhsub.s16   q12, q9, q12\n"      /* calculate odd blue components */
       
   153          "vqshrun.s16 d2, q3, #6\n"        /* right shift, narrow and saturate even blue components */
       
   154          "vqshrun.s16 d5, q12, #6\n"       /* right shift, narrow and saturate odd blue components */
       
   155          "vzip.8      d0, d3\n"    /* join even and odd red components */
       
   156          "vzip.8      d1, d4\n"    /* join even and odd green components */
       
   157          "vzip.8      d2, d5\n"    /* join even and odd blue components */
       
   158          "vshll.u8     q7, d0, #8\n" //red
       
   159          "vshll.u8     q6, d1, #8\n" //greed
       
   160          "vsri.u16   q7, q6, #5\n"
       
   161          "vshll.u8     q6, d2, #8\n" //blue
       
   162          "vsri.u16   q7, q6, #11\n" //now there is rgb16 in q7
       
   163          ".if \\size == 16\n"
       
   164          "vst1.16 {d14, d15}, [%[dst]]!\n"
       
   165          //"vst3.8  {d0, d1, d2}, [%[dst]]!\n"
       
   166          "vshll.u8     q7, d3, #8\n" //red
       
   167          "vshll.u8     q6, d4, #8\n" //greed
       
   168          "vsri.u16   q7, q6, #5\n"
       
   169          "vshll.u8     q6, d5, #8\n" //blue
       
   170          "vsri.u16   q7, q6, #11\n" //now there is rgb16 in q7
       
   171          //"vst3.8  {d3, d4, d5}, [%[dst]]!\n"
       
   172          "vst1.16 {d14, d15}, [%[dst]]!\n"
       
   173          ".elseif \\size == 8\n"
       
   174          "vst1.16 {d14, d15}, [%[dst]]!\n"
       
   175          //"vst3.8  {d0, d1, d2}, [%[dst]]!\n"
       
   176          ".elseif \\size == 4\n"
       
   177          "vst1.8 {d14}, [%[dst]]!\n"
       
   178          ".elseif \\size == 2\n"
       
   179          "vst1.8 {d14[0]}, [%[dst]]!\n"
       
   180          "vst1.8 {d14[1]}, [%[dst]]!\n"
       
   181          ".else\n"
       
   182          ".error \"unsupported macroblock size\"\n"
       
   183          ".endif\n"
       
   184          ".endm\n"
       
   185          "vmov.u8     d8, #15\n"  /* add this to U/V to saturate upper boundary */
       
   186          "vmov.u8     d9, #20\n"   /* add this to Y to saturate upper boundary */
       
   187          "vmov.u8     d10, #31\n"  /* sub this from U/V to saturate lower boundary */
       
   188          "vmov.u8     d11, #36\n"  /* sub this from Y to saturate lower boundary */
       
   189          "vmov.u8     d26, #16\n"
       
   190          "vmov.u8     d27, #149\n"
       
   191          "vmov.u8     d28, #204\n"
       
   192          "vmov.u8     d29, #50\n"
       
   193          "vmov.u8     d30, #104\n"
       
   194          "vmov.u8     d31, #154\n"
       
   195          "subs        %[n], %[n], #16\n"
       
   196          "blt         2f\n"
       
   197          "1:\n"
       
   198          "convert_macroblock 16\n"
       
   199          "subs        %[n], %[n], #16\n"
       
   200          "bge         1b\n"
       
   201          "2:\n"
       
   202          "tst         %[n], #8\n"
       
   203          "beq         3f\n"
       
   204          "convert_macroblock 8\n"
       
   205          "3:\n"
       
   206          "tst         %[n], #4\n"
       
   207          "beq         4f\n"
       
   208          "convert_macroblock 4\n"
       
   209          "4:\n"
       
   210          "tst         %[n], #2\n"
       
   211          "beq         5f\n"
       
   212          "convert_macroblock 2\n"
       
   213          "5:\n"
       
   214          ".purgem convert_macroblock\n":[src] "+&r" (src),[dst] "+&r" (dst),
       
   215          [n] "+&r" (n)
       
   216          :[acc_r] "r" (&acc_r[0]),[acc_g] "r" (&acc_g[0]),[acc_b] "r" (&acc_b[0])
       
   217          :"cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
       
   218          "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
       
   219          "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31");
       
   220 }
       
   221 
       
   222 #endif
    61 
   223 
    62 class QGraphicsVideoItemPrivate
   224 class QGraphicsVideoItemPrivate
    63 {
   225 {
    64 public:
   226 public:
    65     QGraphicsVideoItemPrivate()
   227     QGraphicsVideoItemPrivate()
    70         , outputControl(0)
   232         , outputControl(0)
    71         , rendererControl(0)
   233         , rendererControl(0)
    72         , savedViewportUpdateMode(QGraphicsView::FullViewportUpdate)
   234         , savedViewportUpdateMode(QGraphicsView::FullViewportUpdate)
    73         , aspectRatioMode(Qt::KeepAspectRatio)
   235         , aspectRatioMode(Qt::KeepAspectRatio)
    74         , rect(0.0, 0.0, 320, 240)
   236         , rect(0.0, 0.0, 320, 240)
       
   237         , softwareRenderingEnabled(false)
    75     {
   238     {
    76     }
   239     }
    77 
   240 
    78     QGraphicsVideoItem *q_ptr;
   241     QGraphicsVideoItem *q_ptr;
    79 
   242 
    89     QRectF rect;
   252     QRectF rect;
    90     QRectF boundingRect;
   253     QRectF boundingRect;
    91     QRectF sourceRect;
   254     QRectF sourceRect;
    92     QSizeF nativeSize;
   255     QSizeF nativeSize;
    93 
   256 
       
   257     QPixmap lastFrame;
       
   258     QBasicTimer softwareRenderingTimer;
       
   259     QBasicTimer geometryUpdateTimer;
       
   260     bool softwareRenderingEnabled;
       
   261     QRect overlayRect;
       
   262 
    94     void clearService();
   263     void clearService();
    95     void updateRects();
   264     void updateRects();
       
   265     void updateLastFrame();
    96 
   266 
    97     void _q_present();
   267     void _q_present();
    98     void _q_formatChanged(const QVideoSurfaceFormat &format);
   268     void _q_formatChanged(const QVideoSurfaceFormat &format);
    99     void _q_serviceDestroyed();
   269     void _q_serviceDestroyed();
   100     void _q_mediaObjectDestroyed();
   270     void _q_mediaObjectDestroyed();
   144                 0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height());
   314                 0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height());
   145         sourceRect.moveCenter(QPointF(0.5, 0.5));
   315         sourceRect.moveCenter(QPointF(0.5, 0.5));
   146     }
   316     }
   147 }
   317 }
   148 
   318 
       
   319 void QGraphicsVideoItemPrivate::updateLastFrame()
       
   320 {
       
   321     lastFrame = QPixmap();
       
   322 
       
   323     if (!softwareRenderingEnabled)
       
   324         return;
       
   325 
       
   326     QVideoFrame lastVideoFrame = surface->lastFrame();
       
   327 
       
   328     if (!lastVideoFrame.isValid())
       
   329         return;
       
   330 
       
   331     if (lastVideoFrame.map(QAbstractVideoBuffer::ReadOnly)) {
       
   332 
       
   333 #ifdef  __ARM_NEON__
       
   334         if (lastVideoFrame.pixelFormat() == QVideoFrame::Format_UYVY) {
       
   335             QImage lastImage(lastVideoFrame.size(), QImage::Format_RGB16);
       
   336 
       
   337             const uchar *src = lastVideoFrame.bits();
       
   338             uchar *dst = lastImage.bits();
       
   339             const int srcLineStep = lastVideoFrame.bytesPerLine();
       
   340             const int dstLineStep = lastImage.bytesPerLine();
       
   341             const int h = lastVideoFrame.height();
       
   342             const int w = lastVideoFrame.width();
       
   343 
       
   344             for (int y=0; y<h; y++) {
       
   345                 uyvy422_to_rgb16_line_neon(dst, src, w);
       
   346                 src += srcLineStep;
       
   347                 dst += dstLineStep;
       
   348             }
       
   349             lastFrame = QPixmap::fromImage(
       
   350                 lastImage.scaled(boundingRect.size().toSize(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
       
   351         } else
       
   352 #endif
       
   353         {
       
   354             QImage::Format imgFormat = QVideoFrame::imageFormatFromPixelFormat(lastVideoFrame.pixelFormat());
       
   355 
       
   356             if (imgFormat != QImage::Format_Invalid) {
       
   357                 QImage lastImage(lastVideoFrame.bits(),
       
   358                                  lastVideoFrame.width(),
       
   359                                  lastVideoFrame.height(),
       
   360                                  lastVideoFrame.bytesPerLine(),
       
   361                                  imgFormat);
       
   362 
       
   363                 lastFrame = QPixmap::fromImage(
       
   364                         lastImage.scaled(boundingRect.size().toSize(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
       
   365             }
       
   366         }
       
   367 
       
   368         lastVideoFrame.unmap();
       
   369     }
       
   370 
       
   371 }
       
   372 
   149 void QGraphicsVideoItemPrivate::_q_present()
   373 void QGraphicsVideoItemPrivate::_q_present()
   150 {
   374 {
   151     q_ptr->update(boundingRect);
   375     q_ptr->update(boundingRect);
   152 }
   376 }
   153 
   377 
   154 void QGraphicsVideoItemPrivate::_q_formatChanged(const QVideoSurfaceFormat &format)
   378 void QGraphicsVideoItemPrivate::_q_formatChanged(const QVideoSurfaceFormat &format)
   155 {
   379 {
   156     nativeSize = format.sizeHint();
   380     nativeSize = format.sizeHint();
       
   381     lastFrame = QPixmap();
   157 
   382 
   158     updateRects();
   383     updateRects();
   159 
   384 
   160     emit q_ptr->nativeSizeChanged(nativeSize);
   385     emit q_ptr->nativeSizeChanged(nativeSize);
   161 }
   386 }
   174     mediaObject = 0;
   399     mediaObject = 0;
   175 
   400 
   176     clearService();
   401     clearService();
   177 }
   402 }
   178 
   403 
   179 /*!
       
   180     \class QGraphicsVideoItem
       
   181 
       
   182     \brief The QGraphicsVideoItem class provides a graphics item which display video produced by a QMediaObject.
       
   183 
       
   184     \ingroup multimedia
       
   185 
       
   186     Attaching a QGraphicsVideoItem to a QMediaObject allows it to display
       
   187     the video or image output of that media object.  A QGraphicsVideoItem
       
   188     is attached to a media object by passing a pointer to the QMediaObject
       
   189     to the setMediaObject() function.
       
   190 
       
   191     \code
       
   192     player = new QMediaPlayer(this);
       
   193 
       
   194     QGraphicsVideoItem *item = new QGraphicsVideoItem;
       
   195     item->setMediaObject(player);
       
   196     graphicsView->scence()->addItem(item);
       
   197     graphicsView->show();
       
   198 
       
   199     player->setMedia(video);
       
   200     player->play();
       
   201     \endcode
       
   202 
       
   203     \bold {Note}: Only a single display output can be attached to a media object at one time.
       
   204 
       
   205     \sa QMediaObject, QMediaPlayer, QVideoWidget
       
   206 */
       
   207 
       
   208 /*!
       
   209     \enum QGraphicsVideoItem::FillMode
       
   210 
       
   211     Enumerates the methods of scaling a video to fit a graphics item.
       
   212 
       
   213     \value Stretch The video is stretched to fit the item's size.
       
   214     \value PreserveAspectFit The video is uniformly scaled to fix the item's
       
   215     size without cropping.
       
   216     \value PreserveAspectCrop The video is uniformly scaled to fill the item's
       
   217     size, cropping if necessary.
       
   218 */
       
   219 
       
   220 /*!
       
   221     Constructs a graphics item that displays video.
       
   222 
       
   223     The \a parent is passed to QGraphicsItem.
       
   224 */
       
   225 QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent)
   404 QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent)
   226     : QGraphicsObject(parent)
   405     : QGraphicsObject(parent)
   227     , d_ptr(new QGraphicsVideoItemPrivate)
   406     , d_ptr(new QGraphicsVideoItemPrivate)
   228 {
   407 {
   229     d_ptr->q_ptr = this;
   408     d_ptr->q_ptr = this;
   238             this, SLOT(_q_formatChanged(QVideoSurfaceFormat)));
   417             this, SLOT(_q_formatChanged(QVideoSurfaceFormat)));
   239 
   418 
   240     connect(d_ptr->surface, SIGNAL(activeChanged(bool)), this, SLOT(_q_present()));
   419     connect(d_ptr->surface, SIGNAL(activeChanged(bool)), this, SLOT(_q_present()));
   241 }
   420 }
   242 
   421 
   243 /*!
       
   244     Destroys a video graphics item.
       
   245 */
       
   246 QGraphicsVideoItem::~QGraphicsVideoItem()
   422 QGraphicsVideoItem::~QGraphicsVideoItem()
   247 {
   423 {
   248 
   424 
   249     if (d_ptr->outputControl)
   425     if (d_ptr->outputControl)
   250         d_ptr->outputControl->setOutput(QVideoOutputControl::NoOutput);
   426         d_ptr->outputControl->setOutput(QVideoOutputControl::NoOutput);
   256         d_ptr->currentView->setViewportUpdateMode(d_ptr->savedViewportUpdateMode);
   432         d_ptr->currentView->setViewportUpdateMode(d_ptr->savedViewportUpdateMode);
   257 
   433 
   258     delete d_ptr->surface;
   434     delete d_ptr->surface;
   259     delete d_ptr;
   435     delete d_ptr;
   260 }
   436 }
   261 
       
   262 /*!
       
   263     \property QGraphicsVideoItem::mediaObject
       
   264     \brief the media object which provides the video displayed by a graphics item.
       
   265 */
       
   266 
   437 
   267 QMediaObject *QGraphicsVideoItem::mediaObject() const
   438 QMediaObject *QGraphicsVideoItem::mediaObject() const
   268 {
   439 {
   269     return d_func()->mediaObject;
   440     return d_func()->mediaObject;
   270 }
   441 }
   308             }
   479             }
   309         }
   480         }
   310     }
   481     }
   311 }
   482 }
   312 
   483 
   313 /*!
       
   314     \property QGraphicsVideoItem::aspectRatioMode
       
   315     \brief how a video is scaled to fit the graphics item's size.
       
   316 */
       
   317 
       
   318 Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const
   484 Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const
   319 {
   485 {
   320     return d_func()->aspectRatioMode;
   486     return d_func()->aspectRatioMode;
   321 }
   487 }
   322 
   488 
   326 
   492 
   327     d->aspectRatioMode = mode;
   493     d->aspectRatioMode = mode;
   328     d->updateRects();
   494     d->updateRects();
   329 }
   495 }
   330 
   496 
   331 /*!
       
   332     \property QGraphicsVideoItem::offset
       
   333     \brief the video item's offset.
       
   334 
       
   335     QGraphicsVideoItem will draw video using the offset for its top left
       
   336     corner.
       
   337 */
       
   338 
       
   339 QPointF QGraphicsVideoItem::offset() const
   497 QPointF QGraphicsVideoItem::offset() const
   340 {
   498 {
   341     return d_func()->rect.topLeft();
   499     return d_func()->rect.topLeft();
   342 }
   500 }
   343 
   501 
   347 
   505 
   348     d->rect.moveTo(offset);
   506     d->rect.moveTo(offset);
   349     d->updateRects();
   507     d->updateRects();
   350 }
   508 }
   351 
   509 
   352 /*!
       
   353     \property QGraphicsVideoItem::size
       
   354     \brief the video item's size.
       
   355 
       
   356     QGraphicsVideoItem will draw video scaled to fit size according to its
       
   357     fillMode.
       
   358 */
       
   359 
       
   360 QSizeF QGraphicsVideoItem::size() const
   510 QSizeF QGraphicsVideoItem::size() const
   361 {
   511 {
   362     return d_func()->rect.size();
   512     return d_func()->rect.size();
   363 }
   513 }
   364 
   514 
   368 
   518 
   369     d->rect.setSize(size.isValid() ? size : QSizeF(0, 0));
   519     d->rect.setSize(size.isValid() ? size : QSizeF(0, 0));
   370     d->updateRects();
   520     d->updateRects();
   371 }
   521 }
   372 
   522 
   373 /*!
       
   374     \property QGraphicsVideoItem::nativeSize
       
   375     \brief the native size of the video.
       
   376 */
       
   377 
       
   378 QSizeF QGraphicsVideoItem::nativeSize() const
   523 QSizeF QGraphicsVideoItem::nativeSize() const
   379 {
   524 {
   380     return d_func()->nativeSize;
   525     return d_func()->nativeSize;
   381 }
   526 }
   382 
   527 
   383 /*!
       
   384     \fn QGraphicsVideoItem::nativeSizeChanged(const QSizeF &size)
       
   385 
       
   386     Signals that the native \a size of the video has changed.
       
   387 */
       
   388 
       
   389 
       
   390 /*!
       
   391     \reimp
       
   392 */
       
   393 QRectF QGraphicsVideoItem::boundingRect() const
   528 QRectF QGraphicsVideoItem::boundingRect() const
   394 {
   529 {
   395     return d_func()->boundingRect;
   530     return d_func()->boundingRect;
   396 }
   531 }
   397 
   532 
   398 
       
   399 /*!
       
   400     \reimp
       
   401 */
       
   402 void QGraphicsVideoItem::paint(
   533 void QGraphicsVideoItem::paint(
   403         QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
   534         QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
   404 {
   535 {
       
   536     qDebug() << "QGraphicsVideoItem::paint";
   405     Q_UNUSED(option);
   537     Q_UNUSED(option);
   406     Q_D(QGraphicsVideoItem);
   538     Q_D(QGraphicsVideoItem);
   407 
       
   408     //qDebug() << "paint video item on widget" << widget;
       
   409 
   539 
   410     QGraphicsView *view = 0;
   540     QGraphicsView *view = 0;
   411     if (scene() && !scene()->views().isEmpty())
   541     if (scene() && !scene()->views().isEmpty())
   412         view = scene()->views().first();
   542         view = scene()->views().first();
   413 
   543 
   415     //otherwise the video item area can be just scrolled without notifying overlay
   545     //otherwise the video item area can be just scrolled without notifying overlay
   416     //about geometry changes
   546     //about geometry changes
   417     if (view != d->currentView) {
   547     if (view != d->currentView) {
   418         if (d->currentView) {
   548         if (d->currentView) {
   419             d->currentView->setViewportUpdateMode(d->savedViewportUpdateMode);
   549             d->currentView->setViewportUpdateMode(d->savedViewportUpdateMode);
   420             /*disconnect(d->currentView->verticalScrollBar(), SIGNAL(valueChanged(int)),
       
   421                        this, SLOT(_q_present()));
       
   422             disconnect(d->currentView->horizontalScrollBar(), SIGNAL(valueChanged(int)),
       
   423                        this, SLOT(_q_present()));*/
       
   424         }
   550         }
   425 
   551 
   426         d->currentView = view;
   552         d->currentView = view;
   427         if (view) {
   553         if (view) {
   428             d->savedViewportUpdateMode = view->viewportUpdateMode();
   554             d->savedViewportUpdateMode = view->viewportUpdateMode();
   429             view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
   555             view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
   430             /*connect(d->currentView->verticalScrollBar(), SIGNAL(valueChanged(int)),
       
   431                     this, SLOT(_q_present()));
       
   432             connect(d->currentView->horizontalScrollBar(), SIGNAL(valueChanged(int)),
       
   433                     this, SLOT(_q_present()));*/
       
   434         }
   556         }
   435     }
   557     }
   436 
   558 
   437     QColor colorKey = Qt::black;
   559     QColor colorKey = Qt::black;
       
   560     bool geometryChanged = false;
   438 
   561 
   439     if (d->surface) {
   562     if (d->surface) {
   440         if (widget)
   563         if (widget)
   441             d->surface->setWinId(widget->winId());
   564             d->surface->setWinId(widget->winId());
   442 
   565 
   443         QTransform transform = painter->combinedTransform();
   566         QTransform transform = painter->combinedTransform();
   444         QRect deviceRect = transform.mapRect(boundingRect()).toRect();
   567         QRect overlayRect = transform.mapRect(boundingRect()).toRect();
       
   568         QRect currentSurfaceRect = d->surface->displayRect();
   445 
   569 
   446         if (widget) {
   570         if (widget) {
   447             //workaround for xvideo issue with U/V planes swapped
   571             //workaround for xvideo issue with U/V planes swapped
   448             QPoint topLeft = widget->mapToGlobal(deviceRect.topLeft());
   572             QPoint topLeft = widget->mapToGlobal(overlayRect.topLeft());
   449             if ((topLeft.x() & 1) == 0)
   573             if ((topLeft.x() & 1) == 0)
   450                 deviceRect.moveLeft(deviceRect.left()-1);
   574                 overlayRect.moveLeft(overlayRect.left()-1);
   451         }
   575         }
   452 
   576 
   453         if (d->surface->displayRect() != deviceRect) {
   577         d->overlayRect = overlayRect;
       
   578 
       
   579         if (currentSurfaceRect != overlayRect) {
       
   580             if (!d->surface->displayRect().isEmpty()) {
       
   581                 if (d->softwareRenderingEnabled) {
       
   582                     //recalculate scaled frame pixmap if area is resized
       
   583                     if (currentSurfaceRect.size() != overlayRect.size()) {
       
   584                         d->updateLastFrame();
       
   585                         d->surface->setDisplayRect( overlayRect );
       
   586                     }
       
   587                 } else {
       
   588                     d->softwareRenderingEnabled = true;
       
   589                     d->updateLastFrame();
       
   590 
       
   591                     //don't set new geometry right now,
       
   592                     //but with small delay, to ensure the frame is already
       
   593                     //rendered on top of color key
       
   594                     if (!d->geometryUpdateTimer.isActive())
       
   595                         d->geometryUpdateTimer.start(GEOMETRY_UPDATE_DELAY, this);
       
   596                 }
       
   597             } else
       
   598                 d->surface->setDisplayRect( overlayRect );
       
   599 
       
   600             geometryChanged = true;
       
   601             d->softwareRenderingTimer.start(SOFTWARE_RENDERING_DURATION, this);
       
   602 
   454             //qDebug() << "set video display rect:" << deviceRect;
   603             //qDebug() << "set video display rect:" << deviceRect;
   455             d->surface->setDisplayRect( deviceRect );
   604 
   456             // repaint last frame after the color key area is filled
       
   457             QMetaObject::invokeMethod(d->surface, "repaintLastFrame", Qt::QueuedConnection);
       
   458         }
   605         }
   459 
   606 
   460         colorKey = d->surface->colorKey();
   607         colorKey = d->surface->colorKey();
   461     }
   608     }
   462 
   609 
   463     painter->fillRect(d->boundingRect, colorKey);
   610 
   464 }
   611     if (!d->softwareRenderingEnabled) {
   465 
   612         painter->fillRect(d->boundingRect, colorKey);
   466 /*!
   613     } else {
   467     \reimp
   614         if (!d->lastFrame.isNull()) {
   468 
   615             painter->drawPixmap(d->boundingRect.topLeft(), d->lastFrame );
   469     \internal
   616 
   470 */
   617         } else
       
   618             painter->fillRect(d->boundingRect, Qt::black);
       
   619     }
       
   620 }
       
   621 
   471 QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value)
   622 QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value)
   472 {
   623 {
   473     Q_D(QGraphicsVideoItem);
   624     Q_D(QGraphicsVideoItem);
   474 
   625 
   475     if (change == ItemVisibleChange && d->outputControl != 0 && d->rendererControl != 0) {
   626     if (change == ItemVisibleChange && d->outputControl != 0 && d->rendererControl != 0) {
   489     }
   640     }
   490 
   641 
   491     return value;
   642     return value;
   492 }
   643 }
   493 
   644 
       
   645 void QGraphicsVideoItem::timerEvent(QTimerEvent *event)
       
   646 {
       
   647     Q_D(QGraphicsVideoItem);
       
   648 
       
   649     if (event->timerId() == d->softwareRenderingTimer.timerId() && d->softwareRenderingEnabled) {
       
   650         d->softwareRenderingTimer.stop();
       
   651         d->softwareRenderingEnabled = false;
       
   652         d->updateLastFrame();
       
   653         // repaint last frame, to ensure geometry change is applyed in paused state
       
   654         d->surface->repaintLastFrame();
       
   655         d->_q_present();
       
   656     } else if ((event->timerId() == d->geometryUpdateTimer.timerId())) {
       
   657         d->geometryUpdateTimer.stop();
       
   658         //slightly delayed geometry update,
       
   659         //to avoid flicker at the first geometry change
       
   660         d->surface->setDisplayRect( d->overlayRect );
       
   661     }
       
   662 
       
   663     QGraphicsObject::timerEvent(event);
       
   664 }
       
   665 
   494 #include "moc_qgraphicsvideoitem.cpp"
   666 #include "moc_qgraphicsvideoitem.cpp"
   495 QTM_END_NAMESPACE
   667 QTM_END_NAMESPACE