Skip to content

Commit

Permalink
configure RenderSession directly
Browse files Browse the repository at this point in the history
  • Loading branch information
rectalogic committed Apr 23, 2024
1 parent 12d9279 commit e947944
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 37 deletions.
2 changes: 2 additions & 0 deletions src/MediaFX/app-encoder.qml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ RenderWindow {
RenderSession {
id: renderSession
sourceUrl: RenderContext.sourceUrl
frameRate: RenderContext.frameRate
sampleRate: RenderContext.sampleRate
anchors.fill: parent
}
Encoder {
Expand Down
2 changes: 0 additions & 2 deletions src/MediaFX/encoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ extern "C" {

// NOLINTBEGIN(bugprone-assignment-in-if-condition)

const Rational Encoder::DefaultFrameRate = { 30, 1 };

Encoder::Encoder(QObject* parent)
: QObject(parent)
{
Expand Down
4 changes: 1 addition & 3 deletions src/MediaFX/encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "formats.h"
#include "render_context.h"
#include <QObject>
#include <QQmlParserStatus>
Expand Down Expand Up @@ -66,9 +67,6 @@ public slots:
private:
Q_DISABLE_COPY(Encoder);

static const Rational DefaultFrameRate;
static const int DefaultSampleRate = 44100;

bool m_isValid = false;
QSize m_frameSize;
int m_frameByteSize = 0;
Expand Down
4 changes: 4 additions & 0 deletions src/MediaFX/formats.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "render_context.h"
#include <QAudioFormat>
#include <QString>
#include <QVideoFrameFormat>
Expand Down Expand Up @@ -37,3 +38,6 @@ inline constexpr auto VideoColorSpace_Qt = QVideoFrameFormat::ColorSpace_AdobeRg
inline constexpr auto VideoColorSpace_FFMPEG = AVCOL_SPC_RGB;
inline constexpr auto VideoColorRange_Qt = QVideoFrameFormat::ColorRange_Full;
inline constexpr auto VideoColorRange_FFMPEG = AVCOL_RANGE_JPEG;

inline constexpr int DefaultSampleRate = 44100;
inline constexpr Rational DefaultFrameRate = { 30, 1 };
10 changes: 5 additions & 5 deletions src/MediaFX/media_clip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void MediaClip::setStartTime(qint64 ms)
}
m_startTime = ms;

std::chrono::duration<double> frameDuration(frameRateToFrameDuration(m_renderSession->outputFrameRate()));
std::chrono::duration<double> frameDuration(frameRateToFrameDuration(m_renderSession->frameRate()));
m_startTimeAdjusted = duration_cast<microseconds>((milliseconds(ms) / frameDuration) * frameDuration);

emit startTimeChanged();
Expand All @@ -93,7 +93,7 @@ void MediaClip::setEndTime(const microseconds& us)
}
m_endTime = duration_cast<milliseconds>(us).count();

std::chrono::duration<double> frameDuration(frameRateToFrameDuration(m_renderSession->outputFrameRate()));
std::chrono::duration<double> frameDuration(frameRateToFrameDuration(m_renderSession->frameRate()));
m_endTimeAdjusted = duration_cast<microseconds>((us / frameDuration) * frameDuration);
if (m_endTimeAdjusted < us)
m_endTimeAdjusted += duration_cast<microseconds>(frameDuration);
Expand Down Expand Up @@ -140,7 +140,7 @@ void MediaClip::render()

m_frameCount++;
m_currentFrameTime = m_currentFrameTime.nextInterval(
m_startTimeAdjusted + duration_cast<microseconds>(m_frameCount * frameRateToFrameDuration(m_renderSession->outputFrameRate())));
m_startTimeAdjusted + duration_cast<microseconds>(m_frameCount * frameRateToFrameDuration(m_renderSession->frameRate())));
if (m_currentFrameTime.start() >= m_endTimeAdjusted) {
emit clipEnded();
m_decoder.stop();
Expand Down Expand Up @@ -196,7 +196,7 @@ void MediaClip::loadMedia()
return;
}
connect(&m_decoder, &Decoder::errorMessage, this, &MediaClip::onDecoderErrorMessage);
if (m_decoder.open(source().toLocalFile(), m_renderSession->outputFrameRate(), m_renderSession->outputAudioFormat(), m_startTimeAdjusted) < 0) {
if (m_decoder.open(source().toLocalFile(), m_renderSession->frameRate(), m_renderSession->outputAudioFormat(), m_startTimeAdjusted) < 0) {
m_renderSession->fatalError();
return;
}
Expand Down Expand Up @@ -226,7 +226,7 @@ void MediaClip::componentComplete()
if (endTime() < 0) {
setEndTime(m_decoder.duration());
}
m_currentFrameTime = Interval(m_startTimeAdjusted, m_startTimeAdjusted + frameRateToFrameDuration<microseconds>(m_renderSession->outputFrameRate()));
m_currentFrameTime = Interval(m_startTimeAdjusted, m_startTimeAdjusted + frameRateToFrameDuration<microseconds>(m_renderSession->frameRate()));
emit currentFrameTimeChanged();
}

Expand Down
58 changes: 36 additions & 22 deletions src/MediaFX/render_session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const QEvent::Type renderEventType = static_cast<const QEvent::Type>(QEvent::reg

RenderSession::RenderSession(QQuickItem* parent)
: QQuickItem(parent)
, m_rootAudioRenderer(std::make_unique<AudioRenderer>())
{
}

Expand Down Expand Up @@ -88,24 +89,18 @@ RenderSessionAttached* RenderSession::qmlAttachedProperties(QObject* object)
return nullptr;
}

void RenderSession::classBegin()
void RenderSession::componentComplete()
{
QQuickItem::classBegin();
m_renderContext = qmlEngine(this)->singletonInstance<RenderContext*>("MediaFX", "RenderContext");
m_currentRenderTime = Interval(0us, frameRateToFrameDuration<microseconds>(m_renderContext->data().frameRate()));
m_rootAudioRenderer = std::make_unique<AudioRenderer>();
QQuickItem::componentComplete();

m_animationDriver = std::make_unique<AnimationDriver>(frameRateToFrameDuration<microseconds>(m_renderContext->data().frameRate()));
m_currentRenderTime = Interval(0us, frameRateToFrameDuration<microseconds>(frameRate()));
m_animationDriver = std::make_unique<AnimationDriver>(frameRateToFrameDuration<microseconds>(frameRate()));
m_animationDriver->install();

m_outputAudioFormat.setSampleFormat(AudioSampleFormat_Qt);
m_outputAudioFormat.setChannelConfig(AudioChannelLayout_Qt);
m_outputAudioFormat.setSampleRate(m_renderContext->data().sampleRate());
}
m_outputAudioFormat.setSampleRate(sampleRate());

void RenderSession::componentComplete()
{
QQuickItem::componentComplete();
QQmlComponent component(qmlEngine(this), m_sourceUrl);
QQmlContext* creationContext = component.creationContext();
if (!creationContext)
Expand Down Expand Up @@ -134,16 +129,40 @@ void RenderSession::geometryChange(const QRectF& newGeometry, const QRectF& oldG

void RenderSession::setSourceUrl(const QUrl& url)
{
if (!m_sourceUrl.isEmpty()) {
qmlWarning(this) << "RenderSession sourceUrl is a write-once property";
return;
}
if (m_sourceUrl != url) {
if (!m_sourceUrl.isEmpty()) {
qmlWarning(this) << "RenderSession sourceUrl is a write-once property";
return;
}
m_sourceUrl = url;
emit sourceUrlChanged();
}
}

void RenderSession::setFrameRate(const Rational& frameRate)
{
if (m_frameRate != frameRate) {
if (m_frameRate != DefaultFrameRate) {
qmlWarning(this) << "RenderSession frameRate is a write-once property";
return;
}
m_frameRate = frameRate;
emit frameRateChanged();
}
}

void RenderSession::setSampleRate(int sampleRate)
{
if (m_sampleRate != sampleRate) {
if (m_sampleRate != DefaultSampleRate) {
qmlWarning(this) << "RenderSession sampleRate is a write-once property";
return;
}
m_sampleRate = sampleRate;
emit sampleRateChanged();
}
}

/*!
\qmlmethod void RenderSession::pauseRendering
Expand Down Expand Up @@ -187,7 +206,7 @@ void RenderSession::render()
emit renderScene();

m_frameCount++;
m_currentRenderTime = m_currentRenderTime.nextInterval(duration_cast<microseconds>(m_frameCount * frameRateToFrameDuration(renderContext()->data().frameRate())));
m_currentRenderTime = m_currentRenderTime.nextInterval(duration_cast<microseconds>(m_frameCount * frameRateToFrameDuration(frameRate())));
emit currentRenderTimeChanged();

if (isSessionEnded()) {
Expand All @@ -204,11 +223,6 @@ void RenderSession::render()

void RenderSession::beginSession()
{
if (!m_renderContext) {
qCritical() << "RenderSession is not initialized";
emit qmlEngine(this)->exit(1);
return;
}
postRenderEvent();
}

Expand Down Expand Up @@ -259,7 +273,7 @@ bool RenderSession::event(QEvent* event)
const QAudioBuffer& RenderSession::silentOutputAudioBuffer()
{
if (!m_silentOutputAudioBuffer.isValid()) {
m_silentOutputAudioBuffer = QAudioBuffer(m_outputAudioFormat.framesForDuration(frameRateToFrameDuration<microseconds>(renderContext()->data().frameRate()).count()), m_outputAudioFormat);
m_silentOutputAudioBuffer = QAudioBuffer(m_outputAudioFormat.framesForDuration(frameRateToFrameDuration<microseconds>(frameRate()).count()), m_outputAudioFormat);
}
return m_silentOutputAudioBuffer;
}
19 changes: 14 additions & 5 deletions src/MediaFX/render_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "formats.h"
#include "interval.h"
#include "render_context.h"
#include <QAudioBuffer>
Expand All @@ -27,7 +28,8 @@ class RenderSession : public QQuickItem {
Q_OBJECT
Q_PROPERTY(QUrl sourceUrl READ sourceUrl WRITE setSourceUrl NOTIFY sourceUrlChanged FINAL REQUIRED)
Q_PROPERTY(IntervalGadget currentRenderTime READ currentRenderTime NOTIFY currentRenderTimeChanged FINAL)
Q_PROPERTY(const RenderContext* renderContext READ renderContext CONSTANT)
Q_PROPERTY(Rational frameRate READ frameRate WRITE setFrameRate NOTIFY frameRateChanged FINAL)
Q_PROPERTY(int sampleRate READ sampleRate WRITE setSampleRate NOTIFY sampleRateChanged FINAL)
QML_ATTACHED(RenderSessionAttached)
QML_ELEMENT

Expand All @@ -38,7 +40,6 @@ class RenderSession : public QQuickItem {
~RenderSession() override;

static RenderSessionAttached* qmlAttachedProperties(QObject* object);
const RenderContext* renderContext() const { return m_renderContext; }

Q_INVOKABLE IntervalGadget createInterval(qint64 start, qint64 end) const
{
Expand All @@ -48,7 +49,12 @@ class RenderSession : public QQuickItem {
const QUrl& sourceUrl() const { return m_sourceUrl; }
void setSourceUrl(const QUrl& url);

const AVRational& outputFrameRate() const { return renderContext()->data().frameRate(); }
const Rational& frameRate() const { return m_frameRate; }
void setFrameRate(const Rational& frameRate);

int sampleRate() const { return m_sampleRate; }
void setSampleRate(int sampleRate);

const QAudioFormat& outputAudioFormat() const { return m_outputAudioFormat; }
const IntervalGadget currentRenderTime() const { return IntervalGadget(m_currentRenderTime); }

Expand All @@ -67,6 +73,8 @@ class RenderSession : public QQuickItem {

signals:
void sourceUrlChanged();
void frameRateChanged();
void sampleRateChanged();
void currentRenderTimeChanged();
void sessionEnded();
void renderMediaClips();
Expand All @@ -79,7 +87,7 @@ public slots:

protected:
void postRenderEvent();
void classBegin() override;
void classBegin() override { }
void componentComplete() override;
void geometryChange(const QRectF& newGeometry, const QRectF& oldGeometry) override;

Expand All @@ -90,7 +98,8 @@ public slots:

QUrl m_sourceUrl;
QQuickItem* m_loadedItem = nullptr;
const RenderContext* m_renderContext = nullptr;
Rational m_frameRate = DefaultFrameRate;
int m_sampleRate = DefaultSampleRate;
QAudioFormat m_outputAudioFormat;
Interval<microseconds> m_currentRenderTime;
int m_frameCount = 1;
Expand Down

0 comments on commit e947944

Please sign in to comment.