summaryrefslogtreecommitdiffstats
path: root/src/plugins/avfoundation/mediaplayer
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-03-18 11:54:53 +0100
committerQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-03-18 11:54:53 +0100
commit432e929e644097b25060f85b1e089f2943577bc9 (patch)
tree9a0cf5abcc77b85ee7aa88f875cb5dc097ab667c /src/plugins/avfoundation/mediaplayer
parent4ad0484b825524bcbb74145ac4e63bdd6274ce6a (diff)
parent69837e6e04ae125186a8deaac59d82607fcd6d1a (diff)
Merge remote-tracking branch 'origin/5.15' into dev
Diffstat (limited to 'src/plugins/avfoundation/mediaplayer')
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h6
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm125
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfvideowidget.mm17
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm9
4 files changed, 130 insertions, 27 deletions
diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h
index 7a268a3d9..db29e88aa 100644
--- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h
+++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h
@@ -67,7 +67,7 @@ public:
QMediaPlayer::MediaStatus mediaStatus() const;
QMediaContent media() const;
- const QIODevice *mediaStream() const;
+ QIODevice *mediaStream() const;
void setMedia(const QMediaContent &content, QIODevice *stream);
qint64 position() const;
@@ -110,6 +110,9 @@ public Q_SLOTS:
void processDurationChange(qint64 duration);
+ void streamReady();
+ void streamDestroyed();
+
Q_SIGNALS:
void positionChanged(qint64 position);
void durationChanged(qint64 duration);
@@ -128,6 +131,7 @@ private:
void setAudioAvailable(bool available);
void setVideoAvailable(bool available);
void setSeekable(bool seekable);
+ void resetStream(QIODevice *stream = nullptr);
AVFMediaPlayerService *m_service;
AVFVideoOutput *m_videoOutput;
diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm
index 3e3736183..424f30008 100644
--- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm
+++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm
@@ -42,6 +42,7 @@
#include "avfvideooutput.h"
#include <qpointer.h>
+#include <QFileInfo>
#import <AVFoundation/AVFoundation.h>
@@ -66,7 +67,7 @@ static void *AVFMediaPlayerSessionObserverBufferLikelyToKeepUpContext = &AVFMedi
static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMediaPlayerSessionObserverCurrentItemObservationContext;
static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext = &AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext;
-@interface AVFMediaPlayerSessionObserver : NSObject
+@interface AVFMediaPlayerSessionObserver : NSObject<AVAssetResourceLoaderDelegate>
@property (readonly, getter=player) AVPlayer* m_player;
@property (readonly, getter=playerItem) AVPlayerItem* m_playerItem;
@@ -74,7 +75,7 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
@property (readonly, getter=session) AVFMediaPlayerSession* m_session;
- (AVFMediaPlayerSessionObserver *) initWithMediaPlayerSession:(AVFMediaPlayerSession *)session;
-- (void) setURL:(NSURL *)url;
+- (void) setURL:(NSURL *)url mimeType:(NSString *)mimeType;
- (void) unloadMedia;
- (void) prepareToPlayAsset:(AVURLAsset *)asset withKeys:(NSArray *)requestedKeys;
- (void) assetFailedToPrepareForPlayback:(NSError *)error;
@@ -84,6 +85,7 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
change:(NSDictionary *)change context:(void *)context;
- (void) detatchSession;
- (void) dealloc;
+- (BOOL) resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest;
@end
@implementation AVFMediaPlayerSessionObserver
@@ -95,6 +97,8 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
AVPlayerLayer *m_playerLayer;
NSURL *m_URL;
BOOL m_bufferIsLikelyToKeepUp;
+ NSData *m_data;
+ NSString *m_mimeType;
}
@synthesize m_player, m_playerItem, m_playerLayer, m_session;
@@ -109,8 +113,11 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
return self;
}
-- (void) setURL:(NSURL *)url
+- (void) setURL:(NSURL *)url mimeType:(NSString *)mimeType
{
+ [m_mimeType release];
+ m_mimeType = [mimeType retain];
+
if (m_URL != url)
{
[m_URL release];
@@ -122,6 +129,8 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
// use __block to avoid maintaining strong references on variables captured by the
// following block callback
__block AVURLAsset *asset = [[AVURLAsset URLAssetWithURL:m_URL options:nil] retain];
+ [asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
+
__block NSArray *requestedKeys = [[NSArray arrayWithObjects:AVF_TRACKS_KEY, AVF_PLAYABLE_KEY, nil] retain];
__block AVFMediaPlayerSessionObserver *blockSelf = self;
@@ -403,9 +412,48 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
[m_URL release];
}
+ [m_mimeType release];
[super dealloc];
}
+- (BOOL) resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
+{
+ Q_UNUSED(resourceLoader);
+
+ if (![loadingRequest.request.URL.scheme isEqualToString:@"iodevice"])
+ return NO;
+
+ QIODevice *device = m_session->mediaStream();
+ if (!device)
+ return NO;
+
+ device->seek(loadingRequest.dataRequest.requestedOffset);
+ if (loadingRequest.contentInformationRequest) {
+ loadingRequest.contentInformationRequest.contentType = m_mimeType;
+ loadingRequest.contentInformationRequest.contentLength = device->size();
+ loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES;
+ }
+
+ if (loadingRequest.dataRequest) {
+ NSInteger requestedLength = loadingRequest.dataRequest.requestedLength;
+ int maxBytes = qMin(32 * 1064, int(requestedLength));
+ char buffer[maxBytes];
+ NSInteger submitted = 0;
+ while (submitted < requestedLength) {
+ qint64 len = device->read(buffer, maxBytes);
+ if (len < 1)
+ break;
+
+ [loadingRequest.dataRequest respondWithData:[NSData dataWithBytes:buffer length:len]];
+ submitted += len;
+ }
+
+ // Finish loading even if not all bytes submitted.
+ [loadingRequest finishLoading];
+ }
+
+ return YES;
+}
@end
AVFMediaPlayerSession::AVFMediaPlayerSession(AVFMediaPlayerService *service, QObject *parent)
@@ -483,11 +531,23 @@ QMediaContent AVFMediaPlayerSession::media() const
return m_resources;
}
-const QIODevice *AVFMediaPlayerSession::mediaStream() const
+QIODevice *AVFMediaPlayerSession::mediaStream() const
{
return m_mediaStream;
}
+static void setURL(void *observer, const QString &url, const QString &mimeType = QString())
+{
+ NSString *urlString = [NSString stringWithUTF8String:url.toUtf8().constData()];
+ NSURL *nsurl = [NSURL URLWithString:urlString];
+ [static_cast<AVFMediaPlayerSessionObserver*>(observer) setURL:nsurl mimeType:[NSString stringWithUTF8String:mimeType.toLatin1().constData()]];
+}
+
+static void setStreamURL(void *observer, const QString &url)
+{
+ setURL(observer, QLatin1String("iodevice://") + url, QFileInfo(url).suffix());
+}
+
void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *stream)
{
#ifdef QT_DEBUG_AVF
@@ -497,7 +557,7 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st
[static_cast<AVFMediaPlayerSessionObserver*>(m_observer) unloadMedia];
m_resources = content;
- m_mediaStream = stream;
+ resetStream(stream);
setAudioAvailable(false);
setVideoAvailable(false);
@@ -508,7 +568,7 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st
const QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus;
const QMediaPlayer::State oldState = m_state;
- if (content.isNull() || content.request().url().isEmpty()) {
+ if (!m_mediaStream && (content.isNull() || content.request().url().isEmpty())) {
m_mediaStatus = QMediaPlayer::NoMedia;
if (m_mediaStatus != oldMediaStatus)
Q_EMIT mediaStatusChanged(m_mediaStatus);
@@ -524,11 +584,16 @@ 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.request().url().toEncoded().constData()];
- NSURL *url = [NSURL URLWithString:urlString];
- [static_cast<AVFMediaPlayerSessionObserver*>(m_observer) setURL:url];
+ if (m_mediaStream) {
+ // If there is a data, try to load it,
+ // otherwise wait for readyRead.
+ if (m_mediaStream->size())
+ setStreamURL(m_observer, m_resources.request().url().toString());
+ } else {
+ //Load AVURLAsset
+ //initialize asset using content's URL
+ setURL(m_observer, m_resources.request().url().toString());
+ }
m_state = QMediaPlayer::StoppedState;
if (m_state != oldState)
@@ -686,7 +751,7 @@ void AVFMediaPlayerSession::setPosition(qint64 pos)
CMTime newTime = [playerItem currentTime];
newTime.value = (pos / 1000.0f) * newTime.timescale;
- [playerItem seekToTime:newTime];
+ [playerItem seekToTime:newTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:nil];
Q_EMIT positionChanged(pos);
@@ -875,9 +940,11 @@ void AVFMediaPlayerSession::processLoadStateChange(QMediaPlayer::State newState)
// Get the native size of the video, and reset the bounds of the player layer
AVPlayerLayer *playerLayer = [static_cast<AVFMediaPlayerSessionObserver*>(m_observer) playerLayer];
if (videoTrack && playerLayer) {
- playerLayer.bounds = CGRectMake(0.0f, 0.0f,
- videoTrack.naturalSize.width,
- videoTrack.naturalSize.height);
+ if (!playerLayer.bounds.size.width || !playerLayer.bounds.size.height) {
+ playerLayer.bounds = CGRectMake(0.0f, 0.0f,
+ videoTrack.naturalSize.width,
+ videoTrack.naturalSize.height);
+ }
if (m_videoOutput && newState != QMediaPlayer::StoppedState) {
m_videoOutput->setLayer(playerLayer);
@@ -928,7 +995,8 @@ void AVFMediaPlayerSession::processBufferStateChange(int bufferStatus)
} else if (status == QMediaPlayer::StalledMedia) {
status = QMediaPlayer::BufferedMedia;
// Resume playback.
- [[static_cast<AVFMediaPlayerSessionObserver*>(m_observer) player] setRate:m_rate];
+ if (m_state == QMediaPlayer::PlayingState)
+ [[static_cast<AVFMediaPlayerSessionObserver*>(m_observer) player] setRate:m_rate];
}
if (m_mediaStatus != status)
@@ -966,3 +1034,28 @@ void AVFMediaPlayerSession::processMediaLoadError()
Q_EMIT error(QMediaPlayer::FormatError, tr("Failed to load media"));
}
+
+void AVFMediaPlayerSession::streamReady()
+{
+ setStreamURL(m_observer, m_resources.request().url().toString());
+}
+
+void AVFMediaPlayerSession::streamDestroyed()
+{
+ resetStream(nullptr);
+}
+
+void AVFMediaPlayerSession::resetStream(QIODevice *stream)
+{
+ if (m_mediaStream) {
+ disconnect(m_mediaStream, &QIODevice::readyRead, this, &AVFMediaPlayerSession::streamReady);
+ disconnect(m_mediaStream, &QIODevice::destroyed, this, &AVFMediaPlayerSession::streamDestroyed);
+ }
+
+ m_mediaStream = stream;
+
+ if (m_mediaStream) {
+ connect(m_mediaStream, &QIODevice::readyRead, this, &AVFMediaPlayerSession::streamReady);
+ connect(m_mediaStream, &QIODevice::destroyed, this, &AVFMediaPlayerSession::streamDestroyed);
+ }
+}
diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm
index be349710c..0987342b4 100644
--- a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm
+++ b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm
@@ -38,12 +38,9 @@
****************************************************************************/
#include "avfvideowidget.h"
-#include <QtCore/QDebug>
-#include <AVFoundation/AVFoundation.h>
-#include <QtGui/QResizeEvent>
-#include <QtGui/QPaintEvent>
-#include <QtGui/QPainter>
+#import <AVFoundation/AVFoundation.h>
+#import <QuartzCore/CATransaction.h>
#if defined(Q_OS_MACOS)
#import <AppKit/AppKit.h>
@@ -51,6 +48,11 @@
#import <UIKit/UIKit.h>
#endif
+#include <QtCore/QDebug>
+#include <QtGui/QResizeEvent>
+#include <QtGui/QPaintEvent>
+#include <QtGui/QPainter>
+
QT_USE_NAMESPACE
AVFVideoWidget::AVFVideoWidget(QWidget *parent)
@@ -178,5 +180,8 @@ void AVFVideoWidget::updateAspectRatio()
void AVFVideoWidget::updatePlayerLayerBounds(const QSize &size)
{
- m_playerLayer.bounds = CGRectMake(0.0f, 0.0f, (float)size.width(), (float)size.height());
+ [CATransaction begin];
+ [CATransaction setDisableActions: YES]; // disable animation/flicks
+ m_playerLayer.bounds = QRect(QPoint(0, 0), size).toCGRect();
+ [CATransaction commit];
}
diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm b/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm
index 7fa41fdc2..d61129ec9 100644
--- a/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm
+++ b/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm
@@ -40,6 +40,7 @@
#include "avfvideowindowcontrol.h"
#include <AVFoundation/AVFoundation.h>
+#import <QuartzCore/CATransaction.h>
#if QT_HAS_INCLUDE(<AppKit/AppKit.h>)
#include <AppKit/AppKit.h>
@@ -244,10 +245,10 @@ void AVFVideoWindowControl::updateAspectRatio()
void AVFVideoWindowControl::updatePlayerLayerBounds()
{
if (m_playerLayer) {
- CGRect newBounds = CGRectMake(0, 0,
- m_displayRect.width(), m_displayRect.height());
- m_playerLayer.bounds = newBounds;
- m_playerLayer.position = CGPointMake(m_displayRect.x(), m_displayRect.y());
+ [CATransaction begin];
+ [CATransaction setDisableActions: YES]; // disable animation/flicks
+ m_playerLayer.frame = m_displayRect.toCGRect();
+ [CATransaction commit];
}
}