From 1eb77d37821a42742a9b2984c89e3aed8296a5fc Mon Sep 17 00:00:00 2001 From: tommyadam Date: Wed, 3 Jul 2013 10:22:50 +0200 Subject: Fix resource leak in directshow plugin. Add two missing release calls to free file handles. Task-number: QTBUG-23822 Change-Id: I8f5b6d0dcf9ad66bdaa2f378c0d3e401388d7add Reviewed-by: Wouter Huysentruit Reviewed-by: Yoann Lopes --- src/plugins/directshow/player/directshowplayerservice.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/directshow/player/directshowplayerservice.cpp b/src/plugins/directshow/player/directshowplayerservice.cpp index d89ed7bdb..70049e245 100644 --- a/src/plugins/directshow/player/directshowplayerservice.cpp +++ b/src/plugins/directshow/player/directshowplayerservice.cpp @@ -578,6 +578,9 @@ void DirectShowPlayerService::doReleaseGraph(QMutexLocker *locker) control->Release(); } + //release m_headerInfo -> decrease ref counter of m_source + m_metaDataControl->updateGraph(0, 0); + if (m_source) { m_source->Release(); m_source = 0; @@ -627,6 +630,7 @@ int DirectShowPlayerService::findStreamTypes(IBaseFilter *source) const } } } + pins->Release(); } filter->Release(); } -- cgit v1.2.3 From 1dfbe44d90fb0a13f67642ca61a64c91f8322e9f Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 23 May 2013 15:15:44 +0200 Subject: Android: release the Android media player before destroying it. Change-Id: I18715efd7ff346a9f6f2214727ec66ee79ad0d33 Reviewed-by: Christian Stromme --- src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp | 1 + src/plugins/android/wrappers/jmediaplayer.cpp | 5 +++++ src/plugins/android/wrappers/jmediaplayer.h | 2 ++ 3 files changed, 8 insertions(+) diff --git a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp index 5a9c8b84f..cb34fba32 100644 --- a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp +++ b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp @@ -74,6 +74,7 @@ QAndroidMediaPlayerControl::QAndroidMediaPlayerControl(QObject *parent) QAndroidMediaPlayerControl::~QAndroidMediaPlayerControl() { + mMediaPlayer->release(); delete mMediaPlayer; } diff --git a/src/plugins/android/wrappers/jmediaplayer.cpp b/src/plugins/android/wrappers/jmediaplayer.cpp index 48e743b26..f6e03ee22 100644 --- a/src/plugins/android/wrappers/jmediaplayer.cpp +++ b/src/plugins/android/wrappers/jmediaplayer.cpp @@ -82,6 +82,11 @@ JMediaPlayer::~JMediaPlayer() mplayers.remove(mId); } +void JMediaPlayer::release() +{ + callMethod("release"); +} + void JMediaPlayer::onError(qint32 what, qint32 extra) { Q_EMIT error(what, extra); diff --git a/src/plugins/android/wrappers/jmediaplayer.h b/src/plugins/android/wrappers/jmediaplayer.h index f5cb11773..710246b9a 100644 --- a/src/plugins/android/wrappers/jmediaplayer.h +++ b/src/plugins/android/wrappers/jmediaplayer.h @@ -89,6 +89,8 @@ public: MEDIA_PLAYER_FINISHED = 6 }; + void release(); + int getCurrentPosition(); int getDuration(); bool isPlaying(); -- cgit v1.2.3 From 5e7e8e04d1be82e23f69e2966d355b4aa8d93442 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 5 Jul 2013 16:26:55 +0200 Subject: Android: wait to have a valid video surface before loading a media. Setting the video surface on the Android media player after it has loaded the media doesn't work on some hardware. Change-Id: I5e621a34ace9de458bfc65bfac8fa50c29cee9a5 Reviewed-by: Christian Stromme --- .../mediaplayer/qandroidmediaplayercontrol.cpp | 54 +++++++++++--- .../mediaplayer/qandroidmediaplayercontrol.h | 4 ++ .../android/mediaplayer/qandroidvideooutput.h | 6 ++ .../mediaplayer/qandroidvideorendercontrol.cpp | 84 +++++++++++++++++----- .../mediaplayer/qandroidvideorendercontrol.h | 9 ++- 5 files changed, 130 insertions(+), 27 deletions(-) diff --git a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp index cb34fba32..a70f4e130 100644 --- a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp +++ b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp @@ -45,6 +45,12 @@ QT_BEGIN_NAMESPACE +static void textureReadyCallback(void *context) +{ + if (context) + reinterpret_cast(context)->onSurfaceTextureReady(); +} + QAndroidMediaPlayerControl::QAndroidMediaPlayerControl(QObject *parent) : QMediaPlayerControl(parent), mMediaPlayer(new JMediaPlayer), @@ -58,7 +64,8 @@ QAndroidMediaPlayerControl::QAndroidMediaPlayerControl(QObject *parent) mVideoAvailable(false), mBuffering(false), mMediaPlayerReady(false), - mPendingPosition(-1) + mPendingPosition(-1), + mPendingSetMedia(false) { connect(mMediaPlayer, SIGNAL(bufferingUpdate(qint32)), this, SLOT(onBufferChanged(qint32))); @@ -208,6 +215,13 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent, mMediaContent = mediaContent; mMediaStream = stream; + if (mVideoOutput && !mMediaPlayer->display()) { + // if a video output is set but the video texture is not ready, delay loading the media + // since it can cause problems on some hardware + mPendingSetMedia = true; + return; + } + const QString uri = mediaContent.canonicalUrl().toString(); if (!uri.isEmpty()) @@ -231,6 +245,13 @@ void QAndroidMediaPlayerControl::setVideoOutput(QAndroidVideoOutput *videoOutput mVideoOutput->stop(); mVideoOutput = videoOutput; + + if (mVideoOutput && !mMediaPlayer->display()) { + if (mVideoOutput->isTextureReady()) + mMediaPlayer->setDisplay(mVideoOutput->surfaceHolder()); + else + mVideoOutput->setTextureReadyCallback(textureReadyCallback, this); + } } void QAndroidMediaPlayerControl::play() @@ -239,7 +260,8 @@ void QAndroidMediaPlayerControl::play() mPendingState = QMediaPlayer::PlayingState; if (mCurrentState == QMediaPlayer::StoppedState && !mMediaContent.isNull() - && mCurrentMediaStatus != QMediaPlayer::LoadingMedia) { + && mCurrentMediaStatus != QMediaPlayer::LoadingMedia + && !mPendingSetMedia) { setMedia(mMediaContent, 0); } return; @@ -392,16 +414,23 @@ void QAndroidMediaPlayerControl::onBufferChanged(qint32 percent) void QAndroidMediaPlayerControl::onVideoSizeChanged(qint32 width, qint32 height) { - if (width == 0 || height == 0) + QSize newSize(width, height); + + if (width == 0 || height == 0 || newSize == mVideoSize) return; setVideoAvailable(true); + mVideoSize = newSize; - if (mVideoOutput) { - if (!mMediaPlayer->display()) - mMediaPlayer->setDisplay(mVideoOutput->surfaceHolder()); - if (mMediaPlayer->display()) - mVideoOutput->setVideoSize(QSize(width, height)); + if (mVideoOutput) + mVideoOutput->setVideoSize(mVideoSize); +} + +void QAndroidMediaPlayerControl::onSurfaceTextureReady() +{ + if (!mMediaPlayer->display() && mVideoOutput) { + mMediaPlayer->setDisplay(mVideoOutput->surfaceHolder()); + flushPendingStates(); } } @@ -465,6 +494,9 @@ void QAndroidMediaPlayerControl::setVideoAvailable(bool available) if (mVideoAvailable == available) return; + if (!available) + mVideoSize = QSize(); + mVideoAvailable = available; Q_EMIT videoAvailableChanged(mVideoAvailable); } @@ -479,6 +511,12 @@ void QAndroidMediaPlayerControl::resetBufferingProgress() void QAndroidMediaPlayerControl::flushPendingStates() { + if (mPendingSetMedia) { + setMedia(mMediaContent, 0); + mPendingSetMedia = false; + return; + } + switch (mPendingState) { case QMediaPlayer::PlayingState: if (mPendingPosition > -1) diff --git a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.h b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.h index 445e8de7a..93eced853 100644 --- a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.h +++ b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.h @@ -44,6 +44,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -75,6 +76,7 @@ public: void setMedia(const QMediaContent &mediaContent, QIODevice *stream) Q_DECL_OVERRIDE; void setVideoOutput(QAndroidVideoOutput *videoOutput); + void onSurfaceTextureReady(); Q_SIGNALS: void metaDataUpdated(); @@ -105,11 +107,13 @@ private: int mBufferPercent; bool mAudioAvailable; bool mVideoAvailable; + QSize mVideoSize; bool mBuffering; QMediaTimeRange mAvailablePlaybackRange; bool mMediaPlayerReady; QMediaPlayer::State mPendingState; qint64 mPendingPosition; + bool mPendingSetMedia; void setState(QMediaPlayer::State state); void setMediaStatus(QMediaPlayer::MediaStatus status); diff --git a/src/plugins/android/mediaplayer/qandroidvideooutput.h b/src/plugins/android/mediaplayer/qandroidvideooutput.h index 99db7c3e7..d59971f3b 100644 --- a/src/plugins/android/mediaplayer/qandroidvideooutput.h +++ b/src/plugins/android/mediaplayer/qandroidvideooutput.h @@ -48,6 +48,8 @@ QT_BEGIN_NAMESPACE +typedef void (*TextureReadyCallback)(void*); + class QAndroidVideoOutput { public: @@ -55,6 +57,10 @@ public: virtual ~QAndroidVideoOutput() { } virtual jobject surfaceHolder() = 0; + + virtual bool isTextureReady() = 0; + virtual void setTextureReadyCallback(TextureReadyCallback cb, void *context = 0) = 0; + virtual void setVideoSize(const QSize &size) = 0; virtual void stop() = 0; }; diff --git a/src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp b/src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp index c63e0e771..fe26b455a 100644 --- a/src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp +++ b/src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp @@ -50,6 +50,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -134,6 +135,8 @@ QAndroidVideoRendererControl::QAndroidVideoRendererControl(QObject *parent) , m_surfaceTexture(0) , m_surfaceHolder(0) , m_externalTex(0) + , m_textureReadyCallback(0) + , m_textureReadyContext(0) { } @@ -177,42 +180,66 @@ void QAndroidVideoRendererControl::setSurface(QAbstractVideoSurface *surface) if (surface == m_surface) return; - if (m_surface && m_surface->isActive()) + if (m_surface && m_surface->isActive()) { m_surface->stop(); + m_surface->removeEventFilter(this); + } m_surface = surface; - if (m_surface) + if (m_surface) { m_useImage = !m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).contains(QVideoFrame::Format_BGR32); + m_surface->installEventFilter(this); + } } -jobject QAndroidVideoRendererControl::surfaceHolder() +bool QAndroidVideoRendererControl::isTextureReady() +{ + return QOpenGLContext::currentContext() || (m_surface && m_surface->property("GLContext").isValid()); +} + +void QAndroidVideoRendererControl::setTextureReadyCallback(TextureReadyCallback cb, void *context) +{ + m_textureReadyCallback = cb; + m_textureReadyContext = context; +} + +bool QAndroidVideoRendererControl::initSurfaceTexture() { - if (m_surfaceHolder) - return m_surfaceHolder->object(); + if (m_surfaceTexture) + return true; + + if (!m_surface) + return false; QOpenGLContext *currContext = QOpenGLContext::currentContext(); // If we don't have a GL context in the current thread, create one and share it // with the render thread GL context if (!currContext && !m_glContext) { + QOpenGLContext *shareContext = qobject_cast(m_surface->property("GLContext").value()); + if (!shareContext) + return false; + m_offscreenSurface = new QOffscreenSurface; QSurfaceFormat format; format.setSwapBehavior(QSurfaceFormat::SingleBuffer); m_offscreenSurface->setFormat(format); m_offscreenSurface->create(); - QOpenGLContext *shareContext = 0; - if (m_surface) - shareContext = qobject_cast(m_surface->property("GLContext").value()); m_glContext = new QOpenGLContext; m_glContext->setFormat(m_offscreenSurface->requestedFormat()); if (shareContext) m_glContext->setShareContext(shareContext); - if (!m_glContext->create()) - return 0; + if (!m_glContext->create()) { + delete m_glContext; + m_glContext = 0; + delete m_offscreenSurface; + m_offscreenSurface = 0; + return false; + } // if sharing contexts is not supported, fallback to image rendering and send the bits // to the video surface @@ -228,7 +255,21 @@ jobject QAndroidVideoRendererControl::surfaceHolder() if (m_surfaceTexture->isValid()) { connect(m_surfaceTexture, SIGNAL(frameAvailable()), this, SLOT(onFrameAvailable())); + } else { + delete m_surfaceTexture; + m_surfaceTexture = 0; + glDeleteTextures(1, &m_externalTex); + } + return m_surfaceTexture != 0; +} + +jobject QAndroidVideoRendererControl::surfaceHolder() +{ + if (!initSurfaceTexture()) + return 0; + + if (!m_surfaceHolder) { QJNILocalRef surfaceTex = m_surfaceTexture->surfaceTexture(); m_androidSurface = new QJNIObject("android/view/Surface", @@ -236,16 +277,9 @@ jobject QAndroidVideoRendererControl::surfaceHolder() surfaceTex.object()); m_surfaceHolder = new JSurfaceTextureHolder(m_androidSurface->object()); - } else { - delete m_surfaceTexture; - m_surfaceTexture = 0; - glDeleteTextures(1, &m_externalTex); } - if (m_surfaceHolder) - return m_surfaceHolder->object(); - - return 0; + return m_surfaceHolder->object(); } void QAndroidVideoRendererControl::setVideoSize(const QSize &size) @@ -373,4 +407,18 @@ void QAndroidVideoRendererControl::createGLResources() } } +bool QAndroidVideoRendererControl::eventFilter(QObject *, QEvent *e) +{ + if (e->type() == QEvent::DynamicPropertyChange) { + QDynamicPropertyChangeEvent *event = static_cast(e); + if (event->propertyName() == "GLContext" && m_textureReadyCallback) { + m_textureReadyCallback(m_textureReadyContext); + m_textureReadyCallback = 0; + m_textureReadyContext = 0; + } + } + + return false; +} + QT_END_NAMESPACE diff --git a/src/plugins/android/mediaplayer/qandroidvideorendercontrol.h b/src/plugins/android/mediaplayer/qandroidvideorendercontrol.h index 525291e1f..cd935502c 100644 --- a/src/plugins/android/mediaplayer/qandroidvideorendercontrol.h +++ b/src/plugins/android/mediaplayer/qandroidvideorendercontrol.h @@ -65,14 +65,18 @@ public: void setSurface(QAbstractVideoSurface *surface) Q_DECL_OVERRIDE; jobject surfaceHolder() Q_DECL_OVERRIDE; + bool isTextureReady() Q_DECL_OVERRIDE; + void setTextureReadyCallback(TextureReadyCallback cb, void *context = 0) Q_DECL_OVERRIDE; void setVideoSize(const QSize &size) Q_DECL_OVERRIDE; void stop() Q_DECL_OVERRIDE; + bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; + private Q_SLOTS: void onFrameAvailable(); private: - void setupSurface(); + bool initSurfaceTexture(); void renderFrameToFbo(); void createGLResources(); @@ -88,6 +92,9 @@ private: JSurfaceTexture *m_surfaceTexture; JSurfaceTextureHolder *m_surfaceHolder; uint m_externalTex; + + TextureReadyCallback m_textureReadyCallback; + void *m_textureReadyContext; }; QT_END_NAMESPACE -- cgit v1.2.3 From 6c941c6c2b547c8c1f5dab5310f165e0d796fe96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Wed, 29 May 2013 02:06:16 +0200 Subject: Android: Make it possible for MediaPlayer to read from assets. The Android MediaPlayer doesn't handle assets automatically, so we need to open it and pass it in as a file descriptor. Task-number: QTBUG-31422 Change-Id: Ic29c0ab6348d760cf21aa89ae423d41e15523976 Reviewed-by: Yoann Lopes --- .../qt5/android/multimedia/QtAndroidMediaPlayer.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java index e4dbae632..d1abf658e 100644 --- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java +++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java @@ -50,6 +50,9 @@ import android.content.Context; import android.media.MediaPlayer; import android.net.Uri; import android.util.Log; +import java.io.FileDescriptor; +import android.content.res.AssetFileDescriptor; +import android.content.res.AssetManager; public class QtAndroidMediaPlayer extends MediaPlayer { @@ -335,7 +338,17 @@ public class QtAndroidMediaPlayer extends MediaPlayer mPreparing = true; onMediaPlayerInfoNative(MEDIA_PLAYER_PREPARING, 0, mID); mUri = Uri.parse(path); - setDataSource(mApplicationContext, mUri); + if (mUri.getScheme().compareTo("assets") == 0) { + final String asset = mUri.getPath().substring(1 /* Remove first '/' */); + final AssetManager am = mApplicationContext.getAssets(); + final AssetFileDescriptor afd = am.openFd(asset); + final long offset = afd.getStartOffset(); + final long length = afd.getLength(); + FileDescriptor fd = afd.getFileDescriptor(); + setDataSource(fd, offset, length); + } else { + setDataSource(mApplicationContext, mUri); + } mInitialized = true; setOnPreparedListener(new MediaPlayerPreparedListener()); prepareAsync(); -- cgit v1.2.3 From e15a2b92b6120a119cf218ab0f0630f23bc45ba5 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 5 Jul 2013 16:39:25 +0200 Subject: Android: removed unnecessary init class for QtMultimedia.jar Change-Id: Ib13597389a3896da8b619993d197623e7c74a7e0 Reviewed-by: Christian Stromme --- src/multimedia/multimedia.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro index f04bbd326..96b9e79ec 100644 --- a/src/multimedia/multimedia.pro +++ b/src/multimedia/multimedia.pro @@ -52,9 +52,9 @@ include(recording/recording.pri) include(video/video.pri) ANDROID_BUNDLED_JAR_DEPENDENCIES = \ - jar/QtMultimedia-bundled.jar:org.qtproject.qt5.android.multimedia.QtAndroidMediaPlayer + jar/QtMultimedia-bundled.jar ANDROID_JAR_DEPENDENCIES = \ - jar/QtMultimedia.jar:org.qtproject.qt5.android.multimedia.QtAndroidMediaPlayer + jar/QtMultimedia.jar ANDROID_LIB_DEPENDENCIES = \ plugins/mediaservice/libandroidmediaplayer.so \ lib/libQt5MultimediaQuick_p.so:Qt5Quick -- cgit v1.2.3