summaryrefslogtreecommitdiffstats
path: root/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm')
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm161
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);