e5fcad3 by Lars Knoll at 2009-03-23 1
/****************************************************************************
2
**
fbc2c44 by Jason McDonald at 2011-01-10 3
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
04e3b30 by Jason McDonald at 2009-09-09 4
** All rights reserved.
858c70f by Jason McDonald at 2009-06-16 5
** Contact: Nokia Corporation (qt-info@nokia.com)
e5fcad3 by Lars Knoll at 2009-03-23 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
309db73 by Jason McDonald at 2009-08-31 13
** contained in the Technology Preview License Agreement accompanying
14
** this package.
e5fcad3 by Lars Knoll at 2009-03-23 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
**
04e3b30 by Jason McDonald at 2009-09-09 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.
e5fcad3 by Lars Knoll at 2009-03-23 27
**
309db73 by Jason McDonald at 2009-08-31 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
**
e5fcad3 by Lars Knoll at 2009-03-23 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
911557f by Volker Hilsheimer at 2009-08-17 48
    \ingroup painting
e5fcad3 by Lars Knoll at 2009-03-23 49
9e389da by David Boddie at 2009-09-25 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
e5fcad3 by Lars Knoll at 2009-03-23 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);
3d50220 by Thierry Bastian at 2009-08-17 363
                    (void)reader->canRead(); // Provoke a device->open() call
e5fcad3 by Lars Knoll at 2009-03-23 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