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