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:
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) override
84 {
85 if (plane != 0)
86 return 0;
87 if (!m_handle)
88 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().constData(),
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().constData(), "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 // QNX 8.0+ serves audio through io-snd (ALSA/SALSA), reached as
411 // "alsa:default"; older releases use the QSA "snd:" device.
412 const char *fallbackDevice =
413#if __QNX__ >= 800
414 "alsa:default";
415#else
416 "snd:";
417#endif
418
419 m_audioId = mmr_output_attach(m_context,
420 defaultAudioDevice.isEmpty() ? fallbackDevice : defaultAudioDevice.constData(), "audio");
421
422 if (m_audioId == -1) {
423 emitMmError("mmr_output_attach() for audio failed");
424
425 return false;
426 }
427
428 return true;
429}
430
431bool QQnxMediaPlayer::attachInput()
432{
433 if (isInputAttached())
434 return true;
435
436 const QByteArray resourcePath = resourcePathForUrl(m_media);
437
438 if (resourcePath.isEmpty())
439 return false;
440
441 if (mmr_input_attach(m_context, resourcePath.constData(), "track") != 0) {
442 emitMmError(QStringLiteral("mmr_input_attach() failed for ")
443 + QString::fromUtf8(resourcePath));
444
445 mediaStatusChanged(QMediaPlayer::InvalidMedia);
446
447 return false;
448 }
449
450 m_inputAttached = true;
451
452 return true;
453}
454
455void QQnxMediaPlayer::detach()
456{
457 if (!m_context)
458 return;
459
460 if (isVideoOutputAttached())
461 detachVideoOutput();
462
463 if (isAudioOutputAttached())
464 detachAudioOutput();
465
466 if (isInputAttached())
467 detachInput();
468
469 resetMonitoring();
470}
471
472void QQnxMediaPlayer::detachVideoOutput()
473{
474 m_windowGrabber->stop();
475
476 if (m_platformVideoSink)
477 m_platformVideoSink->setVideoFrame({});
478
479 if (isVideoOutputAttached())
480 mmr_output_detach(m_context, m_videoId);
481
482 m_videoId = -1;
483}
484
485void QQnxMediaPlayer::detachAudioOutput()
486{
487 if (isAudioOutputAttached())
488 mmr_output_detach(m_context, m_audioId);
489
490 m_audioId = -1;
491}
492
493void QQnxMediaPlayer::detachInput()
494{
495 if (isInputAttached())
496 mmr_input_detach(m_context);
497
498 m_inputAttached = false;
499}
500
501bool QQnxMediaPlayer::isVideoOutputAttached() const
502{
503 return m_videoId != -1;
504}
505
506bool QQnxMediaPlayer::isAudioOutputAttached() const
507{
508 return m_audioId != -1;
509}
510
511bool QQnxMediaPlayer::isInputAttached() const
512{
513 return m_inputAttached;
514}
515
516void QQnxMediaPlayer::updateScene(const QSize &size)
517{
518 if (!m_platformVideoSink)
519 return;
520
521 QVideoFrameFormat format(size, QVideoFrameFormat::Format_BGRX8888);
522
523 const QVideoFrame actualFrame = m_windowGrabber->isEglImageSupported()
524 ? QVideoFramePrivate::createFrame(std::make_unique<QnxTextureBuffer>(m_windowGrabber),
525 std::move(format))
526 : QVideoFramePrivate::createFrame(std::make_unique<QnxRasterBuffer>(m_windowGrabber),
527 std::move(format));
528
529 m_platformVideoSink->setVideoFrame(actualFrame);
530}
531
533{
534 return m_metaData.duration();
535}
536
538{
539 return m_position;
540}
541
542void QQnxMediaPlayer::setPosition(qint64 position)
543{
544 if (m_position == position)
545 return;
546
547 m_pendingPosition = position;
548 m_flushPositionTimer.start();
549}
550
551void QQnxMediaPlayer::setPositionInternal(qint64 position)
552{
553 if (!m_context || !m_metaData.isSeekable() || mediaStatus() == QMediaPlayer::NoMedia)
554 return;
555
556 if (mmr_seek(m_context, QString::number(position).toLatin1().constData()) != 0)
557 emitMmError("Seeking failed");
558}
559
560void QQnxMediaPlayer::flushPosition()
561{
562 setPositionInternal(m_pendingPosition);
563}
564
565bool QQnxMediaPlayer::isPendingPositionFlush() const
566{
567 return m_flushPositionTimer.isActive();
568}
569
570void QQnxMediaPlayer::setDeferredSpeedEnabled(bool enabled)
571{
572 m_deferredSpeedEnabled = enabled;
573}
574
575bool QQnxMediaPlayer::isDeferredSpeedEnabled() const
576{
577 return m_deferredSpeedEnabled;
578}
579
580void QQnxMediaPlayer::setVolume(float volume)
581{
582 const int normalizedVolume = ::normalizeVolume(volume);
583
584 if (m_volume == normalizedVolume)
585 return;
586
587 m_volume = normalizedVolume;
588
589 if (!m_muted)
590 updateVolume();
591}
592
593void QQnxMediaPlayer::setMuted(bool muted)
594{
595 if (m_muted == muted)
596 return;
597
598 m_muted = muted;
599
600 updateVolume();
601}
602
603void QQnxMediaPlayer::updateVolume()
604{
605 if (!m_context || m_audioId == -1)
606 return;
607
608 const int volume = m_muted ? 0 : m_volume;
609
610 char buf[] = "100";
611 std::snprintf(buf, sizeof buf, "%d", volume);
612
613 strm_dict_t * dict = strm_dict_new();
614 dict = strm_dict_set(dict, "volume", buf);
615
616 if (mmr_output_parameters(m_context, m_audioId, dict) != 0)
617 emitMmError("mmr_output_parameters: Setting volume failed");
618}
619
620void QQnxMediaPlayer::setAudioOutput(QPlatformAudioOutput *output)
621{
622 QAudioOutput *out = output ? output->q : nullptr;
623 if (m_audioOutput == out)
624 return;
625
626 if (m_audioOutput)
627 disconnect(m_audioOutput.get());
628 m_audioOutput = out;
629 if (m_audioOutput) {
630 connect(out, &QAudioOutput::volumeChanged, this, &QQnxMediaPlayer::setVolume);
631 connect(out, &QAudioOutput::mutedChanged, this, &QQnxMediaPlayer::setMuted);
632 }
633 setVolume(out ? out->volume() : 1.);
634 setMuted(out ? out->isMuted() : true);
635}
636
638{
639 // mm-renderer has buffer properties "status" and "level"
640 // QMediaPlayer's buffer status maps to mm-renderer's buffer level
641 return m_bufferLevel/100.0f;
642}
643
645{
646 return m_metaData.hasAudio();
647}
648
650{
651 return m_metaData.hasVideo();
652}
653
655{
656 return m_metaData.isSeekable();
657}
658
660{
661 // We can't get this information from the mmrenderer API yet, so pretend we can seek everywhere
662 return QMediaTimeRange(0, m_metaData.duration());
663}
664
666{
667 return ::speedToRate(m_speed);
668}
669
671{
672 if (!m_context)
673 return;
674
675 const int speed = ::rateToSpeed(rate);
676
677 if (m_speed == speed)
678 return;
679
680 // defer setting the playback speed for when play() is called to prevent
681 // mm-renderer from inadvertently transitioning into play state
682 if (isDeferredSpeedEnabled() && state() != QMediaPlayer::PlayingState) {
683 m_deferredSpeed = speed;
684 return;
685 }
686
687 if (mmr_speed_set(m_context, speed) != 0)
688 emitMmError("mmr_speed_set failed");
689}
690
692{
693 return m_media;
694}
695
697{
698 // Always 0, we don't support QIODevice streams
699 return 0;
700}
701
702void QQnxMediaPlayer::setMedia(const QUrl &media, QIODevice *stream)
703{
704 Q_UNUSED(stream); // not supported
705
706 stop();
707 detach();
708
709 stateChanged(QMediaPlayer::StoppedState);
710 mediaStatusChanged(QMediaPlayer::LoadingMedia);
711
712 m_media = media;
713
714 updateMetaData(nullptr);
715 attach();
716}
717
719{
720 if (!m_media.isValid() || !m_connection || !m_context || m_audioId == -1) {
721 stateChanged(QMediaPlayer::StoppedState);
722 return;
723 }
724
725 if (state() == QMediaPlayer::PlayingState)
726 return;
727
728 setDeferredSpeedEnabled(false);
729
730 if (m_deferredSpeed) {
731 setPlaybackRate(::speedToRate(*m_deferredSpeed));
732 m_deferredSpeed = {};
733 } else {
734 setPlaybackRate(::speedToRate(m_configuredSpeed));
735 }
736
737 setDeferredSpeedEnabled(true);
738
739 // Un-pause the state when it is paused
740 if (state() == QMediaPlayer::PausedState) {
741 return;
742 }
743
744
745 if (mediaStatus() == QMediaPlayer::EndOfMedia)
746 setPositionInternal(0);
747
748 resetMonitoring();
749 updateVolume();
750
751 if (mmr_play(m_context) != 0) {
752 stateChanged(QMediaPlayer::StoppedState);
753 emitMmError("mmr_play() failed");
754 return;
755 }
756
757 stateChanged(QMediaPlayer::PlayingState);
758}
759
761{
762 if (state() != QMediaPlayer::PlayingState)
763 return;
764
765 setPlaybackRate(0);
766}
767
769{
770 if (!m_context
771 || state() == QMediaPlayer::StoppedState
772 || mediaStatus() == QMediaPlayer::NoMedia)
773 return;
774
775 // mm-renderer does not rewind by default
776 setPositionInternal(0);
777
778 mmr_stop(m_context);
779}
780
781void QQnxMediaPlayer::setVideoSink(QVideoSink *videoSink)
782{
783 m_platformVideoSink = videoSink
784 ? static_cast<QQnxVideoSink *>(videoSink->platformVideoSink())
785 : nullptr;
786}
787
788void QQnxMediaPlayer::startMonitoring()
789{
790 m_eventThread = new QQnxMediaEventThread(m_context);
791
792 connect(m_eventThread, &QQnxMediaEventThread::eventPending,
793 this, &QQnxMediaPlayer::readEvents);
794
795 m_eventThread->setObjectName(QStringLiteral("MmrEventThread-") + QString::number(m_id));
796 m_eventThread->start();
797}
798
799void QQnxMediaPlayer::stopMonitoring()
800{
801 delete m_eventThread;
802 m_eventThread = nullptr;
803}
804
805void QQnxMediaPlayer::resetMonitoring()
806{
807 m_bufferLevel = 0;
808 m_position = 0;
809 m_speed = 0;
810}
811
812void QQnxMediaPlayer::handleMmPositionChanged(qint64 newPosition)
813{
814 m_position = newPosition;
815
816 if (state() == QMediaPlayer::PausedState)
817 m_windowGrabber->forceUpdate();
818
819 positionChanged(m_position);
820}
821
822void QQnxMediaPlayer::updateBufferLevel(int level, int capacity)
823{
824 m_bufferLevel = capacity == 0 ? 0 : level / static_cast<float>(capacity) * 100.0f;
825 m_bufferLevel = qBound(0, m_bufferLevel, 100);
826 bufferProgressChanged(m_bufferLevel/100.0f);
827}
828
829void QQnxMediaPlayer::updateMetaData(const strm_dict *dict)
830{
831 m_metaData.update(dict);
832
833 durationChanged(m_metaData.duration());
834 audioAvailableChanged(m_metaData.hasAudio());
835 videoAvailableChanged(m_metaData.hasVideo());
836 seekableChanged(m_metaData.isSeekable());
837}
838
839void QQnxMediaPlayer::emitMmError(const char *msg)
840{
841 emitMmError(QString::fromUtf8(msg));
842}
843
844void QQnxMediaPlayer::emitMmError(const QString &msg)
845{
846 int errorCode = MMR_ERROR_NONE;
847 const QString errorMessage = mmErrorMessage(msg, m_context, &errorCode);
848 emit error(QMediaPlayer::ResourceError, errorMessage);
849}
850
851void QQnxMediaPlayer::emitPError(const QString &msg)
852{
853 const QString errorMessage = QString::fromLatin1("%1: %2").arg(msg).arg(QString::fromUtf8(strerror(errno)));
854 emit error(QMediaPlayer::ResourceError, errorMessage);
855}
856
857
858void QQnxMediaPlayer::readEvents()
859{
860 while (const mmr_event_t *event = mmr_event_get(m_context)) {
861 if (event->type == MMR_EVENT_NONE)
862 break;
863
864 switch (event->type) {
865 case MMR_EVENT_STATUS:
866 handleMmEventStatus(event);
867 break;
868 case MMR_EVENT_STATE:
869 handleMmEventState(event);
870 break;
871 case MMR_EVENT_METADATA:
872 updateMetaData(event->data);
873 break;
874 case MMR_EVENT_ERROR:
875 handleMmEventError(event);
876 break;
877 case MMR_EVENT_NONE:
878 case MMR_EVENT_OVERFLOW:
879 case MMR_EVENT_WARNING:
880 case MMR_EVENT_PLAYLIST:
881 case MMR_EVENT_INPUT:
882 case MMR_EVENT_OUTPUT:
883 case MMR_EVENT_CTXTPAR:
884 case MMR_EVENT_TRKPAR:
885 case MMR_EVENT_OTHER:
886 break;
887 }
888 }
889
890 if (m_eventThread)
891 m_eventThread->signalRead();
892}
893
894QT_END_NAMESPACE
895
896#include "moc_qqnxmediaplayer_p.cpp"
QObject * parent
Definition qobject.h:74
void pause() override
const QIODevice * mediaStream() const override
bool isSeekable() const override
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)