diff options
author | Yoann Lopes <yoann.lopes@digia.com> | 2014-09-01 14:19:53 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-09-01 14:19:53 +0200 |
commit | bc1fa076c944c6af3250cb7210190da42a4de6ea (patch) | |
tree | b6948fa95abbdd4ffbb30b76c7d3c09ae07e51db /src | |
parent | 0c3438c9a12fbc607eada8f938cf0ad8fdea374d (diff) | |
parent | 659f238bbbe040cce1bdf900f8f5500845ca8727 (diff) | |
download | qtmultimedia-bc1fa076c944c6af3250cb7210190da42a4de6ea.tar.gz |
Merge "Merge remote-tracking branch 'origin/5.3' into 5.4" into refs/staging/5.4v5.4.0-alpha1
Diffstat (limited to 'src')
27 files changed, 304 insertions, 139 deletions
diff --git a/src/gsttools/gsttools.pro b/src/gsttools/gsttools.pro index 15edd04d2..7c809a777 100644 --- a/src/gsttools/gsttools.pro +++ b/src/gsttools/gsttools.pro @@ -100,6 +100,8 @@ config_gstreamer_appsrc { LIBS_PRIVATE += -lgstapp-0.10 } +config_linux_v4l: DEFINES += USE_V4L + HEADERS += $$PRIVATE_HEADERS DESTDIR = $$QT.multimedia.libs diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp index 47dd94ccd..bd936f86d 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp +++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp @@ -317,8 +317,10 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent, mMediaPlayer->setDataSource(mediaPath); mMediaPlayer->prepareAsync(); - if (!reloading) + if (!reloading) { Q_EMIT mediaChanged(mMediaContent); + Q_EMIT actualMediaLocationChanged(mediaPath); + } resetBufferingProgress(); } diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h index 86d99e822..ec4dd3280 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h +++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h @@ -72,6 +72,7 @@ public: Q_SIGNALS: void metaDataUpdated(); + void actualMediaLocationChanged(const QString &url); public Q_SLOTS: void setPosition(qint64 position) Q_DECL_OVERRIDE; diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp index 00e8b6184..05cee3b9d 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp +++ b/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp @@ -45,8 +45,8 @@ QAndroidMediaService::QAndroidMediaService(QObject *parent) { mMediaControl = new QAndroidMediaPlayerControl; mMetadataControl = new QAndroidMetaDataReaderControl; - connect(mMediaControl, SIGNAL(mediaChanged(QMediaContent)), - mMetadataControl, SLOT(onMediaChanged(QMediaContent))); + connect(mMediaControl, SIGNAL(actualMediaLocationChanged(QString)), + mMetadataControl, SLOT(onMediaChanged(QString))); connect(mMediaControl, SIGNAL(metaDataUpdated()), mMetadataControl, SLOT(onUpdateMetaData())); } diff --git a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp index a3598228c..a9c87488a 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp +++ b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp @@ -93,18 +93,18 @@ QStringList QAndroidMetaDataReaderControl::availableMetaData() const return m_metadata.keys(); } -void QAndroidMetaDataReaderControl::onMediaChanged(const QMediaContent &media) +void QAndroidMetaDataReaderControl::onMediaChanged(const QString &url) { if (!m_retriever) return; - m_mediaContent = media; + m_mediaLocation = url; updateData(); } void QAndroidMetaDataReaderControl::onUpdateMetaData() { - if (!m_retriever || m_mediaContent.isNull()) + if (!m_retriever || m_mediaLocation.isEmpty()) return; updateData(); @@ -114,8 +114,8 @@ void QAndroidMetaDataReaderControl::updateData() { m_metadata.clear(); - if (!m_mediaContent.isNull()) { - if (m_retriever->setDataSource(m_mediaContent.canonicalUrl())) { + if (!m_mediaLocation.isEmpty()) { + if (m_retriever->setDataSource(m_mediaLocation)) { QString mimeType = m_retriever->extractMetadata(AndroidMediaMetadataRetriever::MimeType); if (!mimeType.isNull()) m_metadata.insert(QMediaMetaData::MediaType, mimeType); diff --git a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.h index 72df6eecc..f8720b77a 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.h +++ b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.h @@ -54,13 +54,13 @@ public: QStringList availableMetaData() const Q_DECL_OVERRIDE; public Q_SLOTS: - void onMediaChanged(const QMediaContent &media); + void onMediaChanged(const QString &url); void onUpdateMetaData(); private: void updateData(); - QMediaContent m_mediaContent; + QString m_mediaLocation; bool m_available; QVariantMap m_metadata; diff --git a/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.cpp b/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.cpp index a01aacf5e..df5345053 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.cpp +++ b/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.cpp @@ -35,9 +35,24 @@ #include <QtCore/private/qjnihelpers_p.h> #include <QtCore/private/qjni_p.h> +#include <QtCore/QUrl> +#include <qdebug.h> QT_BEGIN_NAMESPACE +static bool exceptionCheckAndClear(JNIEnv *env) +{ + if (Q_UNLIKELY(env->ExceptionCheck())) { +#ifdef QT_DEBUG + env->ExceptionDescribe(); +#endif // QT_DEBUG + env->ExceptionClear(); + return true; + } + + return false; +} + AndroidMediaMetadataRetriever::AndroidMediaMetadataRetriever() { m_metadataRetriever = QJNIObjectPrivate("android/media/MediaMetadataRetriever"); @@ -68,55 +83,105 @@ void AndroidMediaMetadataRetriever::release() m_metadataRetriever.callMethod<void>("release"); } -bool AndroidMediaMetadataRetriever::setDataSource(const QUrl &url) +bool AndroidMediaMetadataRetriever::setDataSource(const QString &urlString) { if (!m_metadataRetriever.isValid()) return false; QJNIEnvironmentPrivate env; + QUrl url(urlString); - bool loaded = false; + if (url.isLocalFile()) { // also includes qrc files (copied to a temp file) + QJNIObjectPrivate string = QJNIObjectPrivate::fromString(url.path()); + QJNIObjectPrivate fileInputStream("java/io/FileInputStream", + "(Ljava/lang/String;)V", + string.object()); - QJNIObjectPrivate string = QJNIObjectPrivate::fromString(url.toString()); + if (exceptionCheckAndClear(env)) + return false; + + QJNIObjectPrivate fd = fileInputStream.callObjectMethod("getFD", + "()Ljava/io/FileDescriptor;"); + if (exceptionCheckAndClear(env)) { + fileInputStream.callMethod<void>("close"); + exceptionCheckAndClear(env); + return false; + } - QJNIObjectPrivate uri = m_metadataRetriever.callStaticObjectMethod("android/net/Uri", - "parse", - "(Ljava/lang/String;)Landroid/net/Uri;", - string.object()); - if (env->ExceptionCheck()) { - env->ExceptionClear(); - } else { m_metadataRetriever.callMethod<void>("setDataSource", - "(Landroid/content/Context;Landroid/net/Uri;)V", - QtAndroidPrivate::activity(), - uri.object()); - if (env->ExceptionCheck()) - env->ExceptionClear(); - else - loaded = true; - } + "(Ljava/io/FileDescriptor;)V", + fd.object()); + + bool ok = !exceptionCheckAndClear(env); + + fileInputStream.callMethod<void>("close"); + exceptionCheckAndClear(env); + + if (!ok) + return false; + } else if (url.scheme() == QLatin1String("assets")) { + QJNIObjectPrivate string = QJNIObjectPrivate::fromString(url.path().mid(1)); // remove first '/' + QJNIObjectPrivate activity(QtAndroidPrivate::activity()); + QJNIObjectPrivate assetManager = activity.callObjectMethod("getAssets", + "()Landroid/content/res/AssetManager;"); + QJNIObjectPrivate assetFd = assetManager.callObjectMethod("openFd", + "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;", + string.object()); + if (exceptionCheckAndClear(env)) + return false; + + QJNIObjectPrivate fd = assetFd.callObjectMethod("getFileDescriptor", + "()Ljava/io/FileDescriptor;"); + if (exceptionCheckAndClear(env)) { + assetFd.callMethod<void>("close"); + exceptionCheckAndClear(env); + return false; + } - return loaded; -} + m_metadataRetriever.callMethod<void>("setDataSource", + "(Ljava/io/FileDescriptor;JJ)V", + fd.object(), + assetFd.callMethod<jlong>("getStartOffset"), + assetFd.callMethod<jlong>("getLength")); -bool AndroidMediaMetadataRetriever::setDataSource(const QString &path) -{ - if (!m_metadataRetriever.isValid()) - return false; + bool ok = !exceptionCheckAndClear(env); - QJNIEnvironmentPrivate env; + assetFd.callMethod<void>("close"); + exceptionCheckAndClear(env); - bool loaded = false; + if (!ok) + return false; + } else if (QtAndroidPrivate::androidSdkVersion() >= 14) { + // On API levels >= 14, only setDataSource(String, Map<String, String>) accepts remote media + QJNIObjectPrivate string = QJNIObjectPrivate::fromString(urlString); + QJNIObjectPrivate hash("java/util/HashMap"); - m_metadataRetriever.callMethod<void>("setDataSource", - "(Ljava/lang/String;)V", - QJNIObjectPrivate::fromString(path).object()); - if (env->ExceptionCheck()) - env->ExceptionClear(); - else - loaded = true; + m_metadataRetriever.callMethod<void>("setDataSource", + "(Ljava/lang/String;Ljava/util/Map;)V", + string.object(), + hash.object()); + if (exceptionCheckAndClear(env)) + return false; + } else { + // While on API levels < 14, only setDataSource(Context, Uri) is available and works for + // remote media... + QJNIObjectPrivate string = QJNIObjectPrivate::fromString(urlString); + QJNIObjectPrivate uri = m_metadataRetriever.callStaticObjectMethod("android/net/Uri", + "parse", + "(Ljava/lang/String;)Landroid/net/Uri;", + string.object()); + if (exceptionCheckAndClear(env)) + return false; + + m_metadataRetriever.callMethod<void>("setDataSource", + "(Landroid/content/Context;Landroid/net/Uri;)V", + QtAndroidPrivate::activity(), + uri.object()); + if (exceptionCheckAndClear(env)) + return false; + } - return loaded; + return true; } QT_END_NAMESPACE diff --git a/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.h b/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.h index 1cf0bcc91..c1633580f 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.h +++ b/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.h @@ -35,7 +35,6 @@ #define ANDROIDMEDIAMETADATARETRIEVER_H #include <QtCore/private/qjni_p.h> -#include <qurl.h> QT_BEGIN_NAMESPACE @@ -73,8 +72,7 @@ public: QString extractMetadata(MetadataKey key); void release(); - bool setDataSource(const QUrl &url); - bool setDataSource(const QString &path); + bool setDataSource(const QString &url); private: QJNIObjectPrivate m_metadataRetriever; diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm index 25111c5cc..966202ede 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.mm +++ b/src/plugins/avfoundation/camera/avfcameraservice.mm @@ -135,9 +135,9 @@ QMediaControl *AVFCameraService::requestControl(const char *name) void AVFCameraService::releaseControl(QMediaControl *control) { if (m_videoOutput == control) { - m_videoOutput = 0; m_session->setVideoOutput(0); - delete control; + delete m_videoOutput; + m_videoOutput = 0; } } diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayerservice.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayerservice.mm index e5549803f..bb75adb8b 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayerservice.mm +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayerservice.mm @@ -118,14 +118,15 @@ void AVFMediaPlayerService::releaseControl(QMediaControl *control) #ifdef QT_DEBUG_AVF qDebug() << Q_FUNC_INFO << control; #endif -#if defined(Q_OS_OSX) if (m_videoOutput == control) { +#if defined(Q_OS_OSX) AVFVideoRendererControl *renderControl = qobject_cast<AVFVideoRendererControl*>(m_videoOutput); if (renderControl) renderControl->setSurface(0); +#endif m_videoOutput = 0; m_session->setVideoOutput(0); + delete control; } -#endif } diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h index 09ac4b5b3..c850f45de 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h @@ -148,6 +148,9 @@ private: QByteArray rawData; }; + void setAudioAvailable(bool available); + void setVideoAvailable(bool available); + AVFMediaPlayerService *m_service; AVFVideoOutput *m_videoOutput; diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm index a73974ccd..106e81a37 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm @@ -70,15 +70,11 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe AVPlayerItem *m_playerItem; AVPlayerLayer *m_playerLayer; NSURL *m_URL; - bool m_audioAvailable; - bool m_videoAvailable; } @property (readonly, getter=player) AVPlayer* m_player; @property (readonly, getter=playerItem) AVPlayerItem* m_playerItem; @property (readonly, getter=playerLayer) AVPlayerLayer* m_playerLayer; -@property (readonly, getter=audioAvailable) bool m_audioAvailable; -@property (readonly, getter=videoAvailable) bool m_videoAvailable; @property (readonly, getter=session) AVFMediaPlayerSession* m_session; - (AVFMediaPlayerSessionObserver *) initWithMediaPlayerSession:(AVFMediaPlayerSession *)session; @@ -96,7 +92,7 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe @implementation AVFMediaPlayerSessionObserver -@synthesize m_player, m_playerItem, m_playerLayer, m_audioAvailable, m_videoAvailable, m_session; +@synthesize m_player, m_playerItem, m_playerLayer, m_session; - (AVFMediaPlayerSessionObserver *) initWithMediaPlayerSession:(AVFMediaPlayerSession *)session { @@ -186,18 +182,6 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe return; } - m_audioAvailable = false; - m_videoAvailable = false; - - //Check each track of asset for audio and video content - NSArray *tracks = [asset tracks]; - for (AVAssetTrack *track in tracks) { - if ([track hasMediaCharacteristic:AVMediaCharacteristicAudible]) - m_audioAvailable = true; - if ([track hasMediaCharacteristic:AVMediaCharacteristicVisual]) - m_videoAvailable = true; - } - //At this point we're ready to set up for playback of the asset. //Stop observing our prior AVPlayerItem, if we have one. if (m_playerItem) @@ -258,18 +242,7 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe m_playerLayer = [AVPlayerLayer playerLayerWithPlayer:m_player]; [m_playerLayer retain]; m_playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; - - //Get the native size of the new item, and reset the bounds of the player layer - AVAsset *asset = m_playerItem.asset; - if (asset) { - NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; - if ([tracks count]) { - AVAssetTrack *videoTrack = [tracks objectAtIndex:0]; - m_playerLayer.anchorPoint = CGPointMake(0.0f, 0.0f); - m_playerLayer.bounds = CGRectMake(0.0f, 0.0f, videoTrack.naturalSize.width, videoTrack.naturalSize.height); - } - } - + m_playerLayer.anchorPoint = CGPointMake(0.0f, 0.0f); } //Observe the AVPlayer "currentItem" property to find out when any @@ -366,22 +339,8 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe { AVPlayerItem *newPlayerItem = [change objectForKey:NSKeyValueChangeNewKey]; if (m_playerItem != newPlayerItem) - { m_playerItem = newPlayerItem; - //Get the native size of the new item, and reset the bounds of the player layer - //AVAsset *asset = m_playerItem.asset; - AVAsset *asset = [m_playerItem asset]; - if (asset) { - NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; - if ([tracks count]) { - AVAssetTrack *videoTrack = [tracks objectAtIndex:0]; - m_playerLayer.anchorPoint = CGPointMake(0.0f, 0.0f); - m_playerLayer.bounds = CGRectMake(0.0f, 0.0f, videoTrack.naturalSize.width, videoTrack.naturalSize.height); - } - } - - } if (self.session) QMetaObject::invokeMethod(m_session, "processCurrentItemChanged", Qt::AutoConnection); } @@ -513,6 +472,9 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st m_resources = content; m_mediaStream = stream; + setAudioAvailable(false); + setVideoAvailable(false); + QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus; if (content.isNull() || content.canonicalUrl().isEmpty()) { @@ -582,14 +544,32 @@ bool AVFMediaPlayerSession::isMuted() const return m_muted; } +void AVFMediaPlayerSession::setAudioAvailable(bool available) +{ + if (m_audioAvailable == available) + return; + + m_audioAvailable = available; + Q_EMIT audioAvailableChanged(available); +} + bool AVFMediaPlayerSession::isAudioAvailable() const { - return [(AVFMediaPlayerSessionObserver*)m_observer audioAvailable]; + return m_audioAvailable; +} + +void AVFMediaPlayerSession::setVideoAvailable(bool available) +{ + if (m_videoAvailable == available) + return; + + m_videoAvailable = available; + Q_EMIT videoAvailableChanged(available); } bool AVFMediaPlayerSession::isVideoAvailable() const { - return [(AVFMediaPlayerSessionObserver*)m_observer videoAvailable]; + return m_videoAvailable; } bool AVFMediaPlayerSession::isSeekable() const @@ -802,16 +782,37 @@ void AVFMediaPlayerSession::processLoadStateChange() bool isPlaying = (m_state != QMediaPlayer::StoppedState); if (currentStatus == AVPlayerStatusReadyToPlay) { + AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem]; + if (playerItem) { + // Check each track for audio and video content + AVAssetTrack *videoTrack = nil; + NSArray *tracks = playerItem.tracks; + for (AVPlayerItemTrack *track in tracks) { + AVAssetTrack *assetTrack = track.assetTrack; + if (assetTrack) { + if ([assetTrack.mediaType isEqualToString:AVMediaTypeAudio]) + setAudioAvailable(true); + if ([assetTrack.mediaType isEqualToString:AVMediaTypeVideo]) { + setVideoAvailable(true); + if (!videoTrack) + videoTrack = assetTrack; + } + } + } + + // Get the native size of the video, and reset the bounds of the player layer + AVPlayerLayer *playerLayer = [(AVFMediaPlayerSessionObserver*)m_observer playerLayer]; + if (videoTrack && playerLayer) { + playerLayer.bounds = CGRectMake(0.0f, 0.0f, + videoTrack.naturalSize.width, + videoTrack.naturalSize.height); + } + } + qint64 currentDuration = duration(); if (m_duration != currentDuration) Q_EMIT durationChanged(m_duration = currentDuration); - if (m_audioAvailable != isAudioAvailable()) - Q_EMIT audioAvailableChanged(m_audioAvailable = !m_audioAvailable); - - if (m_videoAvailable != isVideoAvailable()) - Q_EMIT videoAvailableChanged(m_videoAvailable = !m_videoAvailable); - newStatus = isPlaying ? QMediaPlayer::BufferedMedia : QMediaPlayer::LoadedMedia; if (m_state == QMediaPlayer::PlayingState && [(AVFMediaPlayerSessionObserver*)m_observer player]) { diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm index d4fa7c4c6..2893921f3 100644 --- a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm +++ b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm @@ -64,8 +64,10 @@ AVFVideoWidget::~AVFVideoWidget() qDebug() << Q_FUNC_INFO; #endif - if (m_playerLayer) + if (m_playerLayer) { + [m_playerLayer removeFromSuperlayer]; [m_playerLayer release]; + } } QSize AVFVideoWidget::sizeHint() const diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm b/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm index 17fc94de7..8e96d732f 100644 --- a/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm +++ b/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm @@ -61,8 +61,10 @@ AVFVideoWindowControl::AVFVideoWindowControl(QObject *parent) AVFVideoWindowControl::~AVFVideoWindowControl() { - if (m_playerLayer) + if (m_playerLayer) { + [m_playerLayer removeFromSuperlayer]; [m_playerLayer release]; + } } WId AVFVideoWindowControl::winId() const diff --git a/src/plugins/coreaudio/coreaudiooutput.mm b/src/plugins/coreaudio/coreaudiooutput.mm index e5e1c65e5..812d9dfe2 100644 --- a/src/plugins/coreaudio/coreaudiooutput.mm +++ b/src/plugins/coreaudio/coreaudiooutput.mm @@ -698,14 +698,14 @@ void CoreAudioOutput::audioThreadStop() { stopTimers(); if (m_audioThreadState.testAndSetAcquire(Running, Stopped)) - m_threadFinished.wait(&m_mutex); + m_threadFinished.wait(&m_mutex, 500); } void CoreAudioOutput::audioThreadDrain() { stopTimers(); if (m_audioThreadState.testAndSetAcquire(Running, Draining)) - m_threadFinished.wait(&m_mutex); + m_threadFinished.wait(&m_mutex, 500); } void CoreAudioOutput::audioDeviceStop() diff --git a/src/plugins/gstreamer/camerabin/camerabin.pro b/src/plugins/gstreamer/camerabin/camerabin.pro index bba797f5e..90a1040fb 100644 --- a/src/plugins/gstreamer/camerabin/camerabin.pro +++ b/src/plugins/gstreamer/camerabin/camerabin.pro @@ -83,6 +83,8 @@ config_gstreamer_photography { DEFINES += GST_USE_UNSTABLE_API #prevents warnings because of unstable photography API } +config_linux_v4l: DEFINES += USE_V4L + OTHER_FILES += \ camerabin.json diff --git a/src/plugins/gstreamer/camerabin/camerabinserviceplugin.cpp b/src/plugins/gstreamer/camerabin/camerabinserviceplugin.cpp index 4e7630b72..8c943529e 100644 --- a/src/plugins/gstreamer/camerabin/camerabinserviceplugin.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinserviceplugin.cpp @@ -43,7 +43,10 @@ #include <private/qgstutils_p.h> #include <private/qcore_unix_p.h> + +#if defined(USE_V4L) #include <linux/videodev2.h> +#endif QT_BEGIN_NAMESPACE diff --git a/src/plugins/gstreamer/mediacapture/mediacapture.pro b/src/plugins/gstreamer/mediacapture/mediacapture.pro index e8d039f8d..5baa0fd8f 100644 --- a/src/plugins/gstreamer/mediacapture/mediacapture.pro +++ b/src/plugins/gstreamer/mediacapture/mediacapture.pro @@ -15,7 +15,6 @@ HEADERS += $$PWD/qgstreamercaptureservice.h \ $$PWD/qgstreamerrecordercontrol.h \ $$PWD/qgstreamermediacontainercontrol.h \ $$PWD/qgstreamercameracontrol.h \ - $$PWD/qgstreamerv4l2input.h \ $$PWD/qgstreamercapturemetadatacontrol.h \ $$PWD/qgstreamerimagecapturecontrol.h \ $$PWD/qgstreamerimageencode.h \ @@ -28,7 +27,6 @@ SOURCES += $$PWD/qgstreamercaptureservice.cpp \ $$PWD/qgstreamerrecordercontrol.cpp \ $$PWD/qgstreamermediacontainercontrol.cpp \ $$PWD/qgstreamercameracontrol.cpp \ - $$PWD/qgstreamerv4l2input.cpp \ $$PWD/qgstreamercapturemetadatacontrol.cpp \ $$PWD/qgstreamerimagecapturecontrol.cpp \ $$PWD/qgstreamerimageencode.cpp \ @@ -37,13 +35,18 @@ SOURCES += $$PWD/qgstreamercaptureservice.cpp \ # Camera usage with gstreamer needs to have #CONFIG += use_gstreamer_camera -use_gstreamer_camera { -DEFINES += USE_GSTREAMER_CAMERA +use_gstreamer_camera:config_linux_v4l { + DEFINES += USE_GSTREAMER_CAMERA + + OTHER_FILES += \ + mediacapturecamera.json + + HEADERS += \ + $$PWD/qgstreamerv4l2input.h + SOURCES += \ + $$PWD/qgstreamerv4l2input.cpp -OTHER_FILES += \ - mediacapturecamera.json } else { -OTHER_FILES += \ - mediacapture.json + OTHER_FILES += \ + mediacapture.json } - diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp index 2e73797ee..97a165dca 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp +++ b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp @@ -40,9 +40,12 @@ #include "qgstreamerimageencode.h" #include "qgstreamercameracontrol.h" #include <private/qgstreamerbushelper_p.h> -#include "qgstreamerv4l2input.h" #include "qgstreamercapturemetadatacontrol.h" +#if defined(USE_GSTREAMER_CAMERA) +#include "qgstreamerv4l2input.h" +#endif + #include "qgstreamerimagecapturecontrol.h" #include <private/qgstreameraudioinputselector_p.h> #include <private/qgstreamervideoinputdevicecontrol_p.h> @@ -66,7 +69,9 @@ QGstreamerCaptureService::QGstreamerCaptureService(const QString &service, QObje m_cameraControl = 0; m_metaDataControl = 0; +#if defined(USE_GSTREAMER_CAMERA) m_videoInput = 0; +#endif m_audioInputSelector = 0; m_videoInputDevice = 0; @@ -82,6 +87,7 @@ QGstreamerCaptureService::QGstreamerCaptureService(const QString &service, QObje m_captureSession = new QGstreamerCaptureSession(QGstreamerCaptureSession::Audio, this); } +#if defined(USE_GSTREAMER_CAMERA) if (service == Q_MEDIASERVICE_CAMERA) { m_captureSession = new QGstreamerCaptureSession(QGstreamerCaptureSession::AudioAndVideo, this); m_cameraControl = new QGstreamerCameraControl(m_captureSession); @@ -103,6 +109,7 @@ QGstreamerCaptureService::QGstreamerCaptureService(const QString &service, QObje #endif m_imageCaptureControl = new QGstreamerImageCaptureControl(m_captureSession); } +#endif m_audioInputSelector = new QGstreamerAudioInputSelector(this); connect(m_audioInputSelector, SIGNAL(activeInputChanged(QString)), m_captureSession, SLOT(setCaptureDevice(QString))); diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h index 2b1a0dcca..7ff8ce253 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h +++ b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h @@ -70,7 +70,9 @@ private: QGstreamerCaptureSession *m_captureSession; QGstreamerCameraControl *m_cameraControl; +#if defined(USE_GSTREAMER_CAMERA) QGstreamerV4L2Input *m_videoInput; +#endif QGstreamerCaptureMetaDataControl *m_metaDataControl; QAudioInputSelectorControl *m_audioInputSelector; diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index f055796b5..f6583e542 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -70,7 +70,8 @@ QOpenSLESAudioOutput::QOpenSLESAudioOutput(const QByteArray &device) m_periodSize(0), m_elapsedTime(0), m_processedBytes(0), - m_availableBuffers(BUFFER_COUNT) + m_availableBuffers(BUFFER_COUNT), + m_eventMask(SL_PLAYEVENT_HEADATEND) { #ifndef ANDROID m_streamType = -1; @@ -190,7 +191,33 @@ int QOpenSLESAudioOutput::bufferSize() const void QOpenSLESAudioOutput::setNotifyInterval(int ms) { - m_notifyInterval = ms > 0 ? ms : 0; + const int newInterval = ms > 0 ? ms : 0; + + if (newInterval == m_notifyInterval) + return; + + const SLuint32 newEvenMask = newInterval == 0 ? m_eventMask & ~SL_PLAYEVENT_HEADATNEWPOS + : m_eventMask & SL_PLAYEVENT_HEADATNEWPOS; + + if (m_state == QAudio::StoppedState) { + m_eventMask = newEvenMask; + m_notifyInterval = newInterval; + return; + } + + if (newEvenMask != m_eventMask + && SL_RESULT_SUCCESS != (*m_playItf)->SetCallbackEventsMask(m_playItf, newEvenMask)) { + return; + } + + m_eventMask = newEvenMask; + + if (newInterval && SL_RESULT_SUCCESS != (*m_playItf)->SetPositionUpdatePeriod(m_playItf, + newInterval)) { + return; + } + + m_notifyInterval = newInterval; } int QOpenSLESAudioOutput::notifyInterval() const @@ -480,13 +507,12 @@ bool QOpenSLESAudioOutput::preparePlayer() return false; } - SLuint32 mask = SL_PLAYEVENT_HEADATEND; if (m_notifyInterval && SL_RESULT_SUCCESS == (*m_playItf)->SetPositionUpdatePeriod(m_playItf, m_notifyInterval)) { - mask |= SL_PLAYEVENT_HEADATNEWPOS; + m_eventMask |= SL_PLAYEVENT_HEADATNEWPOS; } - if (SL_RESULT_SUCCESS != (*m_playItf)->SetCallbackEventsMask(m_playItf, mask)) { + if (SL_RESULT_SUCCESS != (*m_playItf)->SetCallbackEventsMask(m_playItf, m_eventMask)) { setError(QAudio::FatalError); return false; } diff --git a/src/plugins/opensles/qopenslesaudiooutput.h b/src/plugins/opensles/qopenslesaudiooutput.h index 60c8cfa86..d466ea64b 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.h +++ b/src/plugins/opensles/qopenslesaudiooutput.h @@ -112,6 +112,7 @@ private: qint64 m_elapsedTime; qint64 m_processedBytes; QAtomicInt m_availableBuffers; + SLuint32 m_eventMask; qint32 m_streamType; QTime m_clockStamp; diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 0020203c3..f03a138ec 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -44,7 +44,9 @@ unix:!mac:!android { config_alsa: SUBDIRS += alsa # v4l is turned off because it is not supported in Qt 5 - # !maemo*:SUBDIRS += v4l + # config_linux_v4l { + # !maemo*:SUBDIRS += v4l + # } } mac:!simulator { diff --git a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp index 59a9f661f..4f8f03836 100644 --- a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp +++ b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp @@ -404,6 +404,7 @@ QList<QByteArray> QWindowsAudioDeviceInfo::availableDevices(QAudio::Mode mode) Q_UNUSED(mode) QList<QByteArray> devices; +#ifndef Q_OS_WINCE //enumerate device fullnames through directshow api CoInitialize(NULL); ICreateDevEnum *pDevEnum = NULL; @@ -455,6 +456,35 @@ QList<QByteArray> QWindowsAudioDeviceInfo::availableDevices(QAudio::Mode mode) } } CoUninitialize(); +#else // Q_OS_WINCE + if (mode == QAudio::AudioOutput) { + WAVEOUTCAPS woc; + unsigned long iNumDevs,i; + iNumDevs = waveOutGetNumDevs(); + for (i=0;i<iNumDevs;i++) { + if (waveOutGetDevCaps(i, &woc, sizeof(WAVEOUTCAPS)) + == MMSYSERR_NOERROR) { + QByteArray device; + QDataStream ds(&device, QIODevice::WriteOnly); + ds << quint32(i) << QString::fromWCharArray(woc.szPname); + devices.append(device); + } + } + } else { + WAVEINCAPS woc; + unsigned long iNumDevs,i; + iNumDevs = waveInGetNumDevs(); + for (i=0;i<iNumDevs;i++) { + if (waveInGetDevCaps(i, &woc, sizeof(WAVEINCAPS)) + == MMSYSERR_NOERROR) { + QByteArray device; + QDataStream ds(&device, QIODevice::WriteOnly); + ds << quint32(i) << QString::fromWCharArray(woc.szPname); + devices.append(device); + } + } + } +#endif // !Q_OS_WINCE return devices; } diff --git a/src/plugins/windowsaudio/windowsaudio.pro b/src/plugins/windowsaudio/windowsaudio.pro index a1a327953..ead73251b 100644 --- a/src/plugins/windowsaudio/windowsaudio.pro +++ b/src/plugins/windowsaudio/windowsaudio.pro @@ -5,7 +5,8 @@ PLUGIN_TYPE = audio PLUGIN_CLASS_NAME = QWindowsAudioPlugin load(qt_plugin) -LIBS += -lwinmm -lstrmiids -lole32 -loleaut32 +LIBS += -lstrmiids -lole32 -loleaut32 +!wince*:LIBS += -lwinmm HEADERS += \ qwindowsaudioplugin.h \ diff --git a/src/plugins/wmf/player/mfplayersession.cpp b/src/plugins/wmf/player/mfplayersession.cpp index 77b19f1b0..4ddb82ee6 100644 --- a/src/plugins/wmf/player/mfplayersession.cpp +++ b/src/plugins/wmf/player/mfplayersession.cpp @@ -1395,14 +1395,17 @@ int MFPlayerSession::bufferStatus() if (!m_netsourceStatistics) return 0; PROPVARIANT var; + PropVariantInit(&var); PROPERTYKEY key; key.fmtid = MFNETSOURCE_STATISTICS; key.pid = MFNETSOURCE_BUFFERPROGRESS_ID; int progress = -1; - if (SUCCEEDED(m_netsourceStatistics->GetValue(key, &var))) { + // GetValue returns S_FALSE if the property is not available, which has + // a value > 0. We therefore can't use the SUCCEEDED macro here. + if (m_netsourceStatistics->GetValue(key, &var) == S_OK) { progress = var.lVal; + PropVariantClear(&var); } - PropVariantClear(&var); #ifdef DEBUG_MEDIAFOUNDATION qDebug() << "bufferStatus: progress = " << progress; @@ -1413,22 +1416,30 @@ int MFPlayerSession::bufferStatus() QMediaTimeRange MFPlayerSession::availablePlaybackRanges() { - if (!m_netsourceStatistics) - return QMediaTimeRange(); + // defaults to the whole media + qint64 start = 0; + qint64 end = qint64(m_duration / 10000); - qint64 start = 0, end = 0; - PROPVARIANT var; - PROPERTYKEY key; - key.fmtid = MFNETSOURCE_STATISTICS; - key.pid = MFNETSOURCE_SEEKRANGESTART_ID; - if (SUCCEEDED(m_netsourceStatistics->GetValue(key, &var))) { - start = qint64(var.uhVal.QuadPart / 10000); - key.pid = MFNETSOURCE_SEEKRANGEEND_ID; - if (SUCCEEDED(m_netsourceStatistics->GetValue(key, &var))) { - end = qint64(var.uhVal.QuadPart / 10000); + if (m_netsourceStatistics) { + PROPVARIANT var; + PropVariantInit(&var); + PROPERTYKEY key; + key.fmtid = MFNETSOURCE_STATISTICS; + key.pid = MFNETSOURCE_SEEKRANGESTART_ID; + // GetValue returns S_FALSE if the property is not available, which has + // a value > 0. We therefore can't use the SUCCEEDED macro here. + if (m_netsourceStatistics->GetValue(key, &var) == S_OK) { + start = qint64(var.uhVal.QuadPart / 10000); + PropVariantClear(&var); + PropVariantInit(&var); + key.pid = MFNETSOURCE_SEEKRANGEEND_ID; + if (m_netsourceStatistics->GetValue(key, &var) == S_OK) { + end = qint64(var.uhVal.QuadPart / 10000); + PropVariantClear(&var); + } } } - PropVariantClear(&var); + return QMediaTimeRange(start, end); } diff --git a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp index e993609ad..72cbc9614 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp @@ -212,7 +212,7 @@ public: stride /= 4; } - m_width = qreal(m_frame.width() / stride); + m_width = qreal(m_frame.width()) / stride; textureSize.setWidth(stride); if (m_textureSize != textureSize) { |