diff options
Diffstat (limited to 'src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm')
-rw-r--r-- | src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm | 161 |
1 files changed, 94 insertions, 67 deletions
diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm index 5ef1f9baf..53cdebd82 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm @@ -121,19 +121,28 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe - (void) unloadMedia { - if (m_player) - [m_player setRate:0.0]; if (m_playerItem) { [m_playerItem removeObserver:self forKeyPath:AVF_STATUS_KEY]; [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification - object:m_playerItem]; + object:m_playerItem]; [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemTimeJumpedNotification object:m_playerItem]; m_playerItem = 0; } + if (m_player) { + [m_player setRate:0.0]; + [m_player removeObserver:self forKeyPath:AVF_CURRENT_ITEM_KEY]; + [m_player removeObserver:self forKeyPath:AVF_RATE_KEY]; + [m_player release]; + m_player = 0; + } + if (m_playerLayer) { + [m_playerLayer release]; + m_playerLayer = 0; + } } - (void) prepareToPlayAsset:(AVURLAsset *)asset @@ -203,30 +212,15 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe name:AVPlayerItemTimeJumpedNotification object:m_playerItem]; - - //Clean up old player if we have one - if (m_player) { - [m_player setRate:0.0]; - [m_player removeObserver:self forKeyPath:AVF_CURRENT_ITEM_KEY]; - [m_player removeObserver:self forKeyPath:AVF_RATE_KEY]; - [m_player release]; - m_player = 0; - - if (m_playerLayer) { - [m_playerLayer release]; - m_playerLayer = 0; //Will have been released - } - } - //Get a new AVPlayer initialized to play the specified player item. m_player = [AVPlayer playerWithPlayerItem:m_playerItem]; [m_player retain]; -#if defined(Q_OS_OSX) //Set the initial volume on new player object - if (self.session) - m_player.volume = m_session->volume() / 100.0f; -#endif + if (self.session && self.session->isVolumeSupported()) { + [m_player setVolume:m_session->volume() / 100.0f]; + [m_player setMuted:m_session->isMuted()]; + } //Create a new player layer if we don't have one already if (!m_playerLayer) @@ -354,18 +348,6 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe #endif [self unloadMedia]; - if (m_player) { - [m_player removeObserver:self forKeyPath:AVF_CURRENT_ITEM_KEY]; - [m_player removeObserver:self forKeyPath:AVF_RATE_KEY]; - [m_player release]; - m_player = 0; - } - - if (m_playerLayer) { - [m_playerLayer release]; - m_playerLayer = 0; - } - if (m_URL) { [m_URL release]; } @@ -382,13 +364,20 @@ AVFMediaPlayerSession::AVFMediaPlayerSession(AVFMediaPlayerService *service, QOb , m_state(QMediaPlayer::StoppedState) , m_mediaStatus(QMediaPlayer::NoMedia) , m_mediaStream(0) +#ifdef Q_OS_IOS + , m_volumeSupported(QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0) +#else + , m_volumeSupported(true) +#endif , m_muted(false) , m_tryingAsync(false) , m_volume(100) , m_rate(1.0) + , m_requestedPosition(-1) , m_duration(0) , m_videoAvailable(false) , m_audioAvailable(false) + , m_seekable(false) { m_observer = [[AVFMediaPlayerSessionObserver alloc] initWithMediaPlayerSession:this]; } @@ -458,23 +447,26 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st qDebug() << Q_FUNC_INFO << content.canonicalUrl(); #endif + [(AVFMediaPlayerSessionObserver*)m_observer unloadMedia]; + m_resources = content; m_mediaStream = stream; setAudioAvailable(false); setVideoAvailable(false); + setSeekable(false); + m_requestedPosition = -1; + Q_EMIT positionChanged(position()); QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus; if (content.isNull() || content.canonicalUrl().isEmpty()) { - [(AVFMediaPlayerSessionObserver*)m_observer unloadMedia]; m_mediaStatus = QMediaPlayer::NoMedia; if (m_state != QMediaPlayer::StoppedState) Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState); if (m_mediaStatus != oldMediaStatus) Q_EMIT mediaStatusChanged(m_mediaStatus); - Q_EMIT positionChanged(position()); return; } else { @@ -482,6 +474,7 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st if (m_mediaStatus != oldMediaStatus) Q_EMIT mediaStatusChanged(m_mediaStatus); } + //Load AVURLAsset //initialize asset using content's URL NSString *urlString = [NSString stringWithUTF8String:content.canonicalUrl().toEncoded().constData()]; @@ -494,7 +487,7 @@ qint64 AVFMediaPlayerSession::position() const AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem]; if (!playerItem) - return 0; + return m_requestedPosition != -1 ? m_requestedPosition : 0; CMTime time = [playerItem currentTime]; return static_cast<quint64>(float(time.value) / float(time.timescale) * 1000.0f); @@ -563,7 +556,16 @@ bool AVFMediaPlayerSession::isVideoAvailable() const bool AVFMediaPlayerSession::isSeekable() const { - return true; + return m_seekable; +} + +void AVFMediaPlayerSession::setSeekable(bool seekable) +{ + if (m_seekable == seekable) + return; + + m_seekable = seekable; + Q_EMIT seekableChanged(seekable); } QMediaTimeRange AVFMediaPlayerSession::availablePlaybackRanges() const @@ -602,10 +604,10 @@ void AVFMediaPlayerSession::setPlaybackRate(qreal rate) m_rate = rate; AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player]; - - if (player != 0 && m_state == QMediaPlayer::PlayingState) { + if (player && m_state == QMediaPlayer::PlayingState) [player setRate:m_rate]; - } + + Q_EMIT playbackRateChanged(m_rate); } void AVFMediaPlayerSession::setPosition(qint64 pos) @@ -614,14 +616,23 @@ void AVFMediaPlayerSession::setPosition(qint64 pos) qDebug() << Q_FUNC_INFO << pos; #endif - if ( !isSeekable() || pos == position()) + if (pos == position()) return; AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem]; - - if (!playerItem) + if (!playerItem) { + m_requestedPosition = pos; + Q_EMIT positionChanged(m_requestedPosition); return; + } else if (!isSeekable()) { + if (m_requestedPosition != -1) { + m_requestedPosition = -1; + Q_EMIT positionChanged(position()); + } + return; + } + pos = qMax(qint64(0), pos); if (duration() > 0) pos = qMin(pos, duration()); @@ -655,8 +666,10 @@ void AVFMediaPlayerSession::play() processLoadStateChange(); } - if (m_mediaStatus == QMediaPlayer::LoadedMedia || m_mediaStatus == QMediaPlayer::BufferedMedia) - [[(AVFMediaPlayerSessionObserver*)m_observer player] play]; + if (m_mediaStatus == QMediaPlayer::LoadedMedia || m_mediaStatus == QMediaPlayer::BufferedMedia) { + // Setting the rate starts playback + [[(AVFMediaPlayerSessionObserver*)m_observer player] setRate:m_rate]; + } //processLoadStateChange(); Q_EMIT stateChanged(m_state); @@ -697,8 +710,8 @@ void AVFMediaPlayerSession::stop() return; m_state = QMediaPlayer::StoppedState; - m_rate = 0.0f; - [[(AVFMediaPlayerSessionObserver*)m_observer player] setRate:m_rate]; + // AVPlayer doesn't have stop(), only pause() and play(). + [[(AVFMediaPlayerSessionObserver*)m_observer player] pause]; setPosition(0); if (m_videoOutput) { @@ -716,21 +729,20 @@ void AVFMediaPlayerSession::setVolume(int volume) qDebug() << Q_FUNC_INFO << volume; #endif - if (m_volume == volume) - return; - - AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player]; - if (!player) - return; - - if (![player respondsToSelector:@selector(setVolume:)]) { + if (!m_volumeSupported) { qWarning("%s not implemented, requires iOS 7 or later", Q_FUNC_INFO); return; } - [player setVolume:volume / 100.0f]; + if (m_volume == volume) + return; + m_volume = volume; + AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player]; + if (player) + [player setVolume:volume / 100.0f]; + Q_EMIT volumeChanged(m_volume); } @@ -739,22 +751,21 @@ void AVFMediaPlayerSession::setMuted(bool muted) #ifdef QT_DEBUG_AVF qDebug() << Q_FUNC_INFO << muted; #endif - if (m_muted == muted) - return; - AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player]; - if (!player) - return; - - // iOS: setMuted exists since iOS 7.0, thus check if it exists - if (![player respondsToSelector:@selector(setMuted:)]) { + if (!m_volumeSupported) { qWarning("%s not implemented, requires iOS 7 or later", Q_FUNC_INFO); return; } - [player setMuted:muted]; + if (m_muted == muted) + return; + m_muted = muted; + AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player]; + if (player) + [player setMuted:muted]; + Q_EMIT mutedChanged(muted); } @@ -767,6 +778,11 @@ void AVFMediaPlayerSession::processEOS() Q_EMIT positionChanged(position()); m_mediaStatus = QMediaPlayer::EndOfMedia; + // At this point, frames should not be rendered anymore. + // Clear the output layer to make sure of that. + if (m_videoOutput) + m_videoOutput->setLayer(0); + Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState); Q_EMIT mediaStatusChanged(m_mediaStatus); } @@ -801,6 +817,8 @@ void AVFMediaPlayerSession::processLoadStateChange() } } + setSeekable([[playerItem seekableTimeRanges] count] > 0); + // Get the native size of the video, and reset the bounds of the player layer AVPlayerLayer *playerLayer = [(AVFMediaPlayerSessionObserver*)m_observer playerLayer]; if (videoTrack && playerLayer) { @@ -818,11 +836,16 @@ void AVFMediaPlayerSession::processLoadStateChange() if (m_duration != currentDuration) Q_EMIT durationChanged(m_duration = currentDuration); + if (m_requestedPosition != -1) { + setPosition(m_requestedPosition); + m_requestedPosition = -1; + } + newStatus = isPlaying ? QMediaPlayer::BufferedMedia : QMediaPlayer::LoadedMedia; if (m_state == QMediaPlayer::PlayingState && [(AVFMediaPlayerSessionObserver*)m_observer player]) { + // Setting the rate is enough to start playback, no need to call play() [[(AVFMediaPlayerSessionObserver*)m_observer player] setRate:m_rate]; - [[(AVFMediaPlayerSessionObserver*)m_observer player] play]; } } @@ -837,6 +860,10 @@ void AVFMediaPlayerSession::processPositionChange() void AVFMediaPlayerSession::processMediaLoadError() { + if (m_requestedPosition != -1) { + m_requestedPosition = -1; + Q_EMIT positionChanged(position()); + } Q_EMIT error(QMediaPlayer::FormatError, tr("Failed to load media")); Q_EMIT mediaStatusChanged(m_mediaStatus = QMediaPlayer::InvalidMedia); Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState); |