Merge remote-tracking branch 'origin/5.3' into 5.4

Conflicts:
	src/gsttools/qgstreamervideoinputdevicecontrol.cpp
	src/plugins/gstreamer/camerabin/camerabinserviceplugin.cpp
	src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp

Change-Id: Ic854589562d2deeaa0ebf75840cb8a2ee32e99de
This commit is contained in:
Frederik Gladhorn
2014-08-28 16:25:20 +02:00
38 changed files with 436 additions and 149 deletions

View File

@@ -0,0 +1 @@
SOURCES += main.cpp

View File

@@ -0,0 +1,47 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <linux/videodev2.h>
int main(int argc, char** argv)
{
return 0;
}

View File

@@ -30,8 +30,11 @@
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _WIN32_WCE
#include <wmp.h>
#else
#include <wmpcore.h>
#endif
int main(int, char**)
{

View File

@@ -3,4 +3,5 @@ CONFIG += console
SOURCES += main.cpp
LIBS += -lstrmiids -lole32 -lOleaut32 -luser32 -lgdi32
LIBS += -lstrmiids -lole32 -lOleaut32
!wince*:LIBS += -luser32 -lgdi32

65
dist/changes-5.3.2 vendored Normal file
View File

@@ -0,0 +1,65 @@
Qt 5.3.2 is a bug-fix release. It maintains both forward and backward
compatibility (source and binary) with Qt 5.3.0 and 5.3.1.
For more details, refer to the online documentation included in this
distribution. The documentation is also available online:
http://qt-project.org/doc/qt-5.3
The Qt version 5.3 series is binary compatible with the 5.2.x series.
Applications compiled for 5.2 will continue to run with 5.3.
Some of the changes listed in this file include issue tracking numbers
corresponding to tasks in the Qt Bug Tracker:
http://bugreports.qt-project.org/
Each of these identifiers can be entered in the bug tracker to obtain more
information about a particular change.
****************************************************************************
* Platform Specific Changes *
****************************************************************************
Android
-------
- Fixed regression causing videos recorded with the camera not to be registered with the Android
media scanner, making them invisible to media browsing apps.
- Fixed crash when unloading a QCamera while a recording is active.
- [QTBUG-39307] Setting camera parameters on the QML Camera type (e.g. digitalZoom, flashMode)
now works correctly when set before the camera is loaded.
- [QTBUG-40208] QAudioOutput::setNotifyInterval() can now be used when the output is active.
- [QTBUG-40274] Fixed metadata not being loaded by the MediaPlayer when playing a remote media,
from a qrc file or from assets.
iOS
---
- [QTBUG-39036] Audio played using SoundEffect or QAudioOutput is now correctly muted when the
device is set to silent mode or when the screen is locked.
- [QTBUG-39385] The last video frame displayed in a QML VideoOutput doesn't remain on screen
anymore after destroying the VideoOutput.
Linux
-----
- MediaPlayer's loops property now works correctly when playing a media from a qrc file.
- [QTBUG-29742] Fixed Qt apps hanging when audio APIs are used and PulseAudio is not running.
- [QTBUG-39949] Fixed QMediaRecorder::setOutputLocation() not working with QUrl::fromLocalFile().
OS X
----
- Application doesn't freeze anymore when changing the system audio output device while audio
is being played with QSoundEffect or QAudioOutput.
- [QTBUG-38666] Video frames are now correctly positioned on screen when playing a live stream
in a QVideoWidget. This also applies to iOS.
- [QTBUG-38668] Fixed crash when setting QMediaRecorder's output location to a URL containing
nonstandard characters.
Windows
-------
- The DirectShow camera backend has been almost entirely rewritten. It doesn't provide any new
feature but it now works as it should.

View File

@@ -31,7 +31,8 @@
**
****************************************************************************/
import QtQuick 2.0
import QtQuick 2.1
import QtQuick.Window 2.1
Effect {
id: root
@@ -49,6 +50,7 @@ Effect {
property real posX: -1
property real posY: -1
property real pixDens: Screen.pixelDensity
QtObject {
id: d

View File

@@ -31,7 +31,8 @@
**
****************************************************************************/
import QtQuick 2.0
import QtQuick 2.1
import QtQuick.Window 2.1
Effect {
parameters: ListModel {
@@ -48,6 +49,7 @@ Effect {
// Transform slider values, and bind result to shader uniforms
property real amplitude: parameters.get(0).value * 0.03
property real n: parameters.get(1).value * 7
property real pixDens: Screen.pixelDensity
property real time: 0
NumberAnimation on time { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 600 }

View File

@@ -43,7 +43,7 @@ ListModel {
ListElement { name: "Emboss"; source: "EffectEmboss.qml" }
ListElement { name: "Glow"; source: "EffectGlow.qml" }
ListElement { name: "Isolate"; source: "EffectIsolate.qml" }
//ListElement { name: "Magnify"; source: "EffectMagnify.qml" }
ListElement { name: "Magnify"; source: "EffectMagnify.qml" }
ListElement { name: "Page curl"; source: "EffectPageCurl.qml" }
ListElement { name: "Pixelate"; source: "EffectPixelate.qml" }
ListElement { name: "Posterize"; source: "EffectPosterize.qml" }

View File

@@ -50,12 +50,15 @@ uniform float targetWidth;
uniform float targetHeight;
uniform float posX;
uniform float posY;
uniform float pixDens;
void main()
{
vec2 tc = qt_TexCoord0;
vec2 center = vec2(posX, posY);
vec2 xy = gl_FragCoord.xy - center.xy;
xy.x -= (pixDens * 14.0);
xy.y -= (pixDens * 29.0);
float r = sqrt(xy.x * xy.x + xy.y * xy.y);
if (r < radius) {
float h = diffractionIndex * 0.5 * radius;

View File

@@ -55,12 +55,13 @@ const int ITER = 7;
const float RATE = 0.1;
uniform float amplitude;
uniform float n;
uniform float pixDens;
void main()
{
vec2 uv = qt_TexCoord0.xy;
vec2 tc = uv;
vec2 p = vec2(-1.0 + 2.0 * gl_FragCoord.x / targetWidth, -(-1.0 + 2.0 * gl_FragCoord.y / targetHeight));
vec2 p = vec2(-1.0 + 2.0 * (gl_FragCoord.x - (pixDens * 14.0)) / targetWidth, -(-1.0 + 2.0 * (gl_FragCoord.y - (pixDens * 29.0)) / targetHeight));
float diffx = 0.0;
float diffy = 0.0;
vec4 col;

View File

@@ -12,10 +12,6 @@ win32 {
qtCompileTest(evr)
} else:mac {
qtCompileTest(avfoundation)
} else:android:!android-no-sdk {
SDK_ROOT = $$(ANDROID_SDK_ROOT)
isEmpty(SDK_ROOT): SDK_ROOT = $$DEFAULT_ANDROID_SDK_ROOT
!exists($$SDK_ROOT/platforms/android-11/android.jar): error("QtMultimedia for Android requires API level 11")
} else:qnx {
qtCompileTest(mmrenderer)
} else {
@@ -25,6 +21,7 @@ win32 {
qtCompileTest(gstreamer_photography)
qtCompileTest(gstreamer_encodingprofiles)
qtCompileTest(gstreamer_appsrc)
qtCompileTest(linux_v4l)
}
qtCompileTest(resourcepolicy)
qtCompileTest(gpu_vivante)

View File

@@ -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

View File

@@ -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();
}

View File

@@ -72,6 +72,7 @@ public:
Q_SIGNALS:
void metaDataUpdated();
void actualMediaLocationChanged(const QString &url);
public Q_SLOTS:
void setPosition(qint64 position) Q_DECL_OVERRIDE;

View File

@@ -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()));
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 uri = m_metadataRetriever.callStaticObjectMethod("android/net/Uri",
"parse",
"(Ljava/lang/String;)Landroid/net/Uri;",
string.object());
if (env->ExceptionCheck()) {
env->ExceptionClear();
QJNIObjectPrivate fd = fileInputStream.callObjectMethod("getFD",
"()Ljava/io/FileDescriptor;");
if (exceptionCheckAndClear(env)) {
fileInputStream.callMethod<void>("close");
exceptionCheckAndClear(env);
return false;
}
m_metadataRetriever.callMethod<void>("setDataSource",
"(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;
}
m_metadataRetriever.callMethod<void>("setDataSource",
"(Ljava/io/FileDescriptor;JJ)V",
fd.object(),
assetFd.callMethod<jlong>("getStartOffset"),
assetFd.callMethod<jlong>("getLength"));
bool ok = !exceptionCheckAndClear(env);
assetFd.callMethod<void>("close");
exceptionCheckAndClear(env);
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;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 (env->ExceptionCheck())
env->ExceptionClear();
else
loaded = true;
if (exceptionCheckAndClear(env))
return false;
}
return loaded;
}
bool AndroidMediaMetadataRetriever::setDataSource(const QString &path)
{
if (!m_metadataRetriever.isValid())
return false;
QJNIEnvironmentPrivate env;
bool loaded = false;
m_metadataRetriever.callMethod<void>("setDataSource",
"(Ljava/lang/String;)V",
QJNIObjectPrivate::fromString(path).object());
if (env->ExceptionCheck())
env->ExceptionClear();
else
loaded = true;
return loaded;
return true;
}
QT_END_NAMESPACE

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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
}

View File

@@ -148,6 +148,9 @@ private:
QByteArray rawData;
};
void setAudioAvailable(bool available);
void setVideoAvailable(bool available);
AVFMediaPlayerService *m_service;
AVFVideoOutput *m_videoOutput;

View File

@@ -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]) {

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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)));

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -112,6 +112,7 @@ private:
qint64 m_elapsedTime;
qint64 m_processedBytes;
QAtomicInt m_availableBuffers;
SLuint32 m_eventMask;
qint32 m_streamType;
QTime m_clockStamp;

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -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 \

View File

@@ -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);
}

View File

@@ -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) {