void QAndroidMediaPlayerControl::onMediaPlayerInfo(qint32 what, qint32 extra) { switch (what) { case JMediaPlayer::MEDIA_PLAYER_INVALID_STATE: setError(what, QStringLiteral("Error: Invalid state")); break; case JMediaPlayer::MEDIA_PLAYER_PREPARING: setMediaStatus(QMediaPlayer::LoadingMedia); setState(QMediaPlayer::StoppedState); break; case JMediaPlayer::MEDIA_PLAYER_READY: setMediaStatus(QMediaPlayer::LoadedMedia); if (mBuffering) { setMediaStatus(mBufferPercent == 100 ? QMediaPlayer::BufferedMedia : QMediaPlayer::BufferingMedia); } else { onBufferChanged(100); } setAudioAvailable(true); mMediaPlayerReady = true; flushPendingStates(); break; case JMediaPlayer::MEDIA_PLAYER_DURATION: Q_EMIT durationChanged(extra); break; case JMediaPlayer::MEDIA_PLAYER_PROGRESS: Q_EMIT positionChanged(extra); break; case JMediaPlayer::MEDIA_PLAYER_FINISHED: stop(); setMediaStatus(QMediaPlayer::EndOfMedia); break; } }
void QAndroidMediaPlayerControl::onInfo(qint32 what, qint32 extra) { Q_UNUSED(extra); switch (what) { case JMediaPlayer::MEDIA_INFO_UNKNOWN: break; case JMediaPlayer::MEDIA_INFO_VIDEO_TRACK_LAGGING: // IGNORE break; case JMediaPlayer::MEDIA_INFO_VIDEO_RENDERING_START: break; case JMediaPlayer::MEDIA_INFO_BUFFERING_START: mPendingState = mCurrentState; setState(QMediaPlayer::PausedState); setMediaStatus(QMediaPlayer::StalledMedia); break; case JMediaPlayer::MEDIA_INFO_BUFFERING_END: setMediaStatus(mBufferPercent == 100 ? QMediaPlayer::BufferedMedia : QMediaPlayer::BufferingMedia); flushPendingStates(); break; case JMediaPlayer::MEDIA_INFO_BAD_INTERLEAVING: break; case JMediaPlayer::MEDIA_INFO_NOT_SEEKABLE: setSeekable(false); break; case JMediaPlayer::MEDIA_INFO_METADATA_UPDATE: Q_EMIT metaDataUpdated(); break; } }
void MmRendererMediaPlayerControl::setMmBufferStatus(const QString &bufferStatus) { if (bufferStatus == QLatin1String("buffering")) setMediaStatus(QMediaPlayer::BufferingMedia); else if (bufferStatus == QLatin1String("playing")) setMediaStatus(QMediaPlayer::BufferedMedia); // ignore "idle" buffer status }
void MmRendererMediaPlayerControl::attach() { // Should only be called in detached state Q_ASSERT(m_audioId == -1 && !m_inputAttached); if (m_media.isNull() || !m_context) { setMediaStatus(QMediaPlayer::NoMedia); return; } if (m_videoRendererControl) m_videoRendererControl->attachDisplay(m_context); if (m_videoWindowControl) m_videoWindowControl->attachDisplay(m_context); const QByteArray defaultAudioDevice = qgetenv("QQNX_RENDERER_DEFAULT_AUDIO_SINK"); m_audioId = mmr_output_attach(m_context, defaultAudioDevice.isEmpty() ? "audio:default" : defaultAudioDevice.constData(), "audio"); if (m_audioId == -1) { emitMmError("mmr_output_attach() for audio failed"); return; } const QByteArray resourcePath = resourcePathForUrl(m_media.canonicalUrl()); if (resourcePath.isEmpty()) { detach(); return; } if (mmr_input_attach(m_context, resourcePath.constData(), "track") != 0) { emitMmError(QStringLiteral("mmr_input_attach() failed for ") + QString(resourcePath)); setMediaStatus(QMediaPlayer::InvalidMedia); detach(); return; } // For whatever reason, the mmrenderer sends out a MMR_STOPPED event when calling // mmr_input_attach() above. Ignore it, as otherwise we'll trigger stopping right after we // started. m_stopEventsToIgnore++; m_inputAttached = true; setMediaStatus(QMediaPlayer::LoadedMedia); // mm-renderer has buffer properties "status" and "level" // QMediaPlayer's buffer status maps to mm-renderer's buffer level m_bufferLevel = 0; emit bufferStatusChanged(m_bufferLevel); }
void QAndroidMediaPlayerControl::onError(qint32 what, qint32 extra) { QString errorString; QMediaPlayer::Error error = QMediaPlayer::ResourceError; switch (what) { case JMediaPlayer::MEDIA_ERROR_UNKNOWN: errorString = QLatin1String("Error:"); break; case JMediaPlayer::MEDIA_ERROR_SERVER_DIED: errorString = QLatin1String("Error: Server died"); error = QMediaPlayer::ServiceMissingError; break; } switch (extra) { case JMediaPlayer::MEDIA_ERROR_IO: // Network OR file error errorString += QLatin1String(" (I/O operation failed)"); error = QMediaPlayer::NetworkError; setMediaStatus(QMediaPlayer::InvalidMedia); break; case JMediaPlayer::MEDIA_ERROR_MALFORMED: errorString += QLatin1String(" (Malformed bitstream)"); error = QMediaPlayer::FormatError; setMediaStatus(QMediaPlayer::InvalidMedia); break; case JMediaPlayer::MEDIA_ERROR_UNSUPPORTED: errorString += QLatin1String(" (Unsupported media)"); error = QMediaPlayer::FormatError; setMediaStatus(QMediaPlayer::InvalidMedia); break; case JMediaPlayer::MEDIA_ERROR_TIMED_OUT: errorString += QLatin1String(" (Timed out)"); break; case JMediaPlayer::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK: errorString += QLatin1String(" (Unable to start progressive playback')"); error = QMediaPlayer::FormatError; setMediaStatus(QMediaPlayer::InvalidMedia); break; } setError(error, errorString); }
void QAndroidMediaPlayerControl::onBufferChanged(qint32 percent) { mBuffering = percent != 100; mBufferPercent = percent; Q_EMIT bufferStatusChanged(mBufferPercent); updateAvailablePlaybackRanges(); if (mBufferPercent == 100) setMediaStatus(QMediaPlayer::BufferedMedia); }
void BbMediaPlayerControl::bpsEventHandler(bps_event_t *event) { if (m_videoControl) m_videoControl->bpsEventHandler(event); if (bps_event_get_domain(event) != mmrenderer_get_domain()) return; if (bps_event_get_code(event) == MMRENDERER_STATE_CHANGE) { const mmrenderer_state_t newState = mmrenderer_event_get_state(event); if (newState == MMR_STOPPED) { // Only react to stop events that happen when the end of the stream is reached and // playback is stopped because of this. // Ignore other stop event sources, souch as calling mmr_stop() ourselves and // mmr_input_attach(). if (m_stopEventsToIgnore > 0) { --m_stopEventsToIgnore; } else { setMediaStatus(QMediaPlayer::EndOfMedia); stopInternal(IgnoreMmRenderer); } return; } } if (bps_event_get_code(event) == MMRENDERER_STATUS_UPDATE) { // Prevent spurious position change events from overriding our own position, for example // when setting the position to 0 in stop(). if (m_state != QMediaPlayer::PlayingState || m_mediaStatus == QMediaPlayer::LoadingMedia || m_mediaStatus == QMediaPlayer::NoMedia || m_mediaStatus == QMediaPlayer::InvalidMedia) return; const qint64 newPosition = QString::fromAscii(mmrenderer_event_get_position(event)).toLongLong(); if (newPosition != 0 && newPosition != m_position) { m_position = newPosition; emit positionChanged(m_position); } const QString bufferStatus = QString::fromAscii(mmrenderer_event_get_bufferlevel(event)); const int slashPos = bufferStatus.indexOf('/'); if (slashPos != -1) { const int fill = bufferStatus.left(slashPos).toInt(); const int capacity = bufferStatus.mid(slashPos + 1).toInt(); if (capacity != 0) { m_bufferStatus = fill / static_cast<float>(capacity) * 100.0f; emit bufferStatusChanged(m_bufferStatus); } } } }
void BbMediaPlayerControl::attach() { if (m_media.isNull() || !m_context) { setMediaStatus(QMediaPlayer::NoMedia); return; } if (m_videoControl) m_videoControl->attachDisplay(m_context); m_audioId = mmr_output_attach(m_context, "audio:default", "audio"); if (m_audioId == -1) { emitMmError("mmr_output_attach() for audio failed"); return; } const QString resourcePath = resourcePathForUrl(m_media.canonicalUrl()); if (resourcePath.isEmpty()) { detach(); return; } if (mmr_input_attach(m_context, QFile::encodeName(resourcePath), "track") != 0) { emitMmError(QString("mmr_input_attach() for %1 failed").arg(resourcePath)); setMediaStatus(QMediaPlayer::InvalidMedia); detach(); return; } // For whatever reason, the mmrenderer sends out a MMR_STOPPED event when calling // mmr_input_attach() above. Ignore it, as otherwise we'll trigger stopping right after we // started. m_stopEventsToIgnore++; m_inputAttached = true; setMediaStatus(QMediaPlayer::LoadedMedia); m_bufferStatus = 0; emit bufferStatusChanged(m_bufferStatus); }
void MmRendererMediaPlayerControl::handleMmStopped() { // Only react to stop events that happen when the end of the stream is reached and // playback is stopped because of this. // Ignore other stop event sources, souch as calling mmr_stop() ourselves and // mmr_input_attach(). if (m_stopEventsToIgnore > 0) { --m_stopEventsToIgnore; } else { setMediaStatus(QMediaPlayer::EndOfMedia); stopInternal(IgnoreMmRenderer); } }
void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent, QIODevice *stream) { mMediaContent = mediaContent; mMediaStream = stream; const QString uri = mediaContent.canonicalUrl().toString(); if (!uri.isEmpty()) mMediaPlayer->setDataSource(uri); else setMediaStatus(QMediaPlayer::NoMedia); Q_EMIT mediaChanged(mMediaContent); resetBufferingProgress(); // reset some properties setAudioAvailable(false); setVideoAvailable(false); setSeekable(true); }
void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent, QIODevice *stream) { mMediaContent = mediaContent; mMediaStream = stream; if (mVideoOutput && !mMediaPlayer->display()) { // if a video output is set but the video texture is not ready, delay loading the media // since it can cause problems on some hardware mPendingSetMedia = true; return; } const QUrl url = mediaContent.canonicalUrl(); QString mediaPath; if (url.scheme() == QLatin1String("qrc")) { const QString path = url.toString().mid(3); mTempFile.reset(QTemporaryFile::createNativeFile(path)); if (!mTempFile.isNull()) mediaPath = QLatin1String("file://") + mTempFile->fileName(); } else { mediaPath = url.toString(); } if (!mediaPath.isEmpty()) mMediaPlayer->setDataSource(mediaPath); else setMediaStatus(QMediaPlayer::NoMedia); Q_EMIT mediaChanged(mMediaContent); resetBufferingProgress(); // reset some properties setAudioAvailable(false); setVideoAvailable(false); setSeekable(true); }
void BbMediaPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream) { Q_UNUSED(stream); // not supported stop(); detach(); m_media = media; emit mediaChanged(m_media); // Slight hack: With MediaPlayer QtQuick elements that have autoPlay set to true, playback // would start before the QtQuick canvas is propagated to all elements, and therefore our // video output would not work. Therefore, delay actually playing the media a bit so that the // canvas is ready. // The mmrenderer doesn't allow to attach video outputs after playing has started, otherwise // this would be unnecessary. if (!m_media.isNull()) { setMediaStatus(QMediaPlayer::LoadingMedia); m_loadingTimer.start(); // singleshot timer to continueLoadMedia() } else { continueLoadMedia(); // still needed, as it will update the media status and clear metadata } }