Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
rectalogic committed Nov 29, 2023
1 parent 57ad5a0 commit 9d0e84f
Show file tree
Hide file tree
Showing 8 changed files with 28 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/mediafx/image_clip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ void ImageClip::loadMedia(const QUrl& url)
videoFrame.unmap();
}

bool ImageClip::prepareNextVideoFrame()
bool ImageClip::prepareNextVideoFrame(const Interval& globalTime)
{
// XXX timestamp frame based on nextClipTime() ? (in microseconds, not milliseconds)
setCurrentVideoFrame(videoFrame);
Expand Down
2 changes: 1 addition & 1 deletion src/mediafx/image_clip.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class ImageClip : public VisualClip {
protected:
void loadMedia(const QUrl&) override;

bool prepareNextVideoFrame() override;
bool prepareNextVideoFrame(const Interval& globalTime) override;

void stop() override;

Expand Down
19 changes: 12 additions & 7 deletions src/mediafx/rate_control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@

// XXX need to keep buffer partially full, scale to keep 5 frames in buffer somehow

// track frame enqueue time, and growth rate of buffer, and tweak playback to control growth relative to desired size?
//
/*XXX
qint64 movingAverage(qint64 average, qint64 sample)
{
Expand All @@ -44,24 +46,25 @@ qint64 movingAverage(qint64 average, qint64 sample)
return average;
}
*/
const int desiredBufferSize = 5; // XXX make member - fold into rateScalar

qreal RateControl::playbackRate() const
{
qreal rate = 10.0;
if (isFrameRequiredTimerValid && isEnqueueTimerValid) {
qreal rate = desiredBufferSize;
if (!bufferedFrames.isEmpty() && timeSinceFrameLastRequired && isEnqueueTimerValid) {
auto timeSinceLastEnqueued = enqueueTimer.durationElapsed().count();
auto timeSinceLastRequired = frameRequiredTimer.durationElapsed().count();
rate = (timeSinceLastEnqueued / (qreal)timeSinceLastRequired) * rateScalar;
qCritical() << "rateScalar" << rateScalar << "rate" << rate << "frames" << bufferedFrames.size() << "timeSinceLastEnqueued" << timeSinceLastEnqueued << "timeSinceLastRequired" << timeSinceLastRequired; // XXX
rate = (timeSinceLastEnqueued / (qreal)timeSinceFrameLastRequired)
* (desiredBufferSize / (qreal)bufferedFrames.size())
* rateScalar;
qCritical() << "rateScalar" << rateScalar << "rate" << rate << "frames" << bufferedFrames.size() << "timeSinceLastEnqueued" << timeSinceLastEnqueued << "timeSinceFrameLastRequired" << timeSinceFrameLastRequired; // XXX
}
return rate;
}

void RateControl::onVideoFrameRequired()
{
// Valid when we are called the 2nd time
if (frameRequiredTimer.isValid())
isFrameRequiredTimerValid = true;
timeSinceFrameLastRequired = frameRequiredTimer.durationElapsed().count();
frameRequiredTimer.start();
}

Expand All @@ -76,6 +79,7 @@ void RateControl::enqueue(const QVideoFrame& videoFrame)
isEnqueueTimerValid = true;
enqueueTimer.start();
bufferedFrames.enqueue(videoFrame);
qCritical() << "enqueue" << bufferedFrames.size(); // XXX
}

void RateControl::reset()
Expand All @@ -84,4 +88,5 @@ void RateControl::reset()
bufferedFrames.squeeze();
frameRequiredTimer.invalidate();
enqueueTimer.invalidate();
timeSinceFrameLastRequired = 0;
}
1 change: 1 addition & 0 deletions src/mediafx/rate_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class RateControl : public QObject {

private:
QElapsedTimer frameRequiredTimer;
qint64 timeSinceFrameLastRequired = 0;
bool isFrameRequiredTimerValid = false;
QElapsedTimer enqueueTimer;
bool isEnqueueTimerValid = false;
Expand Down
14 changes: 9 additions & 5 deletions src/mediafx/video_clip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ void VideoClip::loadMedia(const QUrl& url)

void VideoClip::onRateControl()
{
mediaPlayer.setPlaybackRate(rateControl.playbackRate());
auto rate = rateControl.playbackRate();
qCritical() << "onRateControl" << rate; // XXX
mediaPlayer.setPlaybackRate(rate);
}

void VideoClip::onVideoFrameChanged(const QVideoFrame& frame)
Expand All @@ -69,7 +71,7 @@ void VideoClip::onVideoFrameChanged(const QVideoFrame& frame)
QMetaObject::invokeMethod(this, &VideoClip::onRateControl, Qt::QueuedConnection);
}

bool VideoClip::prepareNextVideoFrame()
bool VideoClip::prepareNextVideoFrame(const Interval& globalTime)
{
QMutexLocker locker(&mutex);
auto nextFrameTime = nextClipTime();
Expand All @@ -81,9 +83,11 @@ bool VideoClip::prepareNextVideoFrame()
if (videoFrame.isValid() && nextFrameTime.contains(videoFrame.startTime())) {
return true;
}
if (rateControl.isEmpty())
qCritical() << "prepareNextVideoFrame BUFFER EMPTY"; // XXX
rateControl.onVideoFrameRequired();
qCritical() << "prepareNextVideoFrame buffer empty" << rateControl.isEmpty(); // XXX
if (lastRequestedGlobalTime != globalTime) {
rateControl.onVideoFrameRequired();
lastRequestedGlobalTime = globalTime;
}
while (!rateControl.isEmpty()) {
videoFrame = rateControl.dequeue();
if (nextFrameTime.contains(videoFrame.startTime())) {
Expand Down
3 changes: 2 additions & 1 deletion src/mediafx/video_clip.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class VideoClip : public VisualClip {
protected:
void loadMedia(const QUrl&) override;

bool prepareNextVideoFrame() override;
bool prepareNextVideoFrame(const Interval& globalTime) override;

void onActiveChanged(bool active) override;

Expand All @@ -59,4 +59,5 @@ private slots:
QVideoSink mediaPlayerSink;
QMutex mutex;
RateControl rateControl;
Interval lastRequestedGlobalTime;
};
2 changes: 1 addition & 1 deletion src/mediafx/visual_clip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void VisualClip::setVideoSinks(const QList<QVideoSink*>& videoSinks)

bool VisualClip::renderClip(const Interval& globalTime)
{
if (!prepareNextVideoFrame())
if (!prepareNextVideoFrame(globalTime))
return false;
for (auto videoSink : videoSinks()) {
videoSink->setVideoFrame(m_currentVideoFrame);
Expand Down
2 changes: 1 addition & 1 deletion src/mediafx/visual_clip.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class VisualClip : public Clip {
void setVideoSinks(const QList<QVideoSink*>&);

bool renderClip(const Interval& globalTime) override;
virtual bool prepareNextVideoFrame() = 0;
virtual bool prepareNextVideoFrame(const Interval& globalTime) = 0;
QVideoFrame currentVideoFrame() const { return m_currentVideoFrame; };
void setCurrentVideoFrame(const QVideoFrame& videoFrame) { m_currentVideoFrame = videoFrame; };

Expand Down

0 comments on commit 9d0e84f

Please sign in to comment.