diff --git a/src/AVDemuxThread.cpp b/src/AVDemuxThread.cpp index a51f4d762..82983afd5 100644 --- a/src/AVDemuxThread.cpp +++ b/src/AVDemuxThread.cpp @@ -82,6 +82,8 @@ AVDemuxThread::AVDemuxThread(QObject *parent) : , audio_thread(0) , video_thread(0) , clock_type(-1) + , m_repeat_current(0) + , m_repeat_max(0) { seek_tasks.setCapacity(1); seek_tasks.blockFull(false); @@ -95,6 +97,8 @@ AVDemuxThread::AVDemuxThread(AVDemuxer *dmx, QObject *parent) : , m_buffer(0) , audio_thread(0) , video_thread(0) + , m_repeat_current(0) + , m_repeat_max(0) { setDemuxer(dmx); seek_tasks.setCapacity(1); @@ -556,6 +560,14 @@ void AVDemuxThread::run() //vthread maybe changed by AVPlayer.setPriority() from no dec case vqueue = video_thread ? video_thread->packetQueue() : 0; if (demuxer->atEnd()) { + if (getRepeatCurrent() < 0 || (getRepeatCurrent() >= m_repeat_max && m_repeat_max >= 0)) { + m_repeat_current = -1; + } else { + m_repeat_current++; + qDebug() << " m_repeat_current = " << m_repeat_current; + qDebug() << " m_repeat_max = " << m_repeat_max; + seek(qint64(0), AccurateSeek); + } // if avthread may skip 1st eof packet because of a/v sync const int kMaxEof = 1;//if buffer packet, we can use qMax(aqueue->bufferValue(), vqueue->bufferValue()) and not call blockEmpty(false); if (aqueue && (!was_end || aqueue->isEmpty())) { @@ -731,4 +743,27 @@ bool AVDemuxThread::tryPause(unsigned long timeout) cond.wait(&buffer_mutex, timeout); return true; } + +int AVDemuxThread::getRepeatCurrent() +{ + return m_repeat_current; +} + +void AVDemuxThread::setRepeatCurrent(int repeat_current) +{ + m_repeat_current = repeat_current; +} + +int AVDemuxThread::getRepeatMax() +{ + return m_repeat_max; +} + +void AVDemuxThread::setRepeatMax(int repeat_max) +{ + m_repeat_max = repeat_max; + if (m_repeat_max < 0) + m_repeat_max = std::numeric_limits::max(); +} + } //namespace QtAV diff --git a/src/AVDemuxThread.h b/src/AVDemuxThread.h index 350962013..85708131e 100644 --- a/src/AVDemuxThread.h +++ b/src/AVDemuxThread.h @@ -59,6 +59,10 @@ class AVDemuxThread : public QThread MediaEndAction mediaEndAction() const; void setMediaEndAction(MediaEndAction value); bool waitForStarted(int msec = -1); + int getRepeatCurrent(); + int getRepeatMax(); + void setRepeatCurrent(int repeat_current); + void setRepeatMax(int repeat_max); Q_SIGNALS: void requestClockPause(bool value); void mediaStatusChanged(QtAV::MediaStatus); @@ -106,6 +110,8 @@ private slots: int clock_type; // change happens in different threads(direct connection) friend class SeekTask; friend class stepBackwardTask; + int m_repeat_current; + int m_repeat_max; }; } //namespace QtAV diff --git a/src/AVPlayer.cpp b/src/AVPlayer.cpp index e7a96d073..a2d3ef8cc 100644 --- a/src/AVPlayer.cpp +++ b/src/AVPlayer.cpp @@ -871,21 +871,19 @@ void AVPlayer::setPosition(qint64 position) int AVPlayer::repeat() const { - return d->repeat_max; + return d->read_thread->getRepeatMax(); } int AVPlayer::currentRepeat() const { - return d->repeat_current; + return d->read_thread->getRepeatCurrent(); } // TODO: reset current_repeat? void AVPlayer::setRepeat(int max) { - d->repeat_max = max; - if (d->repeat_max < 0) - d->repeat_max = std::numeric_limits::max(); - Q_EMIT repeatChanged(d->repeat_max); + d->read_thread->setRepeatMax(max); + Q_EMIT repeatChanged(d->read_thread->getRepeatMax()); } bool AVPlayer::setExternalAudio(const QString &file) @@ -1250,8 +1248,8 @@ void AVPlayer::playInternal() QMetaObject::invokeMethod(this, "startNotifyTimer", Qt::AutoConnection); } d->state = PlayingState; - if (d->repeat_current < 0) - d->repeat_current = 0; + if(currentRepeat() < 0) + d->read_thread->setRepeatCurrent(0); } //end lock scoped here to avoid dead lock if connect started() to a slot that call unload()/play() if (d->start_position_norm > 0) { if (relativeTimeMode()) @@ -1267,34 +1265,30 @@ void AVPlayer::stopFromDemuxerThread() { qDebug("demuxer thread emit finished. repeat: %d/%d", currentRepeat(), repeat()); d->seeking = false; - if (currentRepeat() < 0 || (currentRepeat() >= repeat() && repeat() >= 0)) { - qreal stop_pts = masterClock()->videoTime(); - if (stop_pts <= 0) - stop_pts = masterClock()->value(); - masterClock()->reset(); - QMetaObject::invokeMethod(this, "stopNotifyTimer"); - // vars not set by user can be reset - d->repeat_current = -1; - d->start_position_norm = 0; - d->stop_position_norm = kInvalidPosition; // already stopped. so not 0 but invalid. 0 can stop the playback in timerEvent - d->media_end = kInvalidPosition; - qDebug("avplayer emit stopped()"); - d->state = StoppedState; - QMetaObject::invokeMethod(this, "stateChanged", Q_ARG(QtAV::AVPlayer::State, d->state)); - QMetaObject::invokeMethod(this, "stopped"); - QMetaObject::invokeMethod(this, "stoppedAt", Q_ARG(qint64, qint64(stop_pts*1000.0))); - //Q_EMIT stateChanged(d->state); - //Q_EMIT stopped(); - //Q_EMIT stoppedAt(stop_pts*1000.0); - /* - * currently preload is not supported. so always unload. Then some properties will be reset, e.g. duration() - */ - unload(); //TODO: invoke? - } else { - d->repeat_current++; - QMetaObject::invokeMethod(this, "play"); //ensure play() is called from player thread - } + qreal stop_pts = masterClock()->videoTime(); + if (stop_pts <= 0) + stop_pts = masterClock()->value(); + masterClock()->reset(); + QMetaObject::invokeMethod(this, "stopNotifyTimer"); + // vars not set by user can be reset + + d->start_position_norm = 0; + d->stop_position_norm = kInvalidPosition; // already stopped. so not 0 but invalid. 0 can stop the playback in timerEvent + d->media_end = kInvalidPosition; + qDebug("avplayer emit stopped()"); + d->state = StoppedState; + QMetaObject::invokeMethod(this, "stateChanged", Q_ARG(QtAV::AVPlayer::State, d->state)); + QMetaObject::invokeMethod(this, "stopped"); + QMetaObject::invokeMethod(this, "stoppedAt", Q_ARG(qint64, qint64(stop_pts*1000.0))); + //Q_EMIT stateChanged(d->state); + //Q_EMIT stopped(); + //Q_EMIT stoppedAt(stop_pts*1000.0); + + /* + * currently preload is not supported. so always unload. Then some properties will be reset, e.g. duration() + */ + unload(); //TODO: invoke? } void AVPlayer::aboutToQuitApp() @@ -1455,7 +1449,7 @@ void AVPlayer::stop() } d->seeking = false; d->reset_state = true; - d->repeat_current = -1; + d->read_thread->setRepeatCurrent(-1); if (!isPlaying()) { qDebug("Not playing~"); if (mediaStatus() == LoadingMedia || mediaStatus() == LoadedMedia) { @@ -1515,22 +1509,25 @@ void AVPlayer::timerEvent(QTimerEvent *te) qDebug("stopPosition() == 0, stop"); stop(); } - // t < d->start_position is ok. d->repeat_max<0 means repeat forever + // t < d->start_position is ok. repeat()< 0 means repeat forever + if (currentRepeat() >= repeat() && repeat() >= 0) { d->reset_state = true; // true is default, can remove here qDebug("stopPosition() %lld/%lld reached and no repeat: %d", t, stopPosition(), repeat()); stop(); return; } + // FIXME: now stop instead of seek if reach media's end. otherwise will not get eof again if (d->stop_position_norm == mediaStopPosition() || !isSeekable()) { // if not seekable, how it can start to play at specified position? - qDebug("normalized stopPosition() == mediaStopPosition() or !seekable. d->repeat_current=%d", d->repeat_current); + qDebug("normalized stopPosition() == mediaStopPosition() or !seekable. currentRepeat()=%d", currentRepeat()); d->reset_state = false; stop(); // repeat after all threads stopped } else { - d->repeat_current++; - qDebug("noramlized stopPosition() != mediaStopPosition() and seekable. d->repeat_current=%d", d->repeat_current); + int repeat_current = d->read_thread->getRepeatCurrent(); + d->read_thread->setRepeatCurrent(repeat_current++); + qDebug("noramlized stopPosition() != mediaStopPosition() and seekable. currentRepeat()=%d", currentRepeat()); setPosition(d->start_position_norm); } }