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);
}
Example #7
0
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);
            }
        }
    }
}
Example #8
0
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);
}
Example #12
0
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
    }
}