Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix seamless loop #1103

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/AVDemuxThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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())) {
Expand Down Expand Up @@ -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<int>::max();
}

} //namespace QtAV
6 changes: 6 additions & 0 deletions src/AVDemuxThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
77 changes: 37 additions & 40 deletions src/AVPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>::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)
Expand Down Expand Up @@ -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())
Expand All @@ -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()
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
}
Expand Down