4#include <QtCore/qcoreapplication.h>
5#include <QtCore/qloggingcategory.h>
31 Q_ASSERT(QThread::isMainThread());
36 m_busObserver->close();
38 if (m_busObserver->currentThreadIsNotifierThread())
44 QMetaObject::invokeMethod(qApp, [bus = std::move(m_busObserver)] {
53 GstPipeline *pipeline = qGstCheckedCast<GstPipeline>(gst_pipeline_new(name));
54 return adopt(pipeline);
60 GstPipeline *pipeline = qGstCheckedCast<GstPipeline>(playbin3.element());
62 return QGstPipeline::adopt(pipeline);
69 QGstPipeline::NeedsRef,
73 gst_pipeline_get_bus(pipeline),
74 QGstBusHandle::HasRef,
78 wrappedObject.set(
"pipeline-private",
std::move(d));
92 d->m_busObserver->installMessageFilter(filter);
98 d->m_busObserver->removeMessageFilter(filter);
103 return gst_element_set_state(element(), state);
106bool QGstPipeline::processNextPendingMessage(GstMessageType types,
std::chrono::nanoseconds timeout)
109 return d->m_busObserver->processNextPendingMessage(types, timeout);
114 return processNextPendingMessage(GST_MESSAGE_ANY, timeout);
119 seek(position(),
true);
122void QGstPipeline::seek(
std::chrono::nanoseconds pos,
double rate,
bool flush)
124 using namespace std::chrono_literals;
130 qCDebug(qLcGstPipeline) <<
"QGstPipeline::seek to" << pos <<
"rate:" << rate
131 << (flush ?
"flushing" :
"not flushing");
133 GstSeekFlags seekFlags = flush ? GST_SEEK_FLAG_FLUSH : GST_SEEK_FLAG_NONE;
134 seekFlags = GstSeekFlags(seekFlags | GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_ACCURATE);
136 bool success = (rate > 0)
137 ? gst_element_seek(element(), rate, GST_FORMAT_TIME, seekFlags, GST_SEEK_TYPE_SET,
138 pos.count(), GST_SEEK_TYPE_END, 0)
139 : gst_element_seek(element(), rate, GST_FORMAT_TIME, seekFlags, GST_SEEK_TYPE_SET, 0,
140 GST_SEEK_TYPE_SET, pos.count());
143 qDebug() <<
"seek: gst_element_seek failed" << pos;
153 qCDebug(qLcGstPipeline) <<
"QGstPipeline::seek to" << pos;
154 seek(pos, getPrivate()->m_rate, flush);
165 qCDebug(qLcGstPipeline) <<
"QGstPipeline::setPlaybackRate to" << rate;
182 if (!forceFlushingSeek) {
183 bool asyncChangeSuccess = waitForAsyncStateChangeComplete();
184 if (!asyncChangeSuccess) {
186 <<
"QGstPipeline::seek: async pipeline change in progress. Seeking impossible";
190 qCDebug(qLcGstPipeline) <<
"QGstPipeline::applyPlaybackRate instantly";
191 bool success = gst_element_seek(
192 element(), d->m_rate, GST_FORMAT_UNDEFINED, GST_SEEK_FLAG_INSTANT_RATE_CHANGE,
193 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
195 qDebug() <<
"setPlaybackRate: gst_element_seek failed";
196 dumpGraph(
"applyPlaybackRateSeekFailed");
199 seek(position(), d->m_rate);
211 std::optional<std::chrono::nanoseconds> pos = QGstElement::position();
213 d->m_position = *pos;
214 qCDebug(qLcGstPipeline) <<
"QGstPipeline::position:"
215 << std::chrono::round<std::chrono::milliseconds>(*pos);
217 qDebug() <<
"QGstPipeline: failed to query position, using previous position";
221 return d->m_position;
226 using namespace std::chrono;
227 return round<milliseconds>(position());
237std::optional<std::chrono::nanoseconds>
240 using namespace std::chrono_literals;
241 using namespace std::chrono;
243 std::chrono::nanoseconds totalSleepTime{};
246 std::optional<nanoseconds> dur = QGstElement::duration();
250 if (totalSleepTime >= timeout)
252 std::this_thread::sleep_for(20ms);
253 totalSleepTime += 20ms;
257std::optional<std::chrono::nanoseconds>
260 using namespace std::chrono_literals;
261 using namespace std::chrono;
263 std::chrono::nanoseconds totalSleepTime{};
266 std::optional<nanoseconds> dur = QGstElement::duration();
270 if (totalSleepTime >= timeout)
273 std::this_thread::sleep_for(20ms);
274 totalSleepTime += 20ms;
278std::optional<std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds>>
281 using namespace std::chrono_literals;
282 using namespace std::chrono;
284 std::chrono::nanoseconds totalSleepTime{};
286 std::optional<nanoseconds> dur;
287 std::optional<nanoseconds> pos;
291 dur = QGstElement::duration();
293 pos = QGstElement::position();
296 return std::pair{ *dur, *pos };
298 if (totalSleepTime >= timeout)
301 std::this_thread::sleep_for(20ms);
302 totalSleepTime += 20ms;
310 gst_element_seek(element(), d->m_rate, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_END,
311 0, GST_SEEK_TYPE_END, 0);
void dumpGraph(const char *fileNamePrefix) const
static QGstElement createFromFactory(const char *factory, const char *name=nullptr)
static QGstPipeline createFromFactory(const char *factory, const char *name)
void applyPlaybackRate(bool forceFlushingSeek=false)
void removeMessageFilter(QGstreamerBusMessageFilter *filter)
GstStateChangeReturn setState(GstState state)
double playbackRate() const
void setPlaybackRate(double rate, bool forceFlushingSeek=false)
std::chrono::nanoseconds position() const
QGstPipeline(GstPipeline *, RefMode mode)
void installMessageFilter(QGstreamerBusMessageFilter *filter)
static QGstPipeline create(const char *name)
std::chrono::milliseconds positionInMs() const
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
std::chrono::nanoseconds m_position
std::unique_ptr< QGstBusObserver > m_busObserver
QGstPipelinePrivate(QGstBusHandle)