Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qffmpegrenderer.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include <qloggingcategory.h>
6
8
9namespace QFFmpeg {
10
11static Q_LOGGING_CATEGORY(qLcRenderer, "qt.multimedia.ffmpeg.renderer");
12
13Renderer::Renderer(const TimeController &tc, const std::chrono::microseconds &seekPosTimeOffset)
14 : m_timeController(tc),
15 m_lastPosition(tc.currentPosition()),
16 m_seekPos(tc.currentPosition(-seekPosTimeOffset))
17{
18}
19
21{
22 QMetaObject::invokeMethod(this, [this, tp, trackTime]() {
23 m_timeController.syncSoft(tp, trackTime);
24 scheduleNextStep(true);
25 });
26}
27
29{
30 return m_seekPos;
31}
32
34{
35 return m_lastPosition;
36}
37
39{
40 QMetaObject::invokeMethod(this, [this, rate]() {
41 m_timeController.setPlaybackRate(rate);
44 });
45}
46
48{
49 if (!m_isStepForced.exchange(true))
50 QMetaObject::invokeMethod(this, [this]() {
51 // maybe set m_forceStepMaxPos
52
53 if (isAtEnd()) {
55 }
56 else {
57 m_explicitNextFrameTime = Clock::now();
59 }
60 });
61}
62
64{
65 return m_isStepForced;
66}
67
69{
70 render({});
71}
72
74{
75 const auto isFrameOutdated = frame.isValid() && frame.absoluteEnd() < m_seekPos;
76
77 if (isFrameOutdated) {
78 qCDebug(qLcRenderer) << "frame outdated! absEnd:" << frame.absoluteEnd() << "absPts"
79 << frame.absolutePts() << "seekPos:" << m_seekPos;
81 return;
82 }
83
84 m_frames.enqueue(frame);
85
86 if (m_frames.size() == 1)
88}
89
91{
92 m_timeController.setPaused(isPaused());
94}
95
97{
98 return !m_frames.empty() && (m_isStepForced || PlaybackEngineObject::canDoNextStep());
99}
100
102{
103 return m_timeController.playbackRate();
104}
105
107{
108 auto frame = !m_frames.empty() ? m_frames.front() : Frame();
109 if (frame.isValid()) {
110 using namespace std::chrono;
111
112 const auto nextTime = m_explicitNextFrameTime
113 ? *m_explicitNextFrameTime
114 : m_timeController.timeFromPosition(frame.absolutePts());
115
116 const auto delay = nextTime - Clock::now();
117 return std::max(0, static_cast<int>(duration_cast<milliseconds>(delay).count()));
118 }
119
120 return 0;
121}
122
124{
125 if (!m_isStepForced.exchange(false))
126 return false;
127
128 m_explicitNextFrameTime.reset();
130 return true;
131}
132
134{
135 auto frame = m_frames.front();
136
137 if (setForceStepDone()) {
138 // if (frame.isValid() && frame.pts() > m_forceStepMaxPos) {
139 // scheduleNextStep(false);
140 // return;
141 // }
142 }
143
144 const auto result = renderInternal(frame);
145
146 if (result.done) {
147 m_explicitNextFrameTime.reset();
148 m_frames.dequeue();
149
150 if (frame.isValid()) {
151 m_lastPosition = std::max(frame.absolutePts(), m_lastPosition.load());
152 m_seekPos = frame.absoluteEnd();
153
154 const auto loopIndex = frame.loopOffset().index;
155 if (m_loopIndex < loopIndex) {
156 m_loopIndex = loopIndex;
157 emit loopChanged(id(), frame.loopOffset().pos, m_loopIndex);
158 }
159
161 }
162 } else {
163 m_explicitNextFrameTime = Clock::now() + result.recheckInterval;
164 }
165
166 setAtEnd(result.done && !frame.isValid());
167
168 scheduleNextStep(false);
169}
170
171std::chrono::microseconds Renderer::frameDelay(const Frame &frame) const
172{
173 return std::chrono::duration_cast<std::chrono::microseconds>(
174 Clock::now() - m_timeController.timeFromPosition(frame.absolutePts()));
175}
176
177void Renderer::changeRendererTime(std::chrono::microseconds offset)
178{
179 const auto now = Clock::now();
180 const auto pos = m_timeController.positionFromTime(now);
181 m_timeController.sync(now + offset, pos);
182 emit synchronized(id(), now + offset, pos);
183}
184
185} // namespace QFFmpeg
186
188
189#include "moc_qffmpegrenderer_p.cpp"
void scheduleNextStep(bool allowDoImmediatelly=true)
int timerInterval() const override
void onPauseChanged() override
void syncSoft(TimePoint tp, qint64 trackPos)
void doNextStep() override
TimeController::TimePoint TimePoint
virtual RenderingResult renderInternal(Frame frame)=0
void frameProcessed(Frame)
bool canDoNextStep() const override
void setPlaybackRate(float rate)
qint64 seekPosition() const
float playbackRate() const
std::chrono::microseconds frameDelay(const Frame &frame) const
Renderer(const TimeController &tc, const std::chrono::microseconds &seekPosTimeOffset={})
virtual void onPlaybackRateChanged()
void changeRendererTime(std::chrono::microseconds offset)
void loopChanged(Id id, qint64 offset, int index)
qint64 lastPosition() const
bool isStepForced() const
void sync(qint64 trackPos=0)
qint64 positionFromTime(TimePoint tp, bool ignorePause=false) const
TimePoint timeFromPosition(qint64 pos, bool ignorePause=false) const
void setPlaybackRate(PlaybackRate playbackRate)
void syncSoft(const TimePoint &tp, qint64 pos, const Clock::duration &fixingTime=std::chrono::seconds(4))
QPoint pos
the position of the widget within its parent widget
Definition qwidget.h:111
Combined button and popup list for selecting options.
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLenum GLenum GLsizei count
GLenum GLuint GLintptr offset
GLuint GLenum * rate
const GLfloat * tc
GLuint64EXT * result
[6]
#define emit
long long qint64
Definition qtypes.h:55
QFrame frame
[0]
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...