src/gui/image/qmovie.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 QtGui module of the Qt Toolkit.
       
     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 /*! 
       
    43     \class QMovie
       
    44 
       
    45     \brief The QMovie class is a convenience class for playing movies
       
    46     with QImageReader.
       
    47 
       
    48     \ingroup painting
       
    49 
       
    50     This class is used to show simple animations without sound. If you want
       
    51     to display video and media content, use the \l{Phonon Module}{Phonon}
       
    52     multimedia framework instead.
       
    53 
       
    54     First, create a QMovie object by passing either the name of a file or a
       
    55     pointer to a QIODevice containing an animated image format to QMovie's
       
    56     constructor. You can call isValid() to check if the image data is valid,
       
    57     before starting the movie. To start the movie, call start(). QMovie will
       
    58     enter \l Running state, and emit started() and stateChanged(). To get the
       
    59     current state of the movie, call state().
       
    60 
       
    61     To display the movie in your application, you can pass your QMovie object
       
    62     to QLabel::setMovie(). Example:
       
    63 
       
    64     \snippet doc/src/snippets/code/src_gui_image_qmovie.cpp 0
       
    65 
       
    66     Whenever a new frame is available in the movie, QMovie will emit
       
    67     updated(). If the size of the frame changes, resized() is emitted. You can
       
    68     call currentImage() or currentPixmap() to get a copy of the current
       
    69     frame. When the movie is done, QMovie emits finished(). If any error
       
    70     occurs during playback (i.e, the image file is corrupt), QMovie will emit
       
    71     error().
       
    72 
       
    73     You can control the speed of the movie playback by calling setSpeed(),
       
    74     which takes the percentage of the original speed as an argument. Pause the
       
    75     movie by calling setPaused(true). QMovie will then enter \l Paused state
       
    76     and emit stateChanged(). If you call setPaused(false), QMovie will reenter
       
    77     \l Running state and start the movie again. To stop the movie, call
       
    78     stop().
       
    79 
       
    80     Certain animation formats allow you to set the background color. You can
       
    81     call setBackgroundColor() to set the color, or backgroundColor() to
       
    82     retrieve the current background color.
       
    83 
       
    84     currentFrameNumber() returns the sequence number of the current frame. The
       
    85     first frame in the animation has the sequence number 0. frameCount()
       
    86     returns the total number of frames in the animation, if the image format
       
    87     supports this. You can call loopCount() to get the number of times the
       
    88     movie should loop before finishing. nextFrameDelay() returns the number of
       
    89     milliseconds the current frame should be displayed.
       
    90 
       
    91     QMovie can be instructed to cache frames of an animation by calling
       
    92     setCacheMode().
       
    93 
       
    94     Call supportedFormats() for a list of formats that QMovie supports.
       
    95 
       
    96     \sa QLabel, QImageReader, {Movie Example}
       
    97 */
       
    98 
       
    99 /*! \enum QMovie::MovieState
       
   100 
       
   101     This enum describes the different states of QMovie.
       
   102 
       
   103     \value NotRunning The movie is not running. This is QMovie's initial
       
   104     state, and the state it enters after stop() has been called or the movie
       
   105     is finished.
       
   106 
       
   107     \value Paused The movie is paused, and QMovie stops emitting updated() or
       
   108     resized(). This state is entered after calling pause() or
       
   109     setPaused(true). The current frame number it kept, and the movie will
       
   110     continue with the next frame when unpause() or setPaused(false) is called.
       
   111 
       
   112     \value Running The movie is running.
       
   113 */
       
   114 
       
   115 /*! \enum QMovie::CacheMode
       
   116 
       
   117     This enum describes the different cache modes of QMovie.
       
   118 
       
   119     \value CacheNone No frames are cached (the default).
       
   120 
       
   121     \value CacheAll All frames are cached.
       
   122 */
       
   123 
       
   124 /*! \fn void QMovie::started()
       
   125 
       
   126     This signal is emitted after QMovie::start() has been called, and QMovie
       
   127     has entered QMovie::Running state.
       
   128 */
       
   129 
       
   130 /*! \fn void QMovie::resized(const QSize &size)
       
   131 
       
   132     This signal is emitted when the current frame has been resized to \a
       
   133     size. This effect is sometimes used in animations as an alternative to
       
   134     replacing the frame. You can call currentImage() or currentPixmap() to get a
       
   135     copy of the updated frame.
       
   136 */
       
   137 
       
   138 /*! \fn void QMovie::updated(const QRect &rect)
       
   139 
       
   140     This signal is emitted when the rect \a rect in the current frame has been
       
   141     updated. You can call currentImage() or currentPixmap() to get a copy of the
       
   142     updated frame.
       
   143 */
       
   144 
       
   145 /*! \fn void QMovie::frameChanged(int frameNumber)
       
   146     \since 4.1
       
   147 
       
   148     This signal is emitted when the frame number has changed to
       
   149     \a frameNumber.  You can call currentImage() or currentPixmap() to get a
       
   150     copy of the frame.
       
   151 */
       
   152 
       
   153 /*! 
       
   154     \fn void QMovie::stateChanged(QMovie::MovieState state)
       
   155 
       
   156     This signal is emitted every time the state of the movie changes. The new
       
   157     state is specified by \a state.
       
   158 
       
   159     \sa QMovie::state()
       
   160 */
       
   161 
       
   162 /*! \fn void QMovie::error(QImageReader::ImageReaderError error)
       
   163 
       
   164     This signal is emitted by QMovie when the error \a error occurred during
       
   165     playback.  QMovie will stop the movie, and enter QMovie::NotRunning state.
       
   166 */
       
   167 
       
   168 /*! \fn void QMovie::finished()
       
   169 
       
   170     This signal is emitted when the movie has finished.
       
   171 
       
   172     \sa QMovie::stop()
       
   173 */
       
   174 
       
   175 #include "qglobal.h"
       
   176 
       
   177 #ifndef QT_NO_MOVIE
       
   178 
       
   179 #include "qmovie.h"
       
   180 #include "qimage.h"
       
   181 #include "qimagereader.h"
       
   182 #include "qpixmap.h"
       
   183 #include "qrect.h"
       
   184 #include "qdatetime.h"
       
   185 #include "qtimer.h"
       
   186 #include "qpair.h"
       
   187 #include "qmap.h"
       
   188 #include "qlist.h"
       
   189 #include "qbuffer.h"
       
   190 #include "qdir.h"
       
   191 #include "private/qobject_p.h"
       
   192 
       
   193 #define QMOVIE_INVALID_DELAY -1
       
   194 
       
   195 QT_BEGIN_NAMESPACE
       
   196 
       
   197 class QFrameInfo
       
   198 {
       
   199 public:
       
   200     QPixmap pixmap;
       
   201     int delay;
       
   202     bool endMark;
       
   203     inline QFrameInfo(bool endMark)
       
   204         : pixmap(QPixmap()), delay(QMOVIE_INVALID_DELAY), endMark(endMark)
       
   205     { }
       
   206     
       
   207     inline QFrameInfo()
       
   208         : pixmap(QPixmap()), delay(QMOVIE_INVALID_DELAY), endMark(false)
       
   209     { }
       
   210     
       
   211     inline QFrameInfo(const QPixmap &pixmap, int delay)
       
   212         : pixmap(pixmap), delay(delay), endMark(false)
       
   213     { }
       
   214     
       
   215     inline bool isValid()
       
   216     {
       
   217         return endMark || !(pixmap.isNull() && (delay == QMOVIE_INVALID_DELAY));
       
   218     }
       
   219     
       
   220     inline bool isEndMarker()
       
   221     { return endMark; }
       
   222     
       
   223     static inline QFrameInfo endMarker()
       
   224     { return QFrameInfo(true); }
       
   225 };
       
   226 
       
   227 class QMoviePrivate : public QObjectPrivate
       
   228 {
       
   229     Q_DECLARE_PUBLIC(QMovie)
       
   230 
       
   231 public:
       
   232     QMoviePrivate(QMovie *qq);
       
   233     bool isDone();
       
   234     bool next();
       
   235     int speedAdjustedDelay(int delay) const;
       
   236     bool isValid() const;
       
   237     bool jumpToFrame(int frameNumber);
       
   238     int frameCount() const;
       
   239     bool jumpToNextFrame();
       
   240     QFrameInfo infoForFrame(int frameNumber);
       
   241     void reset();
       
   242 
       
   243     inline void enterState(QMovie::MovieState newState) {
       
   244         movieState = newState;
       
   245         emit q_func()->stateChanged(newState);
       
   246     }
       
   247 
       
   248     // private slots
       
   249     void _q_loadNextFrame();
       
   250     void _q_loadNextFrame(bool starting);
       
   251 
       
   252     QImageReader *reader;
       
   253     int speed;
       
   254     QMovie::MovieState movieState;
       
   255     QRect frameRect;
       
   256     QPixmap currentPixmap;
       
   257     int currentFrameNumber;
       
   258     int nextFrameNumber;
       
   259     int greatestFrameNumber;
       
   260     int nextDelay;
       
   261     int playCounter;
       
   262     qint64 initialDevicePos;
       
   263     QMovie::CacheMode cacheMode;
       
   264     bool haveReadAll;
       
   265     bool isFirstIteration;
       
   266     QMap<int, QFrameInfo> frameMap;
       
   267     QString absoluteFilePath;
       
   268 
       
   269     QTimer nextImageTimer;
       
   270 };
       
   271 
       
   272 /*! \internal
       
   273  */
       
   274 QMoviePrivate::QMoviePrivate(QMovie *qq)
       
   275     : reader(0), speed(100), movieState(QMovie::NotRunning),
       
   276       currentFrameNumber(-1), nextFrameNumber(0), greatestFrameNumber(-1),
       
   277       nextDelay(0), playCounter(-1),
       
   278       cacheMode(QMovie::CacheNone), haveReadAll(false), isFirstIteration(true)
       
   279 {
       
   280     q_ptr = qq;
       
   281     nextImageTimer.setSingleShot(true);
       
   282 }
       
   283 
       
   284 /*! \internal
       
   285  */
       
   286 void QMoviePrivate::reset()
       
   287 {
       
   288     nextImageTimer.stop();
       
   289     if (reader->device())
       
   290         initialDevicePos = reader->device()->pos();
       
   291     currentFrameNumber = -1;
       
   292     nextFrameNumber = 0;
       
   293     greatestFrameNumber = -1;
       
   294     nextDelay = 0;
       
   295     playCounter = -1;
       
   296     haveReadAll = false;
       
   297     isFirstIteration = true;
       
   298     frameMap.clear();
       
   299 }
       
   300 
       
   301 /*! \internal
       
   302  */
       
   303 bool QMoviePrivate::isDone()
       
   304 {
       
   305     return (playCounter == 0);
       
   306 }
       
   307 
       
   308 /*!
       
   309     \internal
       
   310 
       
   311     Given the original \a delay, this function returns the
       
   312     actual number of milliseconds to delay according to
       
   313     the current speed. E.g. if the speed is 200%, the
       
   314     result will be half of the original delay.
       
   315 */
       
   316 int QMoviePrivate::speedAdjustedDelay(int delay) const
       
   317 {
       
   318     return int( (qint64(delay) * qint64(100) ) / qint64(speed) );
       
   319 }
       
   320 
       
   321 /*!
       
   322     \internal
       
   323 
       
   324     Returns the QFrameInfo for the given \a frameNumber.
       
   325 
       
   326     If the frame number is invalid, an invalid QFrameInfo is
       
   327     returned.
       
   328 
       
   329     If the end of the animation has been reached, a
       
   330     special end marker QFrameInfo is returned.
       
   331 
       
   332 */
       
   333 QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
       
   334 {
       
   335     if (frameNumber < 0)
       
   336         return QFrameInfo(); // Invalid
       
   337 
       
   338     if (haveReadAll && (frameNumber > greatestFrameNumber)) {
       
   339         if (frameNumber == greatestFrameNumber+1)
       
   340             return QFrameInfo::endMarker();
       
   341         return QFrameInfo(); // Invalid
       
   342     }
       
   343 
       
   344     if (cacheMode == QMovie::CacheNone) {
       
   345         if (frameNumber != currentFrameNumber+1) {
       
   346             // Non-sequential frame access
       
   347             if (!reader->jumpToImage(frameNumber)) {
       
   348                 if (frameNumber == 0) {
       
   349                     // Special case: Attempt to "rewind" so we can loop
       
   350                     // ### This could be implemented as QImageReader::rewind()
       
   351                     if (reader->device()->isSequential())
       
   352                         return QFrameInfo(); // Invalid
       
   353                     QString fileName = reader->fileName();
       
   354                     QByteArray format = reader->format();
       
   355                     QIODevice *device = reader->device();
       
   356                     QColor bgColor = reader->backgroundColor();
       
   357                     QSize scaledSize = reader->scaledSize();
       
   358                     delete reader;
       
   359                     if (fileName.isEmpty())
       
   360                         reader = new QImageReader(device, format);
       
   361                     else
       
   362                         reader = new QImageReader(absoluteFilePath, format);
       
   363                     (void)reader->canRead(); // Provoke a device->open() call
       
   364                     reader->device()->seek(initialDevicePos);
       
   365                     reader->setBackgroundColor(bgColor);
       
   366                     reader->setScaledSize(scaledSize);
       
   367                 } else {
       
   368                     return QFrameInfo(); // Invalid
       
   369                 }
       
   370             }
       
   371         }
       
   372         if (reader->canRead()) {
       
   373             // reader says we can read. Attempt to actually read image
       
   374             QImage anImage = reader->read();
       
   375             if (anImage.isNull()) {
       
   376                 // Reading image failed.
       
   377                 return QFrameInfo(); // Invalid
       
   378             }
       
   379             if (frameNumber > greatestFrameNumber)
       
   380                 greatestFrameNumber = frameNumber;
       
   381             QPixmap aPixmap = QPixmap::fromImage(anImage);
       
   382             int aDelay = reader->nextImageDelay();
       
   383             return QFrameInfo(aPixmap, aDelay);
       
   384         } else {
       
   385             // We've read all frames now. Return an end marker
       
   386             haveReadAll = true;
       
   387             return QFrameInfo::endMarker();
       
   388         }
       
   389     }
       
   390 
       
   391     // CacheMode == CacheAll
       
   392     if (frameNumber > greatestFrameNumber) {
       
   393         // Frame hasn't been read from file yet. Try to do it
       
   394         for (int i = greatestFrameNumber + 1; i <= frameNumber; ++i) {
       
   395             if (reader->canRead()) {
       
   396                 // reader says we can read. Attempt to actually read image
       
   397                 QImage anImage = reader->read();
       
   398                 if (anImage.isNull()) {
       
   399                     // Reading image failed.
       
   400                     return QFrameInfo(); // Invalid
       
   401                 }
       
   402                 greatestFrameNumber = i;
       
   403                 QPixmap aPixmap = QPixmap::fromImage(anImage);
       
   404                 int aDelay = reader->nextImageDelay();
       
   405                 QFrameInfo info(aPixmap, aDelay);
       
   406                 // Cache it!
       
   407                 frameMap.insert(i, info);
       
   408                 if (i == frameNumber) {
       
   409                     return info;
       
   410                 }
       
   411             } else {
       
   412                 // We've read all frames now. Return an end marker
       
   413                 haveReadAll = true;
       
   414                 return QFrameInfo::endMarker();
       
   415             }
       
   416         }
       
   417     }
       
   418     // Return info for requested (cached) frame
       
   419     return frameMap.value(frameNumber);
       
   420 }
       
   421 
       
   422 /*!
       
   423     \internal
       
   424 
       
   425     Attempts to advance the animation to the next frame.
       
   426     If successful, currentFrameNumber, currentPixmap and
       
   427     nextDelay are updated accordingly, and true is returned.
       
   428     Otherwise, false is returned.
       
   429     When false is returned, isDone() can be called to
       
   430     determine whether the animation ended gracefully or
       
   431     an error occurred when reading the frame.
       
   432 */
       
   433 bool QMoviePrivate::next()
       
   434 {
       
   435     QTime time;
       
   436     time.start();
       
   437     QFrameInfo info = infoForFrame(nextFrameNumber);
       
   438     if (!info.isValid())
       
   439         return false;
       
   440     if (info.isEndMarker()) {
       
   441         // We reached the end of the animation.
       
   442         if (isFirstIteration) {
       
   443             if (nextFrameNumber == 0) {
       
   444                 // No frames could be read at all (error).
       
   445                 return false;
       
   446             }
       
   447             // End of first iteration. Initialize play counter
       
   448             playCounter = reader->loopCount();
       
   449             isFirstIteration = false;
       
   450         }
       
   451         // Loop as appropriate
       
   452         if (playCounter != 0) {
       
   453             if (playCounter != -1) // Infinite?
       
   454                 playCounter--;     // Nope
       
   455             nextFrameNumber = 0;
       
   456             return next();
       
   457         }
       
   458         // Loop no more. Done
       
   459         return false;
       
   460     }
       
   461     // Image and delay OK, update internal state
       
   462     currentFrameNumber = nextFrameNumber++;
       
   463     QSize scaledSize = reader->scaledSize();
       
   464     if (scaledSize.isValid() && (scaledSize != info.pixmap.size()))
       
   465         currentPixmap = QPixmap::fromImage( info.pixmap.toImage().scaled(scaledSize) );
       
   466     else
       
   467         currentPixmap = info.pixmap;
       
   468     nextDelay = speedAdjustedDelay(info.delay);
       
   469     // Adjust delay according to the time it took to read the frame
       
   470     int processingTime = time.elapsed();
       
   471     if (processingTime > nextDelay)
       
   472         nextDelay = 0;
       
   473     else
       
   474         nextDelay = nextDelay - processingTime;
       
   475     return true;
       
   476 }
       
   477 
       
   478 /*! \internal
       
   479  */
       
   480 void QMoviePrivate::_q_loadNextFrame()
       
   481 {
       
   482     _q_loadNextFrame(false);
       
   483 }
       
   484 
       
   485 void QMoviePrivate::_q_loadNextFrame(bool starting)
       
   486 {
       
   487     Q_Q(QMovie);
       
   488     if (next()) {
       
   489         if (starting && movieState == QMovie::NotRunning) {
       
   490             enterState(QMovie::Running);
       
   491             emit q->started();
       
   492         }
       
   493 
       
   494         if (frameRect.size() != currentPixmap.rect().size()) {
       
   495             frameRect = currentPixmap.rect();
       
   496             emit q->resized(frameRect.size());
       
   497         }
       
   498 
       
   499         emit q->updated(frameRect);
       
   500         emit q->frameChanged(currentFrameNumber);
       
   501 
       
   502         if (movieState == QMovie::Running)
       
   503             nextImageTimer.start(nextDelay);
       
   504     } else {
       
   505         // Could not read another frame
       
   506         if (!isDone()) {
       
   507             emit q->error(reader->error());
       
   508         }
       
   509 
       
   510         // Graceful finish
       
   511         if (movieState != QMovie::Paused) {
       
   512             nextFrameNumber = 0;
       
   513             isFirstIteration = true;
       
   514             playCounter = -1;
       
   515             enterState(QMovie::NotRunning);
       
   516             emit q->finished();
       
   517         }
       
   518     }
       
   519 }
       
   520 
       
   521 /*!
       
   522     \internal
       
   523 */
       
   524 bool QMoviePrivate::isValid() const
       
   525 {
       
   526     return (greatestFrameNumber >= 0) // have we seen valid data
       
   527         || reader->canRead(); // or does the reader see valid data
       
   528 }
       
   529 
       
   530 /*!
       
   531     \internal
       
   532 */
       
   533 bool QMoviePrivate::jumpToFrame(int frameNumber)
       
   534 {
       
   535     if (frameNumber < 0)
       
   536         return false;
       
   537     if (currentFrameNumber == frameNumber)
       
   538         return true;
       
   539     nextFrameNumber = frameNumber;
       
   540     if (movieState == QMovie::Running)
       
   541         nextImageTimer.stop();
       
   542     _q_loadNextFrame();
       
   543     return (nextFrameNumber == currentFrameNumber+1);
       
   544 }
       
   545 
       
   546 /*!
       
   547     \internal
       
   548 */
       
   549 int QMoviePrivate::frameCount() const
       
   550 {
       
   551     int result;
       
   552     if ((result = reader->imageCount()) != 0)
       
   553         return result;
       
   554     if (haveReadAll)
       
   555         return greatestFrameNumber+1;
       
   556     return 0; // Don't know
       
   557 }
       
   558 
       
   559 /*!
       
   560     \internal
       
   561 */
       
   562 bool QMoviePrivate::jumpToNextFrame()
       
   563 {
       
   564     return jumpToFrame(currentFrameNumber+1);
       
   565 }
       
   566 
       
   567 /*!
       
   568     Constructs a QMovie object, passing the \a parent object to QObject's
       
   569     constructor.
       
   570 
       
   571     \sa setFileName(), setDevice(), setFormat()
       
   572  */
       
   573 QMovie::QMovie(QObject *parent)
       
   574     : QObject(*new QMoviePrivate(this), parent)
       
   575 {
       
   576     Q_D(QMovie);
       
   577     d->reader = new QImageReader;
       
   578     connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame()));
       
   579 }
       
   580 
       
   581 /*!
       
   582     Constructs a QMovie object. QMovie will use read image data from \a
       
   583     device, which it assumes is open and readable. If \a format is not empty,
       
   584     QMovie will use the image format \a format for decoding the image
       
   585     data. Otherwise, QMovie will attempt to guess the format.
       
   586 
       
   587     The \a parent object is passed to QObject's constructor.
       
   588  */
       
   589 QMovie::QMovie(QIODevice *device, const QByteArray &format, QObject *parent)
       
   590     : QObject(*new QMoviePrivate(this), parent)
       
   591 {
       
   592     Q_D(QMovie);
       
   593     d->reader = new QImageReader(device, format);
       
   594     d->initialDevicePos = device->pos();
       
   595     connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame()));
       
   596 }
       
   597 
       
   598 /*!
       
   599     Constructs a QMovie object. QMovie will use read image data from \a
       
   600     fileName. If \a format is not empty, QMovie will use the image format \a
       
   601     format for decoding the image data. Otherwise, QMovie will attempt to
       
   602     guess the format.
       
   603 
       
   604     The \a parent object is passed to QObject's constructor.
       
   605  */
       
   606 QMovie::QMovie(const QString &fileName, const QByteArray &format, QObject *parent)
       
   607     : QObject(*new QMoviePrivate(this), parent)
       
   608 {
       
   609     Q_D(QMovie);
       
   610     d->absoluteFilePath = QDir(fileName).absolutePath();
       
   611     d->reader = new QImageReader(fileName, format);
       
   612     if (d->reader->device())
       
   613         d->initialDevicePos = d->reader->device()->pos();
       
   614     connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame()));
       
   615 }
       
   616 
       
   617 /*!
       
   618     Destructs the QMovie object.
       
   619 */
       
   620 QMovie::~QMovie()
       
   621 {
       
   622     Q_D(QMovie);
       
   623     delete d->reader;
       
   624 }
       
   625 
       
   626 /*!
       
   627     Sets the current device to \a device. QMovie will read image data from
       
   628     this device when the movie is running.
       
   629 
       
   630     \sa device(), setFormat()
       
   631 */
       
   632 void QMovie::setDevice(QIODevice *device)
       
   633 {
       
   634     Q_D(QMovie);
       
   635     d->reader->setDevice(device);
       
   636     d->reset();
       
   637 }
       
   638 
       
   639 /*!
       
   640     Returns the device QMovie reads image data from. If no device has
       
   641     currently been assigned, 0 is returned.
       
   642 
       
   643     \sa setDevice(), fileName()
       
   644 */
       
   645 QIODevice *QMovie::device() const
       
   646 {
       
   647     Q_D(const QMovie);
       
   648     return d->reader->device();
       
   649 }
       
   650 
       
   651 /*!
       
   652     Sets the name of the file that QMovie reads image data from, to \a
       
   653     fileName.
       
   654 
       
   655     \sa fileName(), setDevice(), setFormat()
       
   656 */
       
   657 void QMovie::setFileName(const QString &fileName)
       
   658 {
       
   659     Q_D(QMovie);
       
   660     d->absoluteFilePath = QDir(fileName).absolutePath();
       
   661     d->reader->setFileName(fileName);
       
   662     d->reset();
       
   663 }
       
   664 
       
   665 /*!
       
   666     Returns the name of the file that QMovie reads image data from. If no file
       
   667     name has been assigned, or if the assigned device is not a file, an empty
       
   668     QString is returned.
       
   669 
       
   670     \sa setFileName(), device()
       
   671 */
       
   672 QString QMovie::fileName() const
       
   673 {
       
   674     Q_D(const QMovie);
       
   675     return d->reader->fileName();
       
   676 }
       
   677 
       
   678 /*!
       
   679     Sets the format that QMovie will use when decoding image data, to \a
       
   680     format. By default, QMovie will attempt to guess the format of the image
       
   681     data.
       
   682 
       
   683     You can call supportedFormats() for the full list of formats
       
   684     QMovie supports.
       
   685 
       
   686     \sa QImageReader::supportedImageFormats()
       
   687 */
       
   688 void QMovie::setFormat(const QByteArray &format)
       
   689 {
       
   690     Q_D(QMovie);
       
   691     d->reader->setFormat(format);
       
   692 }
       
   693 
       
   694 /*!
       
   695     Returns the format that QMovie uses when decoding image data. If no format
       
   696     has been assigned, an empty QByteArray() is returned.
       
   697 
       
   698     \sa setFormat()
       
   699 */
       
   700 QByteArray QMovie::format() const
       
   701 {
       
   702     Q_D(const QMovie);
       
   703     return d->reader->format();
       
   704 }
       
   705 
       
   706 /*!
       
   707     For image formats that support it, this function sets the background color
       
   708     to \a color.
       
   709 
       
   710     \sa backgroundColor()
       
   711 */
       
   712 void QMovie::setBackgroundColor(const QColor &color)
       
   713 {
       
   714     Q_D(QMovie);
       
   715     d->reader->setBackgroundColor(color);
       
   716 }
       
   717 
       
   718 /*!
       
   719     Returns the background color of the movie. If no background color has been
       
   720     assigned, an invalid QColor is returned.
       
   721 
       
   722     \sa setBackgroundColor()
       
   723 */
       
   724 QColor QMovie::backgroundColor() const
       
   725 {
       
   726     Q_D(const QMovie);
       
   727     return d->reader->backgroundColor();
       
   728 }
       
   729 
       
   730 /*!
       
   731     Returns the current state of QMovie.
       
   732 
       
   733     \sa MovieState, stateChanged()
       
   734 */
       
   735 QMovie::MovieState QMovie::state() const
       
   736 {
       
   737     Q_D(const QMovie);
       
   738     return d->movieState;
       
   739 }
       
   740 
       
   741 /*!
       
   742     Returns the rect of the last frame. If no frame has yet been updated, an
       
   743     invalid QRect is returned.
       
   744 
       
   745     \sa currentImage(), currentPixmap()
       
   746 */
       
   747 QRect QMovie::frameRect() const
       
   748 {
       
   749     Q_D(const QMovie);
       
   750     return d->frameRect;
       
   751 }
       
   752 
       
   753 /*! \fn QImage QMovie::framePixmap() const
       
   754 
       
   755     Use currentPixmap() instead.
       
   756 */
       
   757 
       
   758 /*! \fn void QMovie::pause()
       
   759 
       
   760     Use setPaused(true) instead.
       
   761 */
       
   762 
       
   763 /*! \fn void QMovie::unpause()
       
   764 
       
   765     Use setPaused(false) instead.
       
   766 */
       
   767 
       
   768 /*!
       
   769     Returns the current frame as a QPixmap.
       
   770 
       
   771     \sa currentImage(), updated()
       
   772 */
       
   773 QPixmap QMovie::currentPixmap() const
       
   774 {
       
   775     Q_D(const QMovie);
       
   776     return d->currentPixmap;
       
   777 }
       
   778 
       
   779 /*! \fn QImage QMovie::frameImage() const
       
   780 
       
   781     Use currentImage() instead.
       
   782 */
       
   783 
       
   784 /*!
       
   785     Returns the current frame as a QImage.
       
   786 
       
   787     \sa currentPixmap(), updated()
       
   788 */
       
   789 QImage QMovie::currentImage() const
       
   790 {
       
   791     Q_D(const QMovie);
       
   792     return d->currentPixmap.toImage();
       
   793 }
       
   794 
       
   795 /*!
       
   796     Returns true if the movie is valid (e.g., the image data is readable and
       
   797     the image format is supported); otherwise returns false.
       
   798 */
       
   799 bool QMovie::isValid() const
       
   800 {
       
   801     Q_D(const QMovie);
       
   802     return d->isValid();
       
   803 }
       
   804 
       
   805 /*! \fn bool QMovie::running() const
       
   806 
       
   807     Use state() instead.
       
   808 */
       
   809 
       
   810 /*! \fn bool QMovie::isNull() const
       
   811 
       
   812     Use isValid() instead.
       
   813 */
       
   814 
       
   815 /*! \fn int QMovie::frameNumber() const
       
   816 
       
   817     Use currentFrameNumber() instead.
       
   818 */
       
   819 
       
   820 /*! \fn bool QMovie::paused() const
       
   821 
       
   822     Use state() instead.
       
   823 */
       
   824 
       
   825 /*! \fn bool QMovie::finished() const
       
   826 
       
   827     Use state() instead.
       
   828 */
       
   829 
       
   830 /*! \fn void QMovie::restart()
       
   831 
       
   832     Use stop() and start() instead.
       
   833 */
       
   834 
       
   835 /*!
       
   836     \fn void QMovie::step()
       
   837 
       
   838     Use jumpToNextFrame() instead.
       
   839 */
       
   840 
       
   841 /*!
       
   842     Returns the number of frames in the movie.
       
   843 
       
   844     Certain animation formats do not support this feature, in which
       
   845     case 0 is returned.
       
   846 */
       
   847 int QMovie::frameCount() const
       
   848 {
       
   849     Q_D(const QMovie);
       
   850     return d->frameCount();
       
   851 }
       
   852 
       
   853 /*!
       
   854     Returns the number of milliseconds QMovie will wait before updating the
       
   855     next frame in the animation.
       
   856 */
       
   857 int QMovie::nextFrameDelay() const
       
   858 {
       
   859     Q_D(const QMovie);
       
   860     return d->nextDelay;
       
   861 }
       
   862 
       
   863 /*!
       
   864     Returns the sequence number of the current frame. The number of the first
       
   865     frame in the movie is 0.
       
   866 */
       
   867 int QMovie::currentFrameNumber() const
       
   868 {
       
   869     Q_D(const QMovie);
       
   870     return d->currentFrameNumber;
       
   871 }
       
   872 
       
   873 /*!
       
   874     Jumps to the next frame. Returns true on success; otherwise returns false.
       
   875 */
       
   876 bool QMovie::jumpToNextFrame()
       
   877 {
       
   878     Q_D(QMovie);
       
   879     return d->jumpToNextFrame();
       
   880 }
       
   881 
       
   882 /*!
       
   883     Jumps to frame number \a frameNumber. Returns true on success; otherwise
       
   884     returns false.
       
   885 */
       
   886 bool QMovie::jumpToFrame(int frameNumber)
       
   887 {
       
   888     Q_D(QMovie);
       
   889     return d->jumpToFrame(frameNumber);
       
   890 }
       
   891 
       
   892 /*!
       
   893     Returns the number of times the movie will loop before it finishes.
       
   894     If the movie will only play once (no looping), loopCount returns 0.
       
   895     If the movie loops forever, loopCount returns -1.
       
   896 
       
   897     Note that, if the image data comes from a sequential device (e.g. a
       
   898     socket), QMovie can only loop the movie if the cacheMode is set to
       
   899     QMovie::CacheAll.
       
   900 */
       
   901 int QMovie::loopCount() const
       
   902 {
       
   903     Q_D(const QMovie);
       
   904     return d->reader->loopCount();
       
   905 }
       
   906 
       
   907 /*!
       
   908     If \a paused is true, QMovie will enter \l Paused state and emit
       
   909     stateChanged(Paused); otherwise it will enter \l Running state and emit
       
   910     stateChanged(Running).
       
   911 
       
   912     \sa state()
       
   913 */
       
   914 void QMovie::setPaused(bool paused)
       
   915 {
       
   916     Q_D(QMovie);
       
   917     if (paused) {
       
   918         if (d->movieState == NotRunning)
       
   919             return;
       
   920         d->enterState(Paused);
       
   921         d->nextImageTimer.stop();
       
   922     } else {
       
   923         if (d->movieState == Running)
       
   924             return;
       
   925         d->enterState(Running);
       
   926         d->nextImageTimer.start(nextFrameDelay());
       
   927     }
       
   928 }
       
   929 
       
   930 /*!
       
   931     \property QMovie::speed
       
   932     \brief the movie's speed
       
   933 
       
   934     The speed is measured in percentage of the original movie speed.
       
   935     The default speed is 100%.
       
   936     Example:
       
   937 
       
   938     \snippet doc/src/snippets/code/src_gui_image_qmovie.cpp 1
       
   939 */
       
   940 void QMovie::setSpeed(int percentSpeed)
       
   941 {
       
   942     Q_D(QMovie);
       
   943     d->speed = percentSpeed;
       
   944 }
       
   945 
       
   946 int QMovie::speed() const
       
   947 {
       
   948     Q_D(const QMovie);
       
   949     return d->speed;
       
   950 }
       
   951 
       
   952 /*!
       
   953     Starts the movie. QMovie will enter \l Running state, and start emitting
       
   954     updated() and resized() as the movie progresses.
       
   955 
       
   956     If QMovie is in the \l Paused state, this function is equivalent
       
   957     to calling setPaused(false). If QMovie is already in the \l
       
   958     Running state, this function does nothing.
       
   959 
       
   960     \sa stop(), setPaused()
       
   961 */
       
   962 void QMovie::start()
       
   963 {
       
   964     Q_D(QMovie);
       
   965     if (d->movieState == NotRunning) {
       
   966         d->_q_loadNextFrame(true);
       
   967     } else if (d->movieState == Paused) {
       
   968         setPaused(false);
       
   969     }
       
   970 }
       
   971 
       
   972 /*!
       
   973     Stops the movie. QMovie enters \l NotRunning state, and stops emitting
       
   974     updated() and resized(). If start() is called again, the movie will
       
   975     restart from the beginning.
       
   976 
       
   977     If QMovie is already in the \l NotRunning state, this function
       
   978     does nothing.
       
   979 
       
   980     \sa start(), setPaused()
       
   981 */
       
   982 void QMovie::stop()
       
   983 {
       
   984     Q_D(QMovie);
       
   985     if (d->movieState == NotRunning)
       
   986         return;
       
   987     d->enterState(NotRunning);
       
   988     d->nextImageTimer.stop();
       
   989     d->nextFrameNumber = 0;
       
   990 }
       
   991 
       
   992 /*!
       
   993     \since 4.1
       
   994 
       
   995     Returns the scaled size of frames.
       
   996 
       
   997     \sa QImageReader::scaledSize()
       
   998 */
       
   999 QSize QMovie::scaledSize()
       
  1000 {
       
  1001     Q_D(QMovie);
       
  1002     return d->reader->scaledSize();
       
  1003 }
       
  1004 
       
  1005 /*!
       
  1006     \since 4.1
       
  1007 
       
  1008     Sets the scaled frame size to \a size.
       
  1009 
       
  1010     \sa QImageReader::setScaledSize()
       
  1011 */
       
  1012 void QMovie::setScaledSize(const QSize &size)
       
  1013 {
       
  1014     Q_D(QMovie);
       
  1015     d->reader->setScaledSize(size);
       
  1016 }
       
  1017 
       
  1018 /*!
       
  1019     \since 4.1
       
  1020 
       
  1021     Returns the list of image formats supported by QMovie.
       
  1022 
       
  1023     \sa QImageReader::supportedImageFormats()
       
  1024 */
       
  1025 QList<QByteArray> QMovie::supportedFormats()
       
  1026 {
       
  1027     QList<QByteArray> list = QImageReader::supportedImageFormats();
       
  1028     QMutableListIterator<QByteArray> it(list);
       
  1029     QBuffer buffer;
       
  1030     buffer.open(QIODevice::ReadOnly);
       
  1031     while (it.hasNext()) {
       
  1032         QImageReader reader(&buffer, it.next());
       
  1033         if (!reader.supportsAnimation())
       
  1034             it.remove();
       
  1035     }
       
  1036     return list;
       
  1037 }
       
  1038 
       
  1039 /*!
       
  1040     \property QMovie::cacheMode
       
  1041     \brief the movie's cache mode
       
  1042 
       
  1043     Caching frames can be useful when the underlying animation format handler
       
  1044     that QMovie relies on to decode the animation data does not support
       
  1045     jumping to particular frames in the animation, or even "rewinding" the
       
  1046     animation to the beginning (for looping). Furthermore, if the image data
       
  1047     comes from a sequential device, it is not possible for the underlying
       
  1048     animation handler to seek back to frames whose data has already been read
       
  1049     (making looping altogether impossible).
       
  1050 
       
  1051     To aid in such situations, a QMovie object can be instructed to cache the
       
  1052     frames, at the added memory cost of keeping the frames in memory for the
       
  1053     lifetime of the object.
       
  1054 
       
  1055     By default, this property is set to \l CacheNone.
       
  1056 
       
  1057     \sa QMovie::CacheMode
       
  1058 */
       
  1059 
       
  1060 QMovie::CacheMode QMovie::cacheMode() const
       
  1061 {
       
  1062     Q_D(const QMovie);
       
  1063     return d->cacheMode;
       
  1064 }
       
  1065 
       
  1066 void QMovie::setCacheMode(CacheMode cacheMode)
       
  1067 {
       
  1068     Q_D(QMovie);
       
  1069     d->cacheMode = cacheMode;
       
  1070 }
       
  1071 
       
  1072 /*!
       
  1073   \internal
       
  1074 */
       
  1075 QMovie::CacheMode QMovie::cacheMode()
       
  1076 {
       
  1077     Q_D(QMovie);
       
  1078     return d->cacheMode;
       
  1079 }
       
  1080 
       
  1081 QT_END_NAMESPACE
       
  1082 
       
  1083 #include "moc_qmovie.cpp"
       
  1084 
       
  1085 #endif // QT_NO_MOVIE