1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
45 \brief The QMovie class is a convenience class for playing movies
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.
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().
61 To display the movie in your application, you can pass your QMovie object
62 to QLabel::setMovie(). Example:
64 \snippet doc/src/snippets/code/src_gui_image_qmovie.cpp 0
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
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
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.
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.
91 QMovie can be instructed to cache frames of an animation by calling
94 Call supportedFormats() for a list of formats that QMovie supports.
96 \sa QLabel, QImageReader, {Movie Example}
99 /*! \enum QMovie::MovieState
101 This enum describes the different states of QMovie.
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
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.
112 \value Running The movie is running.
115 /*! \enum QMovie::CacheMode
117 This enum describes the different cache modes of QMovie.
119 \value CacheNone No frames are cached (the default).
121 \value CacheAll All frames are cached.
124 /*! \fn void QMovie::started()
126 This signal is emitted after QMovie::start() has been called, and QMovie
127 has entered QMovie::Running state.
130 /*! \fn void QMovie::resized(const QSize &size)
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.
138 /*! \fn void QMovie::updated(const QRect &rect)
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
145 /*! \fn void QMovie::frameChanged(int frameNumber)
148 This signal is emitted when the frame number has changed to
149 \a frameNumber. You can call currentImage() or currentPixmap() to get a
154 \fn void QMovie::stateChanged(QMovie::MovieState state)
156 This signal is emitted every time the state of the movie changes. The new
157 state is specified by \a state.
162 /*! \fn void QMovie::error(QImageReader::ImageReaderError error)
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.
168 /*! \fn void QMovie::finished()
170 This signal is emitted when the movie has finished.
181 #include "qimagereader.h"
184 #include "qdatetime.h"
191 #include "private/qobject_p.h"
193 #define QMOVIE_INVALID_DELAY -1
203 inline QFrameInfo(bool endMark)
204 : pixmap(QPixmap()), delay(QMOVIE_INVALID_DELAY), endMark(endMark)
208 : pixmap(QPixmap()), delay(QMOVIE_INVALID_DELAY), endMark(false)
211 inline QFrameInfo(const QPixmap &pixmap, int delay)
212 : pixmap(pixmap), delay(delay), endMark(false)
215 inline bool isValid()
217 return endMark || !(pixmap.isNull() && (delay == QMOVIE_INVALID_DELAY));
220 inline bool isEndMarker()
223 static inline QFrameInfo endMarker()
224 { return QFrameInfo(true); }
227 class QMoviePrivate : public QObjectPrivate
229 Q_DECLARE_PUBLIC(QMovie)
232 QMoviePrivate(QMovie *qq);
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);
243 inline void enterState(QMovie::MovieState newState) {
244 movieState = newState;
245 emit q_func()->stateChanged(newState);
249 void _q_loadNextFrame();
250 void _q_loadNextFrame(bool starting);
252 QImageReader *reader;
254 QMovie::MovieState movieState;
256 QPixmap currentPixmap;
257 int currentFrameNumber;
259 int greatestFrameNumber;
262 qint64 initialDevicePos;
263 QMovie::CacheMode cacheMode;
265 bool isFirstIteration;
266 QMap<int, QFrameInfo> frameMap;
267 QString absoluteFilePath;
269 QTimer nextImageTimer;
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)
281 nextImageTimer.setSingleShot(true);
286 void QMoviePrivate::reset()
288 nextImageTimer.stop();
289 if (reader->device())
290 initialDevicePos = reader->device()->pos();
291 currentFrameNumber = -1;
293 greatestFrameNumber = -1;
297 isFirstIteration = true;
303 bool QMoviePrivate::isDone()
305 return (playCounter == 0);
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.
316 int QMoviePrivate::speedAdjustedDelay(int delay) const
318 return int( (qint64(delay) * qint64(100) ) / qint64(speed) );
324 Returns the QFrameInfo for the given \a frameNumber.
326 If the frame number is invalid, an invalid QFrameInfo is
329 If the end of the animation has been reached, a
330 special end marker QFrameInfo is returned.
333 QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
336 return QFrameInfo(); // Invalid
338 if (haveReadAll && (frameNumber > greatestFrameNumber)) {
339 if (frameNumber == greatestFrameNumber+1)
340 return QFrameInfo::endMarker();
341 return QFrameInfo(); // Invalid
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();
359 if (fileName.isEmpty())
360 reader = new QImageReader(device, format);
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);
368 return QFrameInfo(); // Invalid
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
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
387 return QFrameInfo::endMarker();
389 // No readable frames
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
406 greatestFrameNumber = i;
407 QPixmap aPixmap = QPixmap::fromImage(anImage);
408 int aDelay = reader->nextImageDelay();
409 QFrameInfo info(aPixmap, aDelay);
411 frameMap.insert(i, info);
412 if (i == frameNumber) {
416 // We've read all frames now. Return an end marker
418 return QFrameInfo::endMarker();
422 // Return info for requested (cached) frame
423 return frameMap.value(frameNumber);
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.
437 bool QMoviePrivate::next()
441 QFrameInfo info = infoForFrame(nextFrameNumber);
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).
451 // End of first iteration. Initialize play counter
452 playCounter = reader->loopCount();
453 isFirstIteration = false;
455 // Loop as appropriate
456 if (playCounter != 0) {
457 if (playCounter != -1) // Infinite?
458 playCounter--; // Nope
462 // Loop no more. Done
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) );
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)
478 nextDelay = nextDelay - processingTime;
484 void QMoviePrivate::_q_loadNextFrame()
486 _q_loadNextFrame(false);
489 void QMoviePrivate::_q_loadNextFrame(bool starting)
493 if (starting && movieState == QMovie::NotRunning) {
494 enterState(QMovie::Running);
498 if (frameRect.size() != currentPixmap.rect().size()) {
499 frameRect = currentPixmap.rect();
500 emit q->resized(frameRect.size());
503 emit q->updated(frameRect);
504 emit q->frameChanged(currentFrameNumber);
506 if (movieState == QMovie::Running)
507 nextImageTimer.start(nextDelay);
509 // Could not read another frame
511 emit q->error(reader->error());
515 if (movieState != QMovie::Paused) {
517 isFirstIteration = true;
519 enterState(QMovie::NotRunning);
528 bool QMoviePrivate::isValid() const
530 return (greatestFrameNumber >= 0) // have we seen valid data
531 || reader->canRead(); // or does the reader see valid data
537 bool QMoviePrivate::jumpToFrame(int frameNumber)
541 if (currentFrameNumber == frameNumber)
543 nextFrameNumber = frameNumber;
544 if (movieState == QMovie::Running)
545 nextImageTimer.stop();
547 return (nextFrameNumber == currentFrameNumber+1);
553 int QMoviePrivate::frameCount() const
556 if ((result = reader->imageCount()) != 0)
559 return greatestFrameNumber+1;
560 return 0; // Don't know
566 bool QMoviePrivate::jumpToNextFrame()
568 return jumpToFrame(currentFrameNumber+1);
572 Constructs a QMovie object, passing the \a parent object to QObject's
575 \sa setFileName(), setDevice(), setFormat()
577 QMovie::QMovie(QObject *parent)
578 : QObject(*new QMoviePrivate(this), parent)
581 d->reader = new QImageReader;
582 connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame()));
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.
591 The \a parent object is passed to QObject's constructor.
593 QMovie::QMovie(QIODevice *device, const QByteArray &format, QObject *parent)
594 : QObject(*new QMoviePrivate(this), parent)
597 d->reader = new QImageReader(device, format);
598 d->initialDevicePos = device->pos();
599 connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame()));
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
608 The \a parent object is passed to QObject's constructor.
610 QMovie::QMovie(const QString &fileName, const QByteArray &format, QObject *parent)
611 : QObject(*new QMoviePrivate(this), parent)
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()));
622 Destructs the QMovie object.
631 Sets the current device to \a device. QMovie will read image data from
632 this device when the movie is running.
634 \sa device(), setFormat()
636 void QMovie::setDevice(QIODevice *device)
639 d->reader->setDevice(device);
644 Returns the device QMovie reads image data from. If no device has
645 currently been assigned, 0 is returned.
647 \sa setDevice(), fileName()
649 QIODevice *QMovie::device() const
652 return d->reader->device();
656 Sets the name of the file that QMovie reads image data from, to \a
659 \sa fileName(), setDevice(), setFormat()
661 void QMovie::setFileName(const QString &fileName)
664 d->absoluteFilePath = QDir(fileName).absolutePath();
665 d->reader->setFileName(fileName);
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
674 \sa setFileName(), device()
676 QString QMovie::fileName() const
679 return d->reader->fileName();
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
687 You can call supportedFormats() for the full list of formats
690 \sa QImageReader::supportedImageFormats()
692 void QMovie::setFormat(const QByteArray &format)
695 d->reader->setFormat(format);
699 Returns the format that QMovie uses when decoding image data. If no format
700 has been assigned, an empty QByteArray() is returned.
704 QByteArray QMovie::format() const
707 return d->reader->format();
711 For image formats that support it, this function sets the background color
714 \sa backgroundColor()
716 void QMovie::setBackgroundColor(const QColor &color)
719 d->reader->setBackgroundColor(color);
723 Returns the background color of the movie. If no background color has been
724 assigned, an invalid QColor is returned.
726 \sa setBackgroundColor()
728 QColor QMovie::backgroundColor() const
731 return d->reader->backgroundColor();
735 Returns the current state of QMovie.
737 \sa MovieState, stateChanged()
739 QMovie::MovieState QMovie::state() const
742 return d->movieState;
746 Returns the rect of the last frame. If no frame has yet been updated, an
747 invalid QRect is returned.
749 \sa currentImage(), currentPixmap()
751 QRect QMovie::frameRect() const
758 Returns the current frame as a QPixmap.
760 \sa currentImage(), updated()
762 QPixmap QMovie::currentPixmap() const
765 return d->currentPixmap;
769 Returns the current frame as a QImage.
771 \sa currentPixmap(), updated()
773 QImage QMovie::currentImage() const
776 return d->currentPixmap.toImage();
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.
783 bool QMovie::isValid() const
790 Returns the number of frames in the movie.
792 Certain animation formats do not support this feature, in which
795 int QMovie::frameCount() const
798 return d->frameCount();
802 Returns the number of milliseconds QMovie will wait before updating the
803 next frame in the animation.
805 int QMovie::nextFrameDelay() const
812 Returns the sequence number of the current frame. The number of the first
813 frame in the movie is 0.
815 int QMovie::currentFrameNumber() const
818 return d->currentFrameNumber;
822 Jumps to the next frame. Returns true on success; otherwise returns false.
824 bool QMovie::jumpToNextFrame()
827 return d->jumpToNextFrame();
831 Jumps to frame number \a frameNumber. Returns true on success; otherwise
834 bool QMovie::jumpToFrame(int frameNumber)
837 return d->jumpToFrame(frameNumber);
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.
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
849 int QMovie::loopCount() const
852 return d->reader->loopCount();
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).
862 void QMovie::setPaused(bool paused)
866 if (d->movieState == NotRunning)
868 d->enterState(Paused);
869 d->nextImageTimer.stop();
871 if (d->movieState == Running)
873 d->enterState(Running);
874 d->nextImageTimer.start(nextFrameDelay());
879 \property QMovie::speed
880 \brief the movie's speed
882 The speed is measured in percentage of the original movie speed.
883 The default speed is 100%.
886 \snippet doc/src/snippets/code/src_gui_image_qmovie.cpp 1
888 void QMovie::setSpeed(int percentSpeed)
891 d->speed = percentSpeed;
894 int QMovie::speed() const
901 Starts the movie. QMovie will enter \l Running state, and start emitting
902 updated() and resized() as the movie progresses.
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.
908 \sa stop(), setPaused()
913 if (d->movieState == NotRunning) {
914 d->_q_loadNextFrame(true);
915 } else if (d->movieState == Paused) {
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.
925 If QMovie is already in the \l NotRunning state, this function
928 \sa start(), setPaused()
933 if (d->movieState == NotRunning)
935 d->enterState(NotRunning);
936 d->nextImageTimer.stop();
937 d->nextFrameNumber = 0;
943 Returns the scaled size of frames.
945 \sa QImageReader::scaledSize()
947 QSize QMovie::scaledSize()
950 return d->reader->scaledSize();
956 Sets the scaled frame size to \a size.
958 \sa QImageReader::setScaledSize()
960 void QMovie::setScaledSize(const QSize &size)
963 d->reader->setScaledSize(size);
969 Returns the list of image formats supported by QMovie.
971 \sa QImageReader::supportedImageFormats()
973 QList<QByteArray> QMovie::supportedFormats()
975 QList<QByteArray> list = QImageReader::supportedImageFormats();
976 QMutableListIterator<QByteArray> it(list);
978 buffer.open(QIODevice::ReadOnly);
979 while (it.hasNext()) {
980 QImageReader reader(&buffer, it.next());
981 if (!reader.supportsAnimation())
988 \property QMovie::cacheMode
989 \brief the movie's cache mode
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).
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.
1003 By default, this property is set to \l CacheNone.
1005 \sa QMovie::CacheMode
1008 QMovie::CacheMode QMovie::cacheMode() const
1011 return d->cacheMode;
1014 void QMovie::setCacheMode(CacheMode cacheMode)
1017 d->cacheMode = cacheMode;
1022 #include "moc_qmovie.cpp"
1024 #endif // QT_NO_MOVIE