8dfcf57dfdf00b71aa9a9ffdc0d07e2a06ca1cf2
[profile/ivi/qtbase.git] / src / gui / image / qmovie.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
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 if (frameNumber != 0) {
385             // We've read all frames now. Return an end marker
386             haveReadAll = true;
387             return QFrameInfo::endMarker();
388         } else {
389             // No readable frames
390             haveReadAll = true;
391             return QFrameInfo();
392         }
393     }
394
395     // CacheMode == CacheAll
396     if (frameNumber > greatestFrameNumber) {
397         // Frame hasn't been read from file yet. Try to do it
398         for (int i = greatestFrameNumber + 1; i <= frameNumber; ++i) {
399             if (reader->canRead()) {
400                 // reader says we can read. Attempt to actually read image
401                 QImage anImage = reader->read();
402                 if (anImage.isNull()) {
403                     // Reading image failed.
404                     return QFrameInfo(); // Invalid
405                 }
406                 greatestFrameNumber = i;
407                 QPixmap aPixmap = QPixmap::fromImage(anImage);
408                 int aDelay = reader->nextImageDelay();
409                 QFrameInfo info(aPixmap, aDelay);
410                 // Cache it!
411                 frameMap.insert(i, info);
412                 if (i == frameNumber) {
413                     return info;
414                 }
415             } else {
416                 // We've read all frames now. Return an end marker
417                 haveReadAll = true;
418                 return QFrameInfo::endMarker();
419             }
420         }
421     }
422     // Return info for requested (cached) frame
423     return frameMap.value(frameNumber);
424 }
425
426 /*!
427     \internal
428
429     Attempts to advance the animation to the next frame.
430     If successful, currentFrameNumber, currentPixmap and
431     nextDelay are updated accordingly, and true is returned.
432     Otherwise, false is returned.
433     When false is returned, isDone() can be called to
434     determine whether the animation ended gracefully or
435     an error occurred when reading the frame.
436 */
437 bool QMoviePrivate::next()
438 {
439     QTime time;
440     time.start();
441     QFrameInfo info = infoForFrame(nextFrameNumber);
442     if (!info.isValid())
443         return false;
444     if (info.isEndMarker()) {
445         // We reached the end of the animation.
446         if (isFirstIteration) {
447             if (nextFrameNumber == 0) {
448                 // No frames could be read at all (error).
449                 return false;
450             }
451             // End of first iteration. Initialize play counter
452             playCounter = reader->loopCount();
453             isFirstIteration = false;
454         }
455         // Loop as appropriate
456         if (playCounter != 0) {
457             if (playCounter != -1) // Infinite?
458                 playCounter--;     // Nope
459             nextFrameNumber = 0;
460             return next();
461         }
462         // Loop no more. Done
463         return false;
464     }
465     // Image and delay OK, update internal state
466     currentFrameNumber = nextFrameNumber++;
467     QSize scaledSize = reader->scaledSize();
468     if (scaledSize.isValid() && (scaledSize != info.pixmap.size()))
469         currentPixmap = QPixmap::fromImage( info.pixmap.toImage().scaled(scaledSize) );
470     else
471         currentPixmap = info.pixmap;
472     nextDelay = speedAdjustedDelay(info.delay);
473     // Adjust delay according to the time it took to read the frame
474     int processingTime = time.elapsed();
475     if (processingTime > nextDelay)
476         nextDelay = 0;
477     else
478         nextDelay = nextDelay - processingTime;
479     return true;
480 }
481
482 /*! \internal
483  */
484 void QMoviePrivate::_q_loadNextFrame()
485 {
486     _q_loadNextFrame(false);
487 }
488
489 void QMoviePrivate::_q_loadNextFrame(bool starting)
490 {
491     Q_Q(QMovie);
492     if (next()) {
493         if (starting && movieState == QMovie::NotRunning) {
494             enterState(QMovie::Running);
495             emit q->started();
496         }
497
498         if (frameRect.size() != currentPixmap.rect().size()) {
499             frameRect = currentPixmap.rect();
500             emit q->resized(frameRect.size());
501         }
502
503         emit q->updated(frameRect);
504         emit q->frameChanged(currentFrameNumber);
505
506         if (movieState == QMovie::Running)
507             nextImageTimer.start(nextDelay);
508     } else {
509         // Could not read another frame
510         if (!isDone()) {
511             emit q->error(reader->error());
512         }
513
514         // Graceful finish
515         if (movieState != QMovie::Paused) {
516             nextFrameNumber = 0;
517             isFirstIteration = true;
518             playCounter = -1;
519             enterState(QMovie::NotRunning);
520             emit q->finished();
521         }
522     }
523 }
524
525 /*!
526     \internal
527 */
528 bool QMoviePrivate::isValid() const
529 {
530     return (greatestFrameNumber >= 0) // have we seen valid data
531         || reader->canRead(); // or does the reader see valid data
532 }
533
534 /*!
535     \internal
536 */
537 bool QMoviePrivate::jumpToFrame(int frameNumber)
538 {
539     if (frameNumber < 0)
540         return false;
541     if (currentFrameNumber == frameNumber)
542         return true;
543     nextFrameNumber = frameNumber;
544     if (movieState == QMovie::Running)
545         nextImageTimer.stop();
546     _q_loadNextFrame();
547     return (nextFrameNumber == currentFrameNumber+1);
548 }
549
550 /*!
551     \internal
552 */
553 int QMoviePrivate::frameCount() const
554 {
555     int result;
556     if ((result = reader->imageCount()) != 0)
557         return result;
558     if (haveReadAll)
559         return greatestFrameNumber+1;
560     return 0; // Don't know
561 }
562
563 /*!
564     \internal
565 */
566 bool QMoviePrivate::jumpToNextFrame()
567 {
568     return jumpToFrame(currentFrameNumber+1);
569 }
570
571 /*!
572     Constructs a QMovie object, passing the \a parent object to QObject's
573     constructor.
574
575     \sa setFileName(), setDevice(), setFormat()
576  */
577 QMovie::QMovie(QObject *parent)
578     : QObject(*new QMoviePrivate(this), parent)
579 {
580     Q_D(QMovie);
581     d->reader = new QImageReader;
582     connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame()));
583 }
584
585 /*!
586     Constructs a QMovie object. QMovie will use read image data from \a
587     device, which it assumes is open and readable. If \a format is not empty,
588     QMovie will use the image format \a format for decoding the image
589     data. Otherwise, QMovie will attempt to guess the format.
590
591     The \a parent object is passed to QObject's constructor.
592  */
593 QMovie::QMovie(QIODevice *device, const QByteArray &format, QObject *parent)
594     : QObject(*new QMoviePrivate(this), parent)
595 {
596     Q_D(QMovie);
597     d->reader = new QImageReader(device, format);
598     d->initialDevicePos = device->pos();
599     connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame()));
600 }
601
602 /*!
603     Constructs a QMovie object. QMovie will use read image data from \a
604     fileName. If \a format is not empty, QMovie will use the image format \a
605     format for decoding the image data. Otherwise, QMovie will attempt to
606     guess the format.
607
608     The \a parent object is passed to QObject's constructor.
609  */
610 QMovie::QMovie(const QString &fileName, const QByteArray &format, QObject *parent)
611     : QObject(*new QMoviePrivate(this), parent)
612 {
613     Q_D(QMovie);
614     d->absoluteFilePath = QDir(fileName).absolutePath();
615     d->reader = new QImageReader(fileName, format);
616     if (d->reader->device())
617         d->initialDevicePos = d->reader->device()->pos();
618     connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame()));
619 }
620
621 /*!
622     Destructs the QMovie object.
623 */
624 QMovie::~QMovie()
625 {
626     Q_D(QMovie);
627     delete d->reader;
628 }
629
630 /*!
631     Sets the current device to \a device. QMovie will read image data from
632     this device when the movie is running.
633
634     \sa device(), setFormat()
635 */
636 void QMovie::setDevice(QIODevice *device)
637 {
638     Q_D(QMovie);
639     d->reader->setDevice(device);
640     d->reset();
641 }
642
643 /*!
644     Returns the device QMovie reads image data from. If no device has
645     currently been assigned, 0 is returned.
646
647     \sa setDevice(), fileName()
648 */
649 QIODevice *QMovie::device() const
650 {
651     Q_D(const QMovie);
652     return d->reader->device();
653 }
654
655 /*!
656     Sets the name of the file that QMovie reads image data from, to \a
657     fileName.
658
659     \sa fileName(), setDevice(), setFormat()
660 */
661 void QMovie::setFileName(const QString &fileName)
662 {
663     Q_D(QMovie);
664     d->absoluteFilePath = QDir(fileName).absolutePath();
665     d->reader->setFileName(fileName);
666     d->reset();
667 }
668
669 /*!
670     Returns the name of the file that QMovie reads image data from. If no file
671     name has been assigned, or if the assigned device is not a file, an empty
672     QString is returned.
673
674     \sa setFileName(), device()
675 */
676 QString QMovie::fileName() const
677 {
678     Q_D(const QMovie);
679     return d->reader->fileName();
680 }
681
682 /*!
683     Sets the format that QMovie will use when decoding image data, to \a
684     format. By default, QMovie will attempt to guess the format of the image
685     data.
686
687     You can call supportedFormats() for the full list of formats
688     QMovie supports.
689
690     \sa QImageReader::supportedImageFormats()
691 */
692 void QMovie::setFormat(const QByteArray &format)
693 {
694     Q_D(QMovie);
695     d->reader->setFormat(format);
696 }
697
698 /*!
699     Returns the format that QMovie uses when decoding image data. If no format
700     has been assigned, an empty QByteArray() is returned.
701
702     \sa setFormat()
703 */
704 QByteArray QMovie::format() const
705 {
706     Q_D(const QMovie);
707     return d->reader->format();
708 }
709
710 /*!
711     For image formats that support it, this function sets the background color
712     to \a color.
713
714     \sa backgroundColor()
715 */
716 void QMovie::setBackgroundColor(const QColor &color)
717 {
718     Q_D(QMovie);
719     d->reader->setBackgroundColor(color);
720 }
721
722 /*!
723     Returns the background color of the movie. If no background color has been
724     assigned, an invalid QColor is returned.
725
726     \sa setBackgroundColor()
727 */
728 QColor QMovie::backgroundColor() const
729 {
730     Q_D(const QMovie);
731     return d->reader->backgroundColor();
732 }
733
734 /*!
735     Returns the current state of QMovie.
736
737     \sa MovieState, stateChanged()
738 */
739 QMovie::MovieState QMovie::state() const
740 {
741     Q_D(const QMovie);
742     return d->movieState;
743 }
744
745 /*!
746     Returns the rect of the last frame. If no frame has yet been updated, an
747     invalid QRect is returned.
748
749     \sa currentImage(), currentPixmap()
750 */
751 QRect QMovie::frameRect() const
752 {
753     Q_D(const QMovie);
754     return d->frameRect;
755 }
756
757 /*!
758     Returns the current frame as a QPixmap.
759
760     \sa currentImage(), updated()
761 */
762 QPixmap QMovie::currentPixmap() const
763 {
764     Q_D(const QMovie);
765     return d->currentPixmap;
766 }
767
768 /*!
769     Returns the current frame as a QImage.
770
771     \sa currentPixmap(), updated()
772 */
773 QImage QMovie::currentImage() const
774 {
775     Q_D(const QMovie);
776     return d->currentPixmap.toImage();
777 }
778
779 /*!
780     Returns true if the movie is valid (e.g., the image data is readable and
781     the image format is supported); otherwise returns false.
782 */
783 bool QMovie::isValid() const
784 {
785     Q_D(const QMovie);
786     return d->isValid();
787 }
788
789 /*!
790     Returns the number of frames in the movie.
791
792     Certain animation formats do not support this feature, in which
793     case 0 is returned.
794 */
795 int QMovie::frameCount() const
796 {
797     Q_D(const QMovie);
798     return d->frameCount();
799 }
800
801 /*!
802     Returns the number of milliseconds QMovie will wait before updating the
803     next frame in the animation.
804 */
805 int QMovie::nextFrameDelay() const
806 {
807     Q_D(const QMovie);
808     return d->nextDelay;
809 }
810
811 /*!
812     Returns the sequence number of the current frame. The number of the first
813     frame in the movie is 0.
814 */
815 int QMovie::currentFrameNumber() const
816 {
817     Q_D(const QMovie);
818     return d->currentFrameNumber;
819 }
820
821 /*!
822     Jumps to the next frame. Returns true on success; otherwise returns false.
823 */
824 bool QMovie::jumpToNextFrame()
825 {
826     Q_D(QMovie);
827     return d->jumpToNextFrame();
828 }
829
830 /*!
831     Jumps to frame number \a frameNumber. Returns true on success; otherwise
832     returns false.
833 */
834 bool QMovie::jumpToFrame(int frameNumber)
835 {
836     Q_D(QMovie);
837     return d->jumpToFrame(frameNumber);
838 }
839
840 /*!
841     Returns the number of times the movie will loop before it finishes.
842     If the movie will only play once (no looping), loopCount returns 0.
843     If the movie loops forever, loopCount returns -1.
844
845     Note that, if the image data comes from a sequential device (e.g. a
846     socket), QMovie can only loop the movie if the cacheMode is set to
847     QMovie::CacheAll.
848 */
849 int QMovie::loopCount() const
850 {
851     Q_D(const QMovie);
852     return d->reader->loopCount();
853 }
854
855 /*!
856     If \a paused is true, QMovie will enter \l Paused state and emit
857     stateChanged(Paused); otherwise it will enter \l Running state and emit
858     stateChanged(Running).
859
860     \sa state()
861 */
862 void QMovie::setPaused(bool paused)
863 {
864     Q_D(QMovie);
865     if (paused) {
866         if (d->movieState == NotRunning)
867             return;
868         d->enterState(Paused);
869         d->nextImageTimer.stop();
870     } else {
871         if (d->movieState == Running)
872             return;
873         d->enterState(Running);
874         d->nextImageTimer.start(nextFrameDelay());
875     }
876 }
877
878 /*!
879     \property QMovie::speed
880     \brief the movie's speed
881
882     The speed is measured in percentage of the original movie speed.
883     The default speed is 100%.
884     Example:
885
886     \snippet doc/src/snippets/code/src_gui_image_qmovie.cpp 1
887 */
888 void QMovie::setSpeed(int percentSpeed)
889 {
890     Q_D(QMovie);
891     d->speed = percentSpeed;
892 }
893
894 int QMovie::speed() const
895 {
896     Q_D(const QMovie);
897     return d->speed;
898 }
899
900 /*!
901     Starts the movie. QMovie will enter \l Running state, and start emitting
902     updated() and resized() as the movie progresses.
903
904     If QMovie is in the \l Paused state, this function is equivalent
905     to calling setPaused(false). If QMovie is already in the \l
906     Running state, this function does nothing.
907
908     \sa stop(), setPaused()
909 */
910 void QMovie::start()
911 {
912     Q_D(QMovie);
913     if (d->movieState == NotRunning) {
914         d->_q_loadNextFrame(true);
915     } else if (d->movieState == Paused) {
916         setPaused(false);
917     }
918 }
919
920 /*!
921     Stops the movie. QMovie enters \l NotRunning state, and stops emitting
922     updated() and resized(). If start() is called again, the movie will
923     restart from the beginning.
924
925     If QMovie is already in the \l NotRunning state, this function
926     does nothing.
927
928     \sa start(), setPaused()
929 */
930 void QMovie::stop()
931 {
932     Q_D(QMovie);
933     if (d->movieState == NotRunning)
934         return;
935     d->enterState(NotRunning);
936     d->nextImageTimer.stop();
937     d->nextFrameNumber = 0;
938 }
939
940 /*!
941     \since 4.1
942
943     Returns the scaled size of frames.
944
945     \sa QImageReader::scaledSize()
946 */
947 QSize QMovie::scaledSize()
948 {
949     Q_D(QMovie);
950     return d->reader->scaledSize();
951 }
952
953 /*!
954     \since 4.1
955
956     Sets the scaled frame size to \a size.
957
958     \sa QImageReader::setScaledSize()
959 */
960 void QMovie::setScaledSize(const QSize &size)
961 {
962     Q_D(QMovie);
963     d->reader->setScaledSize(size);
964 }
965
966 /*!
967     \since 4.1
968
969     Returns the list of image formats supported by QMovie.
970
971     \sa QImageReader::supportedImageFormats()
972 */
973 QList<QByteArray> QMovie::supportedFormats()
974 {
975     QList<QByteArray> list = QImageReader::supportedImageFormats();
976     QMutableListIterator<QByteArray> it(list);
977     QBuffer buffer;
978     buffer.open(QIODevice::ReadOnly);
979     while (it.hasNext()) {
980         QImageReader reader(&buffer, it.next());
981         if (!reader.supportsAnimation())
982             it.remove();
983     }
984     return list;
985 }
986
987 /*!
988     \property QMovie::cacheMode
989     \brief the movie's cache mode
990
991     Caching frames can be useful when the underlying animation format handler
992     that QMovie relies on to decode the animation data does not support
993     jumping to particular frames in the animation, or even "rewinding" the
994     animation to the beginning (for looping). Furthermore, if the image data
995     comes from a sequential device, it is not possible for the underlying
996     animation handler to seek back to frames whose data has already been read
997     (making looping altogether impossible).
998
999     To aid in such situations, a QMovie object can be instructed to cache the
1000     frames, at the added memory cost of keeping the frames in memory for the
1001     lifetime of the object.
1002
1003     By default, this property is set to \l CacheNone.
1004
1005     \sa QMovie::CacheMode
1006 */
1007
1008 QMovie::CacheMode QMovie::cacheMode() const
1009 {
1010     Q_D(const QMovie);
1011     return d->cacheMode;
1012 }
1013
1014 void QMovie::setCacheMode(CacheMode cacheMode)
1015 {
1016     Q_D(QMovie);
1017     d->cacheMode = cacheMode;
1018 }
1019
1020 QT_END_NAMESPACE
1021
1022 #include "moc_qmovie.cpp"
1023
1024 #endif // QT_NO_MOVIE