Skip to content

Commit

Permalink
refactor rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
rectalogic committed Oct 18, 2023
1 parent 6570df7 commit 729ceec
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 42 deletions.
27 changes: 27 additions & 0 deletions mediafx/clip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,33 @@ void Clip::setClipEnd(qint64 clipEnd)
}
}

bool Clip::render(const QMediaTimeRange::Interval& globalTime)
{
// Already rendered for this time
if (currentGlobalTime() == globalTime)
return true;

qint64 duration = globalTime.end() - globalTime.start();
if (nextClipTime().end() == -1) {
setNextClipTime(QMediaTimeRange::Interval(clipStart(), clipStart() + duration));
}
if (active() && clipTimeRange().contains(nextClipTime().start())) {
if (renderClip(globalTime)) {
setCurrentGlobalTime(globalTime);
setNextClipTime(nextClipTime().translated(duration));
return true;
} else {
return false;
}
} else if (clipEnd() < nextClipTime().start()) {
stop();
return false;
} else {
setActive(false);
return false;
}
}

void Clip::stop()
{
setNextClipTime(QMediaTimeRange::Interval(clipStart(), -1));
Expand Down
5 changes: 5 additions & 0 deletions mediafx/clip.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class Clip : public QObject {
qint64 clipEnd() const { return m_clipSegment.end(); };
void setClipEnd(qint64);

bool render(const QMediaTimeRange::Interval& globalTime);

signals:
void clipStartChanged();
void clipEndChanged();
Expand All @@ -54,9 +56,12 @@ class Clip : public QObject {
void setCurrentGlobalTime(const QMediaTimeRange::Interval& currentTime) { m_currentGlobalTime = currentTime; };

virtual void setActive(bool active) = 0;
virtual bool active() = 0;

virtual void loadMedia(const QUrl&) = 0;

virtual bool renderClip(const QMediaTimeRange::Interval& globalTime) = 0;

QMediaTimeRange::Interval nextClipTime() const { return m_nextClipTime; };

virtual void stop();
Expand Down
23 changes: 13 additions & 10 deletions mediafx/mediafx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// found in the LICENSE file.

#include "mediafx.h"
#include "visual_clip.h"
#include "clip.h"
#include <QDebug>
#include <QMediaTimeRange>
#include <QMessageLogContext>
Expand All @@ -23,13 +23,15 @@ MediaFX::MediaFX()
MediaFX::typeId = qmlTypeId("stream.mediafx", 254, 254, "MediaFX");
}

void MediaFX::registerVisualClip(VisualClip* clip)
void MediaFX::registerClip(Clip* clip)
{
if (clip && !activeVisualClips.contains(clip)) {
activeVisualClips.append(clip);
// Ensure we don't have multiple clips simultaneously rendering to the same sink
if (clip && !activeClips.contains(clip)) {
activeClips.append(clip);
#if 0 // XXX how should we deal with this? same issue for main audio, don't want to mix audio buffers from different Clips
//XXX move this into Clip subclasses setActive, so they can query other activeClips and check?
// Ensure we don't have multiple clips simultaneously rendering to the same sink
QSet<const QVideoSink*> set;
for (const auto clip : activeVisualClips) {
for (const auto clip : activeClips) {
for (const auto sink : clip->videoSinks()) {
if (set.contains(sink)) {
qWarning() << "Warning: duplicate QVideoSink found on " << clip;
Expand All @@ -38,21 +40,22 @@ void MediaFX::registerVisualClip(VisualClip* clip)
set.insert(sink);
}
}
#endif
}
}

void MediaFX::unregisterVisualClip(VisualClip* clip)
void MediaFX::unregisterClip(Clip* clip)
{
activeVisualClips.removeOne(clip);
activeClips.removeOne(clip);
}

// XXX need to signal frame time so QML can react (how will QML normalize for transitions etc.?)
// XXX signaling time will advance QTimeline and may activate/deactivate Clips
bool MediaFX::renderVideoFrame(const QMediaTimeRange::Interval& frameTimeRange)
{
bool rendered = true;
for (auto clip : activeVisualClips) {
rendered = rendered && clip->renderVideoFrame(frameTimeRange);
for (auto clip : activeClips) {
rendered = rendered && clip->render(frameTimeRange);
}
return rendered;
}
8 changes: 4 additions & 4 deletions mediafx/mediafx.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include <QMediaTimeRange>
#include <QObject>
#include <QtQmlIntegration>
class VisualClip;
class Clip;

class MediaFX : public QObject {
Q_OBJECT
Expand All @@ -19,11 +19,11 @@ class MediaFX : public QObject {
MediaFX();
static int typeId;

void registerVisualClip(VisualClip* clip);
void unregisterVisualClip(VisualClip* clip);
void registerClip(Clip* clip);
void unregisterClip(Clip* clip);

bool renderVideoFrame(const QMediaTimeRange::Interval& frameTimeRange);

private:
QList<VisualClip*> activeVisualClips;
QList<Clip*> activeClips;
};
39 changes: 14 additions & 25 deletions mediafx/visual_clip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,43 +19,32 @@ void VisualClip::setVideoSinks(const QList<QVideoSink*>& videoSinks)
}
}

bool VisualClip::active()
{
return !m_videoSinks.isEmpty();
}

void VisualClip::setActive(bool active)
{
auto mediaFX = qmlEngine(this)->singletonInstance<MediaFX*>(MediaFX::typeId);
if (active) {
mediaFX->registerVisualClip(this);
mediaFX->registerClip(this);
} else {
mediaFX->unregisterVisualClip(this);
mediaFX->unregisterClip(this);
m_videoSinks.clear();
}
}

bool VisualClip::renderVideoFrame(const QMediaTimeRange::Interval& globalTime)
bool VisualClip::renderClip(const QMediaTimeRange::Interval& globalTime)
{
if (currentGlobalTime() == globalTime)
return true;
qint64 duration = globalTime.end() - globalTime.start();
if (nextClipTime().end() == -1) {
setNextClipTime(QMediaTimeRange::Interval(clipStart(), clipStart() + duration));
}
if (!videoSinks().isEmpty() && clipTimeRange().contains(nextClipTime().start())) {
if (!prepareNextVideoFrame())
return false;
m_currentVideoFrame.setStartTime(globalTime.start());
m_currentVideoFrame.setEndTime(globalTime.end());
for (auto videoSink : videoSinks()) {
videoSink->setVideoFrame(m_currentVideoFrame);
}
setCurrentGlobalTime(globalTime);
setNextClipTime(nextClipTime().translated(duration));
return true;
} else if (clipEnd() < nextClipTime().start()) {
stop();
return false;
} else {
setActive(false);
if (!prepareNextVideoFrame())
return false;
m_currentVideoFrame.setStartTime(globalTime.start());
m_currentVideoFrame.setEndTime(globalTime.end());
for (auto videoSink : videoSinks()) {
videoSink->setVideoFrame(m_currentVideoFrame);
}
return true;
}

void VisualClip::stop()
Expand Down
5 changes: 2 additions & 3 deletions mediafx/visual_clip.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@ class VisualClip : public Clip {
QList<QVideoSink*> videoSinks() const { return m_videoSinks; };
void setVideoSinks(const QList<QVideoSink*>&);

bool renderVideoFrame(const QMediaTimeRange::Interval& globalTime);

protected:
void setActive(bool active) override;
bool active() override;

bool renderClip(const QMediaTimeRange::Interval& globalTime) override;
virtual bool prepareNextVideoFrame() = 0;

void setCurrentVideoFrame(const QVideoFrame& videoFrame) { m_currentVideoFrame = videoFrame; };

virtual void stop() override;
Expand Down

0 comments on commit 729ceec

Please sign in to comment.