Skip to content

Commit

Permalink
Merge pull request wang-bin#1248 from ThatOdieGuy/skip-speed-and-disp…
Browse files Browse the repository at this point in the history
…lay-fix

Skip speed and display fix
  • Loading branch information
wang-bin authored Oct 8, 2019
2 parents b51fee7 cf06dbb commit b12a99e
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 12 deletions.
83 changes: 76 additions & 7 deletions src/AVDemuxThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 27,7 @@
#include "VideoThread.h"
#include <QtCore/QTime>
#include "utils/Logger.h"
#include <QTimer>

#define RESUME_ONCE_ON_SEEK 0

Expand Down Expand Up @@ -82,6 83,10 @@ AVDemuxThread::AVDemuxThread(QObject *parent) :
, audio_thread(0)
, video_thread(0)
, clock_type(-1)
, last_seek_pos(0)
, current_seek_task(nullptr)
, stepping(false)
, stepping_timeout_time(0)
{
seek_tasks.setCapacity(1);
seek_tasks.blockFull(false);
Expand All @@ -95,6 100,10 @@ AVDemuxThread::AVDemuxThread(AVDemuxer *dmx, QObject *parent) :
, m_buffer(0)
, audio_thread(0)
, video_thread(0)
, last_seek_pos(0)
, current_seek_task(nullptr)
, stepping(false)
, stepping_timeout_time(0)
{
setDemuxer(dmx);
seek_tasks.setCapacity(1);
Expand Down Expand Up @@ -153,6 162,8 @@ void AVDemuxThread::stepBackward()
{
if (!video_thread)
return;
if (hasSeekTasks())
return;
AVThread *t = video_thread;
const qreal pre_pts = video_thread->previousHistoryPts();
if (pre_pts == 0.0) {
Expand All @@ -165,15 176,24 @@ void AVDemuxThread::stepBackward()
audio_thread->packetQueue()->clear(); // will put new packets before task run
}

class stepBackwardTask : public QRunnable {
class stepBackwardTask : public QObject, public QRunnable {
public:
QTimer timeout_timer;

stepBackwardTask(AVDemuxThread *dt, qreal t)
: demux_thread(dt)
, pts(t)
{}
void run() {
demux_thread->stepping = true;
demux_thread->stepping_timeout_time = QDateTime::currentMSecsSinceEpoch() 200;

AVThread *avt = demux_thread->videoThread();
avt->packetQueue()->clear(); // clear here

connect(avt, SIGNAL(frameDelivered()), demux_thread, SLOT(finishedStepBackward()), Qt::DirectConnection);
connect(avt, SIGNAL(eofDecoded()), demux_thread, SLOT(finishedStepBackward()), Qt::DirectConnection);

if (pts <= 0) {
demux_thread->demuxer->seek(qint64(-pts*1000.0) - 500LL);
QVector<qreal> ts;
Expand All @@ -193,6 213,7 @@ void AVDemuxThread::stepBackward()
pts -= dt/2.0;
}
qDebug("step backward: %lld, %f", qint64(pts*1000.0), pts);

demux_thread->video_thread->setDropFrameOnSeek(false);
demux_thread->seekInternal(qint64(pts*1000.0), AccurateSeek);
}
Expand All @@ -202,6 223,7 @@ void AVDemuxThread::stepBackward()
};

pause(true);

t->packetQueue()->clear(); // will put new packets before task run
t->packetQueue();
Packet pkt;
Expand All @@ -211,6 233,15 @@ void AVDemuxThread::stepBackward()
newSeekRequest(new stepBackwardTask(this, pre_pts));
}

void AVDemuxThread::finishedStepBackward()
{
disconnect(video_thread, SIGNAL(frameDelivered()), this, SLOT(finishedStepBackward()));
disconnect(video_thread, SIGNAL(eofDecoded()), this, SLOT(finishedStepBackward()));

stepping = false;
stepping_timeout_time = 0;
}

void AVDemuxThread::seek(qint64 external_pos, qint64 pos, SeekType type)
{
class SeekTask : public QRunnable {
Expand Down Expand Up @@ -241,7 272,7 @@ void AVDemuxThread::seek(qint64 external_pos, qint64 pos, SeekType type)
};

end = false;
// queue maybe blocked by put()
// queue maybe blocked by put()
// These must be here or seeking while paused will not update the video frame
if (audio_thread) {
audio_thread->packetQueue()->clear();
Expand Down Expand Up @@ -278,6 309,7 @@ void AVDemuxThread::seekInternal(qint64 pos, SeekType type, qint64 external_pos)
if (external_pos != std::numeric_limits < qint64 >::min() )
t->clock()->updateExternalClock(qMax(qint64(0), external_pos));
t->clock()->updateValue(double(pos)/1000.0);
last_seek_pos = pos;
t->requestSeek();
// TODO: the first frame (key frame) will not be decoded correctly if flush() is called.
//PacketBuffer *pb = t->packetQueue();
Expand Down Expand Up @@ -315,12 347,29 @@ void AVDemuxThread::processNextSeekTask()
{
if (seek_tasks.isEmpty())
return;
QRunnable *task = seek_tasks.take();
if (!task)

current_seek_task = seek_tasks.take();
if (!current_seek_task)
return;
task->run();
if (task->autoDelete())
delete task;
current_seek_task->run();

if (current_seek_task->autoDelete())
delete current_seek_task;
current_seek_task = nullptr;
}

bool AVDemuxThread::hasSeekTasks()
{
// This is not great. But I couldn't figure out how to get QTimers and stepBackwardTask working
if (stepping && stepping_timeout_time > 0 && stepping_timeout_time < QDateTime::currentMSecsSinceEpoch()) {
finishedStepBackward();
}
return !seek_tasks.isEmpty() || current_seek_task || stepping;
}

qint64 AVDemuxThread::lastSeekPos()
{
return last_seek_pos;
}

void AVDemuxThread::pauseInternal(bool value)
Expand Down Expand Up @@ -420,6 469,11 @@ void AVDemuxThread::stepForward()
{
if (end)
return;
if (hasSeekTasks())
return;

stepping = true;

// clock type will be wrong if no lock because slot frameDeliveredOnStepForward() is in video thread
QMutexLocker locker(&next_frame_mutex);
Q_UNUSED(locker);
Expand All @@ -440,6 494,7 @@ void AVDemuxThread::stepForward()
if (!connected) {
connect(t, SIGNAL(frameDelivered()), this, SLOT(frameDeliveredOnStepForward()), Qt::DirectConnection);
connect(t, SIGNAL(eofDecoded()), this, SLOT(eofDecodedOnStepForward()), Qt::DirectConnection);

connected = true;
}
}
Expand Down Expand Up @@ -486,6 541,12 @@ void AVDemuxThread::frameDeliveredOnStepForward()
clock_type = -1;
thread->clock()->updateExternalClock((thread->previousHistoryPts() - thread->clock()->initialValue())*1000.0);
}

// Fudge the bit at the end 33ms so that step forward and step backwards present different values
last_seek_pos = (thread->previousHistoryPts() - thread->clock()->initialValue())*1000.0 33;

stepping = false;

Q_EMIT stepFinished();
}

Expand All @@ -504,9 565,17 @@ void AVDemuxThread::eofDecodedOnStepForward()
thread->clock()->setClockType(AVClock::ClockType(clock_type/2));
clock_type = -1;
}

stepping = false;

Q_EMIT stepFinished();
}

void AVDemuxThread::stepForwardDone()
{

}

void AVDemuxThread::onAVThreadQuit()
{
AVThread* av[] = { audio_thread, video_thread};
Expand Down
11 changes: 10 additions & 1 deletion src/AVDemuxThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 27,7 @@
#include <QtCore/QThread>
#include <QtCore/QRunnable>
#include "PacketBuffer.h"
#include <QTimer>

namespace QtAV {

Expand Down Expand Up @@ -59,6 60,8 @@ class AVDemuxThread : public QThread
MediaEndAction mediaEndAction() const;
void setMediaEndAction(MediaEndAction value);
bool waitForStarted(int msec = -1);
qint64 lastSeekPos();
bool hasSeekTasks();
Q_SIGNALS:
void requestClockPause(bool value);
void mediaStatusChanged(QtAV::MediaStatus);
Expand All @@ -67,9 70,11 @@ class AVDemuxThread : public QThread
void stepFinished();
void internalSubtitlePacketRead(int index, const QtAV::Packet& packet);
private slots:
void finishedStepBackward();
void seekOnPauseFinished();
void frameDeliveredOnStepForward();
void eofDecodedOnStepForward();
void stepForwardDone();
void onAVThreadQuit();

protected:
Expand Down Expand Up @@ -100,7 105,11 @@ private slots:
QMutex buffer_mutex;
QWaitCondition cond;
BlockingQueue<QRunnable*> seek_tasks;

qint64 last_seek_pos;
QRunnable *current_seek_task;
bool stepping;
qint64 stepping_timeout_time;

QSemaphore sem;
QMutex next_frame_mutex;
int clock_type; // change happens in different threads(direct connection)
Expand Down
43 changes: 39 additions & 4 deletions src/AVPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 583,16 @@ void AVPlayer::pause(bool p)
return;
if (isPaused() == p)
return;

if (!p) {
if (d->was_stepping) {
d->was_stepping = false;
// If was stepping, skip our position a little bit behind us.
// This fixes an issue with the audio timer
seek(position() - 100);
}
}

audio()->pause(p);
//pause thread. check pause state?
d->read_thread->pause(p);
Expand Down Expand Up @@ -848,6 858,29 @@ qint64 AVPlayer::position() const
return pts;
}

qint64 AVPlayer::displayPosition() const
{
// Return a cached value if there are seek tasks
if (d->seeking || d->read_thread->hasSeekTasks() || (d->read_thread->buffer() && d->read_thread->buffer()->isBuffering())) {
return d->last_known_good_pts = d->read_thread->lastSeekPos();
}

// TODO: videoTime()?
qint64 pts = d->clock->videoTime()*1000.0;

// If we are stepping around, we want the lastSeekPos.
/// But if we're just paused by the user... we want another value.
if (d->was_stepping) {
pts = d->read_thread->lastSeekPos();
}
if (pts < 0) {
return d->last_known_good_pts;
}
d->last_known_good_pts = pts;

return pts;
}

void AVPlayer::setPosition(qint64 position)
{
// FIXME: strange things happen if seek out of eof
Expand Down Expand Up @@ -1258,6 1291,9 @@ void AVPlayer::playInternal()
else
setPosition((qint64)(d->start_position_norm));
}

d->was_stepping = false;

Q_EMIT stateChanged(PlayingState);
Q_EMIT started(); //we called stop(), so must emit started()
}
Expand Down Expand Up @@ -1540,15 1576,14 @@ void AVPlayer::stepForward()
{
// pause clock
pause(true); // must pause AVDemuxThread (set user_paused true)
d->was_stepping = true;
d->read_thread->stepForward();
}

void AVPlayer::stepBackward()
{
d->clock->pause(true);
d->state = PausedState;
Q_EMIT stateChanged(d->state);
Q_EMIT paused(true);
pause(true);
d->was_stepping = true;
d->read_thread->stepBackward();
}

Expand Down
2 changes: 2 additions & 0 deletions src/AVPlayerPrivate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 111,8 @@ AVPlayer::Private::Private()
, status(NoMedia)
, state(AVPlayer::StoppedState)
, end_action(MediaEndAction_Default)
, last_known_good_pts(0)
, was_stepping(false)
{
demuxer.setInterruptTimeout(interrupt_timeout);
/*
Expand Down
2 changes: 2 additions & 0 deletions src/AVPlayerPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 111,8 @@ class AVPlayer::Private
bool reset_state;
qint64 start_position, stop_position;
qint64 start_position_norm, stop_position_norm; // real position
qint64 last_known_good_pts;
bool was_stepping;
int repeat_max, repeat_current;
int timer_id; //notify position change and check AB repeat range. active when playing

Expand Down
1 change: 1 addition & 0 deletions src/QtAV/AVPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 178,7 @@ class Q_AV_EXPORT AVPlayer : public QObject
*/
qint64 stopPosition() const; //unit: ms
qint64 position() const; //unit: ms
qint64 displayPosition() const;
//0: play once. N: play N 1 times. <0: infinity
int repeat() const; //or repeatMax()?
/*!
Expand Down

0 comments on commit b12a99e

Please sign in to comment.