Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqnxmediaplayer.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 Research In Motion
2// Copyright (C) 2021 The Qt Company
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
9
10#include <private/qhwvideobuffer_p.h>
11#include <private/qvideoframe_p.h>
12
13#include <QtCore/qabstracteventdispatcher.h>
14#include <QtCore/qcoreapplication.h>
15#include <QtCore/qdir.h>
16#include <QtCore/qfileinfo.h>
17#include <QtCore/quuid.h>
18#include <mm/renderer.h>
19#include <qmediaplayer.h>
20#include <qqnxaudiooutput_p.h>
21#include <qaudiooutput.h>
22
23#include <errno.h>
24#include <sys/strm.h>
25#include <sys/stat.h>
26
27#include <algorithm>
28#include <tuple>
29
30static constexpr int rateToSpeed(qreal rate)
31{
32 return std::floor(rate * 1000);
33}
34
35static constexpr qreal speedToRate(int speed)
36{
37 return std::floor(speed / 1000.0);
38}
39
40static constexpr int normalizeVolume(float volume)
41{
42 return std::clamp<int>(std::floor(volume * 100.0), 0, 100);
43}
44
45static std::tuple<int, int, bool> parseBufferLevel(const QString &value)
46{
47 if (value.isEmpty())
48 return {};
49
50 const int slashPos = value.indexOf('/');
51 if (slashPos <= 0)
52 return {};
53
54 bool ok = false;
55 const int level = value.left(slashPos).toInt(&ok);
56 if (!ok || level < 0)
57 return {};
58
59 const int capacity = value.mid(slashPos + 1).toInt(&ok);
60 if (!ok || capacity < 0)
61 return {};
62
63 return { level, capacity, true };
64}
65
67{
68public:
71 {
72 m_windowGrabber = QQnxWindowGrabber;
73 m_handle = 0;
74 }
75
76 void unmap() override {}
77
78 MapData map(QVideoFrame::MapMode /*mode*/) override
79 {
80 return {};
81 }
82
83 quint64 textureHandle(QRhi *, int plane) const override
84 {
85 if (plane != 0)
86 return 0;
87 if (!m_handle) {
88 const_cast<QnxTextureBuffer*>(this)->m_handle = m_windowGrabber->getNextTextureId();
89 }
90 return m_handle;
91 }
92
93private:
94 QQnxWindowGrabber *m_windowGrabber;
95 quint64 m_handle;
96};
97
99{
100public:
101 QnxRasterBuffer(QQnxWindowGrabber *windowGrabber) { m_windowGrabber = windowGrabber; }
102
103 MapData map(QVideoFrame::MapMode mode) override
104 {
105 if (mode != QVideoFrame::ReadOnly)
106 return {};
107
108 if (buffer.data) {
109 qWarning("QnxRasterBuffer: need to unmap before mapping");
110 return {};
111 }
112
113 buffer = m_windowGrabber->getNextBuffer();
114
115 return {
116 .planeCount = 1,
117 .bytesPerLine = { buffer.stride },
118 .data = { buffer.data },
119 .dataSize = { buffer.width * buffer.height * buffer.pixelSize }
120 };
121 }
122
124 {
125 buffer = {};
126 }
127
128 QVideoFrameFormat format() const override { return {}; }
129
130private:
131 QQnxWindowGrabber *m_windowGrabber;
132 QQnxWindowGrabber::BufferView buffer;
133};
134
135QT_BEGIN_NAMESPACE
136
137QQnxMediaPlayer::QQnxMediaPlayer(QMediaPlayer *parent)
138 : QObject(parent)
139 , QPlatformMediaPlayer(parent)
140 , m_windowGrabber(new QQnxWindowGrabber(this))
141{
142 m_flushPositionTimer.setSingleShot(true);
143 m_flushPositionTimer.setInterval(100);
144
145 connect(&m_flushPositionTimer, &QTimer::timeout, this, &QQnxMediaPlayer::flushPosition);
146
147 connect(m_windowGrabber, &QQnxWindowGrabber::updateScene, this, &QQnxMediaPlayer::updateScene);
148
149 openConnection();
150}
151
153{
154 stop();
155 detach();
156 closeConnection();
157}
158
159void QQnxMediaPlayer::openConnection()
160{
161 static int idCounter = 0;
162
163 m_connection = mmr_connect(nullptr);
164 if (!m_connection) {
165 emitPError(QString::fromLatin1("Unable to connect to the multimedia renderer"));
166 return;
167 }
168
169 m_id = idCounter++;
170 m_contextName = QString::fromLatin1("QQnxMediaPlayer_%1_%2").arg(m_id)
171 .arg(QCoreApplication::applicationPid());
172 m_context = mmr_context_create(m_connection, m_contextName.toLatin1(),
173 0, S_IRWXU|S_IRWXG|S_IRWXO);
174 if (!m_context) {
175 emitPError(QString::fromLatin1("Unable to create context"));
176 closeConnection();
177 return;
178 }
179
180 startMonitoring();
181}
182
183void QQnxMediaPlayer::handleMmEventState(const mmr_event_t *event)
184{
185 if (!event || event->type != MMR_EVENT_STATE)
186 return;
187
188 switch (event->state) {
189 case MMR_STATE_DESTROYED:
190 break;
191 case MMR_STATE_IDLE:
192 mediaStatusChanged(QMediaPlayer::NoMedia);
193 stateChanged(QMediaPlayer::StoppedState);
194 detachVideoOutput();
195 detachInput();
196 break;
197 case MMR_STATE_STOPPED:
198 stateChanged(QMediaPlayer::StoppedState);
199 m_windowGrabber->stop();
200
201 if (m_platformVideoSink)
202 m_platformVideoSink->setVideoFrame({});
203 break;
204 case MMR_STATE_PLAYING:
205 if (event->speed == 0) {
206 stateChanged(QMediaPlayer::PausedState);
207 m_windowGrabber->pause();
208 } else if (state() == QMediaPlayer::PausedState) {
209 m_windowGrabber->resume();
210 stateChanged(QMediaPlayer::PlayingState);
211 } else {
212 m_windowGrabber->start();
213 stateChanged(QMediaPlayer::PlayingState);
214 }
215
216 if (event->speed != m_speed) {
217 m_speed = event->speed;
218
219 if (state() != QMediaPlayer::PausedState)
220 m_configuredSpeed = m_speed;
221
222 playbackRateChanged(::speedToRate(m_speed));
223 }
224 break;
225 }
226}
227
228void QQnxMediaPlayer::handleMmEventStatus(const mmr_event_t *event)
229{
230 if (!event || event->type != MMR_EVENT_STATUS)
231 return;
232
233 if (event->data)
234 handleMmEventStatusData(event->data);
235
236 // update pos
237 if (!event->pos_str || isPendingPositionFlush())
238 return;
239
240 const QByteArray valueBa(event->pos_str);
241
242 bool ok;
243 const qint64 position = valueBa.toLongLong(&ok);
244
245 if (!ok)
246 qCritical("Could not parse position from '%s'", valueBa.constData());
247 else
248 handleMmPositionChanged(position);
249}
250
251void QQnxMediaPlayer::handleMmEventStatusData(const strm_dict_t *data)
252{
253 if (!data)
254 return;
255
256 const auto getValue = [data](const char *key) -> QString {
257 const strm_string_t *value = strm_dict_find_rstr(data, key);
258
259 if (!value)
260 return {};
261
262 return QString::fromUtf8(strm_string_get(value));
263 };
264
265 // update bufferProgress
266 const QString bufferLevel = getValue("bufferlevel");
267
268 if (!bufferLevel.isEmpty()) {
269 const auto & [level, capacity, ok] = ::parseBufferLevel(bufferLevel);
270
271 if (ok)
272 updateBufferLevel(level, capacity);
273 else
274 qCritical("Could not parse buffer capacity from '%s'", qUtf8Printable(bufferLevel));
275 }
276
277 // update MediaStatus
278 const QString bufferStatus = getValue("bufferstatus");
279 const QString suspended = getValue("suspended");
280
281 if (suspended == QStringLiteral("yes"))
282 mediaStatusChanged(QMediaPlayer::StalledMedia);
283 else if (bufferStatus == QStringLiteral("buffering"))
284 mediaStatusChanged(QMediaPlayer::BufferingMedia);
285 else if (bufferStatus == QStringLiteral("playing"))
286 mediaStatusChanged(QMediaPlayer::BufferedMedia);
287}
288
289void QQnxMediaPlayer::handleMmEventError(const mmr_event_t *event)
290{
291 if (!event)
292 return;
293
294 // When playback is explicitly stopped using mmr_stop(), mm-renderer
295 // generates a STATE event. When the end of media is reached, an ERROR
296 // event is generated and the error code contained in the event information
297 // is set to MMR_ERROR_NONE. When an error causes playback to stop,
298 // the error code is set to something else.
299 if (event->details.error.info.error_code == MMR_ERROR_NONE) {
300 mediaStatusChanged(QMediaPlayer::EndOfMedia);
301 stateChanged(QMediaPlayer::StoppedState);
302 }
303}
304
305void QQnxMediaPlayer::closeConnection()
306{
307 stopMonitoring();
308
309 if (m_context) {
310 mmr_context_destroy(m_context);
311 m_context = nullptr;
312 m_contextName.clear();
313 }
314
315 if (m_connection) {
316 mmr_disconnect(m_connection);
317 m_connection = nullptr;
318 }
319}
320
321QByteArray QQnxMediaPlayer::resourcePathForUrl(const QUrl &url)
322{
323 // If this is a local file, mmrenderer expects the file:// prefix and an absolute path.
324 // We treat URLs without scheme as local files, most likely someone just forgot to set the
325 // file:// prefix when constructing the URL.
326 if (url.isLocalFile() || url.scheme().isEmpty()) {
327 const QString relativeFilePath = url.scheme().isEmpty() ? url.path() : url.toLocalFile();
328 const QFileInfo fileInfo(relativeFilePath);
329 return QFile::encodeName(QStringLiteral("file://") + fileInfo.absoluteFilePath());
330
331 // HTTP or similar URL
332 } else {
333 return url.toEncoded();
334 }
335}
336
337void QQnxMediaPlayer::attach()
338{
339 // Should only be called in detached state
340 if (isInputAttached())
341 return;
342
343 if (!m_media.isValid() || !m_context) {
344 mediaStatusChanged(QMediaPlayer::NoMedia);
345 return;
346 }
347
348 resetMonitoring();
349
350 if (!(attachVideoOutput() && attachAudioOutput() && attachInput())) {
351 detach();
352 return;
353 }
354
355 mediaStatusChanged(QMediaPlayer::LoadedMedia);
356}
357
358bool QQnxMediaPlayer::attachVideoOutput()
359{
360 if (isVideoOutputAttached()) {
361 qWarning() << "QQnxMediaPlayer: Video output already attached!";
362 return true;
363 }
364
365 if (!m_context) {
366 qWarning() << "QQnxMediaPlayer: No media player context!";
367 return false;
368 }
369
370 const QByteArray windowGroupId = m_windowGrabber->windowGroupId();
371 if (windowGroupId.isEmpty()) {
372 qWarning() << "QQnxMediaPlayer: Unable to find window group";
373 return false;
374 }
375
376 static int winIdCounter = 0;
377
378 const QString windowName = QStringLiteral("QQnxVideoSink_%1_%2")
379 .arg(winIdCounter++)
380 .arg(QCoreApplication::applicationPid());
381
382 m_windowGrabber->setWindowId(windowName.toLatin1());
383
384 if (m_platformVideoSink)
385 m_windowGrabber->setRhi(m_platformVideoSink->rhi());
386
387 // Start with an invisible window, because we just want to grab the frames from it.
388 const QString videoDeviceUrl = QStringLiteral("screen:?winid=%1&wingrp=%2&initflags=invisible&nodstviewport=1")
389 .arg(windowName, QString::fromLatin1(windowGroupId));
390
391 m_videoId = mmr_output_attach(m_context, videoDeviceUrl.toLatin1(), "video");
392
393 if (m_videoId == -1) {
394 qWarning() << "mmr_output_attach() for video failed";
395 return false;
396 }
397
398 return true;
399}
400
401bool QQnxMediaPlayer::attachAudioOutput()
402{
403 if (isAudioOutputAttached()) {
404 qWarning() << "QQnxMediaPlayer: Audio output already attached!";
405 return true;
406 }
407
408 const QByteArray defaultAudioDevice = qgetenv("QQNX_RENDERER_DEFAULT_AUDIO_SINK");
409
410 m_audioId = mmr_output_attach(m_context,
411 defaultAudioDevice.isEmpty() ? "snd:" : defaultAudioDevice.constData(), "audio");
412
413 if (m_audioId == -1) {
414 emitMmError("mmr_output_attach() for audio failed");
415
416 return false;
417 }
418
419 return true;
420}
421
422bool QQnxMediaPlayer::attachInput()
423{
424 if (isInputAttached())
425 return true;
426
427 const QByteArray resourcePath = resourcePathForUrl(m_media);
428
429 if (resourcePath.isEmpty())
430 return false;
431
432 if (mmr_input_attach(m_context, resourcePath.constData(), "track") != 0) {
433 emitMmError(QStringLiteral("mmr_input_attach() failed for ")
434 + QString::fromUtf8(resourcePath));
435
436 mediaStatusChanged(QMediaPlayer::InvalidMedia);
437
438 return false;
439 }
440
441 m_inputAttached = true;
442
443 return true;
444}
445
446void QQnxMediaPlayer::detach()
447{
448 if (!m_context)
449 return;
450
451 if (isVideoOutputAttached())
452 detachVideoOutput();
453
454 if (isAudioOutputAttached())
455 detachAudioOutput();
456
457 if (isInputAttached())
458 detachInput();
459
460 resetMonitoring();
461}
462
463void QQnxMediaPlayer::detachVideoOutput()
464{
465 m_windowGrabber->stop();
466
467 if (m_platformVideoSink)
468 m_platformVideoSink->setVideoFrame({});
469
470 if (isVideoOutputAttached())
471 mmr_output_detach(m_context, m_videoId);
472
473 m_videoId = -1;
474}
475
476void QQnxMediaPlayer::detachAudioOutput()
477{
478 if (isAudioOutputAttached())
479 mmr_output_detach(m_context, m_audioId);
480
481 m_audioId = -1;
482}
483
484void QQnxMediaPlayer::detachInput()
485{
486 if (isInputAttached())
487 mmr_input_detach(m_context);
488
489 m_inputAttached = false;
490}
491
492bool QQnxMediaPlayer::isVideoOutputAttached() const
493{
494 return m_videoId != -1;
495}
496
497bool QQnxMediaPlayer::isAudioOutputAttached() const
498{
499 return m_audioId != -1;
500}
501
502bool QQnxMediaPlayer::isInputAttached() const
503{
504 return m_inputAttached;
505}
506
507void QQnxMediaPlayer::updateScene(const QSize &size)
508{
509 if (!m_platformVideoSink)
510 return;
511
512 QVideoFrameFormat format(size, QVideoFrameFormat::Format_BGRX8888);
513
514 const QVideoFrame actualFrame = m_windowGrabber->isEglImageSupported()
515 ? QVideoFramePrivate::createFrame(std::make_unique<QnxTextureBuffer>(m_windowGrabber),
516 std::move(format))
517 : QVideoFramePrivate::createFrame(std::make_unique<QnxRasterBuffer>(m_windowGrabber),
518 std::move(format));
519
520 m_platformVideoSink->setVideoFrame(actualFrame);
521}
522
524{
525 return m_metaData.duration();
526}
527
529{
530 return m_position;
531}
532
533void QQnxMediaPlayer::setPosition(qint64 position)
534{
535 if (m_position == position)
536 return;
537
538 m_pendingPosition = position;
539 m_flushPositionTimer.start();
540}
541
542void QQnxMediaPlayer::setPositionInternal(qint64 position)
543{
544 if (!m_context || !m_metaData.isSeekable() || mediaStatus() == QMediaPlayer::NoMedia)
545 return;
546
547 if (mmr_seek(m_context, QString::number(position).toLatin1()) != 0)
548 emitMmError("Seeking failed");
549}
550
551void QQnxMediaPlayer::flushPosition()
552{
553 setPositionInternal(m_pendingPosition);
554}
555
556bool QQnxMediaPlayer::isPendingPositionFlush() const
557{
558 return m_flushPositionTimer.isActive();
559}
560
561void QQnxMediaPlayer::setDeferredSpeedEnabled(bool enabled)
562{
563 m_deferredSpeedEnabled = enabled;
564}
565
566bool QQnxMediaPlayer::isDeferredSpeedEnabled() const
567{
568 return m_deferredSpeedEnabled;
569}
570
571void QQnxMediaPlayer::setVolume(float volume)
572{
573 const int normalizedVolume = ::normalizeVolume(volume);
574
575 if (m_volume == normalizedVolume)
576 return;
577
578 m_volume = normalizedVolume;
579
580 if (!m_muted)
581 updateVolume();
582}
583
584void QQnxMediaPlayer::setMuted(bool muted)
585{
586 if (m_muted == muted)
587 return;
588
589 m_muted = muted;
590
591 updateVolume();
592}
593
594void QQnxMediaPlayer::updateVolume()
595{
596 if (!m_context || m_audioId == -1)
597 return;
598
599 const int volume = m_muted ? 0 : m_volume;
600
601 char buf[] = "100";
602 std::snprintf(buf, sizeof buf, "%d", volume);
603
604 strm_dict_t * dict = strm_dict_new();
605 dict = strm_dict_set(dict, "volume", buf);
606
607 if (mmr_output_parameters(m_context, m_audioId, dict) != 0)
608 emitMmError("mmr_output_parameters: Setting volume failed");
609}
610
611void QQnxMediaPlayer::setAudioOutput(QPlatformAudioOutput *output)
612{
613 QAudioOutput *out = output ? output->q : nullptr;
614 if (m_audioOutput == out)
615 return;
616
617 if (m_audioOutput)
618 disconnect(m_audioOutput.get());
619 m_audioOutput = out;
620 if (m_audioOutput) {
621 connect(out, &QAudioOutput::volumeChanged, this, &QQnxMediaPlayer::setVolume);
622 connect(out, &QAudioOutput::mutedChanged, this, &QQnxMediaPlayer::setMuted);
623 }
624 setVolume(out ? out->volume() : 1.);
625 setMuted(out ? out->isMuted() : true);
626}
627
629{
630 // mm-renderer has buffer properties "status" and "level"
631 // QMediaPlayer's buffer status maps to mm-renderer's buffer level
632 return m_bufferLevel/100.0f;
633}
634
636{
637 return m_metaData.hasAudio();
638}
639
641{
642 return m_metaData.hasVideo();
643}
644
646{
647 return m_metaData.isSeekable();
648}
649
651{
652 // We can't get this information from the mmrenderer API yet, so pretend we can seek everywhere
653 return QMediaTimeRange(0, m_metaData.duration());
654}
655
657{
658 return ::speedToRate(m_speed);
659}
660
662{
663 if (!m_context)
664 return;
665
666 const int speed = ::rateToSpeed(rate);
667
668 if (m_speed == speed)
669 return;
670
671 // defer setting the playback speed for when play() is called to prevent
672 // mm-renderer from inadvertently transitioning into play state
673 if (isDeferredSpeedEnabled() && state() != QMediaPlayer::PlayingState) {
674 m_deferredSpeed = speed;
675 return;
676 }
677
678 if (mmr_speed_set(m_context, speed) != 0)
679 emitMmError("mmr_speed_set failed");
680}
681
683{
684 return m_media;
685}
686
688{
689 // Always 0, we don't support QIODevice streams
690 return 0;
691}
692
693void QQnxMediaPlayer::setMedia(const QUrl &media, QIODevice *stream)
694{
695 Q_UNUSED(stream); // not supported
696
697 stop();
698 detach();
699
700 stateChanged(QMediaPlayer::StoppedState);
701 mediaStatusChanged(QMediaPlayer::LoadingMedia);
702
703 m_media = media;
704
705 updateMetaData(nullptr);
706 attach();
707}
708
710{
711 if (!m_media.isValid() || !m_connection || !m_context || m_audioId == -1) {
712 stateChanged(QMediaPlayer::StoppedState);
713 return;
714 }
715
716 if (state() == QMediaPlayer::PlayingState)
717 return;
718
719 setDeferredSpeedEnabled(false);
720
721 if (m_deferredSpeed) {
722 setPlaybackRate(::speedToRate(*m_deferredSpeed));
723 m_deferredSpeed = {};
724 } else {
725 setPlaybackRate(::speedToRate(m_configuredSpeed));
726 }
727
728 setDeferredSpeedEnabled(true);
729
730 // Un-pause the state when it is paused
731 if (state() == QMediaPlayer::PausedState) {
732 return;
733 }
734
735
736 if (mediaStatus() == QMediaPlayer::EndOfMedia)
737 setPositionInternal(0);
738
739 resetMonitoring();
740 updateVolume();
741
742 if (mmr_play(m_context) != 0) {
743 stateChanged(QMediaPlayer::StoppedState);
744 emitMmError("mmr_play() failed");
745 return;
746 }
747
748 stateChanged(QMediaPlayer::PlayingState);
749}
750
752{
753 if (state() != QMediaPlayer::PlayingState)
754 return;
755
756 setPlaybackRate(0);
757}
758
760{
761 if (!m_context
762 || state() == QMediaPlayer::StoppedState
763 || mediaStatus() == QMediaPlayer::NoMedia)
764 return;
765
766 // mm-renderer does not rewind by default
767 setPositionInternal(0);
768
769 mmr_stop(m_context);
770}
771
772void QQnxMediaPlayer::setVideoSink(QVideoSink *videoSink)
773{
774 m_platformVideoSink = videoSink
775 ? static_cast<QQnxVideoSink *>(videoSink->platformVideoSink())
776 : nullptr;
777}
778
779void QQnxMediaPlayer::startMonitoring()
780{
781 m_eventThread = new QQnxMediaEventThread(m_context);
782
783 connect(m_eventThread, &QQnxMediaEventThread::eventPending,
784 this, &QQnxMediaPlayer::readEvents);
785
786 m_eventThread->setObjectName(QStringLiteral("MmrEventThread-") + QString::number(m_id));
787 m_eventThread->start();
788}
789
790void QQnxMediaPlayer::stopMonitoring()
791{
792 delete m_eventThread;
793 m_eventThread = nullptr;
794}
795
796void QQnxMediaPlayer::resetMonitoring()
797{
798 m_bufferLevel = 0;
799 m_position = 0;
800 m_speed = 0;
801}
802
803void QQnxMediaPlayer::handleMmPositionChanged(qint64 newPosition)
804{
805 m_position = newPosition;
806
807 if (state() == QMediaPlayer::PausedState)
808 m_windowGrabber->forceUpdate();
809
810 positionChanged(m_position);
811}
812
813void QQnxMediaPlayer::updateBufferLevel(int level, int capacity)
814{
815 m_bufferLevel = capacity == 0 ? 0 : level / static_cast<float>(capacity) * 100.0f;
816 m_bufferLevel = qBound(0, m_bufferLevel, 100);
817 bufferProgressChanged(m_bufferLevel/100.0f);
818}
819
820void QQnxMediaPlayer::updateMetaData(const strm_dict *dict)
821{
822 m_metaData.update(dict);
823
824 durationChanged(m_metaData.duration());
825 audioAvailableChanged(m_metaData.hasAudio());
826 videoAvailableChanged(m_metaData.hasVideo());
827 seekableChanged(m_metaData.isSeekable());
828}
829
830void QQnxMediaPlayer::emitMmError(const char *msg)
831{
832 emitMmError(QString::fromUtf8(msg));
833}
834
835void QQnxMediaPlayer::emitMmError(const QString &msg)
836{
837 int errorCode = MMR_ERROR_NONE;
838 const QString errorMessage = mmErrorMessage(msg, m_context, &errorCode);
839 emit error(errorCode, errorMessage);
840}
841
842void QQnxMediaPlayer::emitPError(const QString &msg)
843{
844 const QString errorMessage = QString::fromLatin1("%1: %2").arg(msg).arg(QString::fromUtf8(strerror(errno)));
845 emit error(errno, errorMessage);
846}
847
848
849void QQnxMediaPlayer::readEvents()
850{
851 while (const mmr_event_t *event = mmr_event_get(m_context)) {
852 if (event->type == MMR_EVENT_NONE)
853 break;
854
855 switch (event->type) {
856 case MMR_EVENT_STATUS:
857 handleMmEventStatus(event);
858 break;
859 case MMR_EVENT_STATE:
860 handleMmEventState(event);
861 break;
862 case MMR_EVENT_METADATA:
863 updateMetaData(event->data);
864 break;
865 case MMR_EVENT_ERROR:
866 handleMmEventError(event);
867 break;
868 case MMR_EVENT_NONE:
869 case MMR_EVENT_OVERFLOW:
870 case MMR_EVENT_WARNING:
871 case MMR_EVENT_PLAYLIST:
872 case MMR_EVENT_INPUT:
873 case MMR_EVENT_OUTPUT:
874 case MMR_EVENT_CTXTPAR:
875 case MMR_EVENT_TRKPAR:
876 case MMR_EVENT_OTHER:
877 break;
878 }
879 }
880
881 if (m_eventThread)
882 m_eventThread->signalRead();
883}
884
885QT_END_NAMESPACE
886
887#include "moc_qqnxmediaplayer_p.cpp"
QObject * parent
Definition qobject.h:73
void pause() override
const QIODevice * mediaStream() const override
bool isSeekable() const override
void setVideoSink(QVideoSink *videoSink)
void play() override
void setPlaybackRate(qreal rate) override
qint64 position() const override
QMediaTimeRange availablePlaybackRanges() const override
bool isAudioAvailable() const override
float bufferProgress() const override
void setPosition(qint64 position) override
qint64 duration() const override
void stop() override
qreal playbackRate() const override
QUrl media() const override
bool isVideoAvailable() const override
void setMedia(const QUrl &media, QIODevice *stream) override
MapData map(QVideoFrame::MapMode mode) override
Maps the planes of a video buffer to memory.
QnxRasterBuffer(QQnxWindowGrabber *windowGrabber)
void unmap() override
Releases the memory mapped by the map() function.
QVideoFrameFormat format() const override
Gets \l QVideoFrameFormat of the underlying video buffer.
quint64 textureHandle(QRhi *, int plane) const override
QnxTextureBuffer(QQnxWindowGrabber *QQnxWindowGrabber)
MapData map(QVideoFrame::MapMode) override
Maps the planes of a video buffer to memory.
void unmap() override
Releases the memory mapped by the map() function.
struct strm_dict strm_dict_t
static constexpr int normalizeVolume(float volume)
static std::tuple< int, int, bool > parseBufferLevel(const QString &value)
static constexpr qreal speedToRate(int speed)
static constexpr int rateToSpeed(qreal rate)