summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/android/android.pro3
-rw-r--r--src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java17
-rw-r--r--src/plugins/android/src/common/qandroidmultimediautils.cpp25
-rw-r--r--src/plugins/android/src/common/qandroidmultimediautils.h2
-rw-r--r--src/plugins/android/src/common/qandroidvideooutput.h18
-rw-r--r--src/plugins/android/src/common/qandroidvideorendercontrol.cpp300
-rw-r--r--src/plugins/android/src/common/qandroidvideorendercontrol.h36
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.cpp63
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.h9
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcaptureservice.h2
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcapturesession.cpp39
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcapturesession.h3
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp18
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h4
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaservice.h3
-rw-r--r--src/plugins/android/src/wrappers/jcamera.cpp37
-rw-r--r--src/plugins/android/src/wrappers/jcamera.h17
-rw-r--r--src/plugins/android/src/wrappers/jsurfacetexture.h1
-rw-r--r--src/plugins/android/videonode/android_videonode.json3
-rw-r--r--src/plugins/android/videonode/qandroidsgvideonode.cpp204
-rw-r--r--src/plugins/android/videonode/qandroidsgvideonode.h67
-rw-r--r--src/plugins/android/videonode/qandroidsgvideonodeplugin.cpp69
-rw-r--r--src/plugins/android/videonode/qandroidsgvideonodeplugin.h62
-rw-r--r--src/plugins/android/videonode/videonode.pro16
-rw-r--r--src/plugins/audiocapture/audiocaptureprobecontrol.cpp4
-rw-r--r--src/plugins/audiocapture/audiocaptureprobecontrol.h4
-rw-r--r--src/plugins/audiocapture/audiocaptureservice.cpp4
-rw-r--r--src/plugins/audiocapture/audiocaptureservice.h6
-rw-r--r--src/plugins/audiocapture/audiocaptureserviceplugin.cpp2
-rw-r--r--src/plugins/audiocapture/audiocaptureserviceplugin.h4
-rw-r--r--src/plugins/audiocapture/audiocapturesession.cpp322
-rw-r--r--src/plugins/audiocapture/audiocapturesession.h48
-rw-r--r--src/plugins/audiocapture/audiocontainercontrol.cpp16
-rw-r--r--src/plugins/audiocapture/audiocontainercontrol.h6
-rw-r--r--src/plugins/audiocapture/audioencodercontrol.cpp127
-rw-r--r--src/plugins/audiocapture/audioencodercontrol.h10
-rw-r--r--src/plugins/audiocapture/audioinputselector.cpp5
-rw-r--r--src/plugins/audiocapture/audioinputselector.h6
-rw-r--r--src/plugins/audiocapture/audiomediarecordercontrol.cpp72
-rw-r--r--src/plugins/audiocapture/audiomediarecordercontrol.h15
-rw-r--r--src/plugins/blackberry/bbserviceplugin.cpp6
-rw-r--r--src/plugins/blackberry/blackberry.pro4
-rw-r--r--src/plugins/blackberry/camera/bbcameraexposurecontrol.cpp4
-rw-r--r--src/plugins/blackberry/camera/bbcameramediarecordercontrol.cpp13
-rw-r--r--src/plugins/blackberry/camera/bbcameraorientationhandler.cpp2
-rw-r--r--src/plugins/blackberry/camera/bbcamerasession.cpp33
-rw-r--r--src/plugins/blackberry/camera/bbcameraviewfindersettingscontrol.cpp2
-rw-r--r--src/plugins/blackberry/camera/camera.pri6
-rw-r--r--src/plugins/directshow/player/directshowmetadatacontrol.cpp400
-rw-r--r--src/plugins/directshow/player/directshowmetadatacontrol.h15
-rw-r--r--src/plugins/directshow/player/directshowplayerservice.cpp19
-rw-r--r--src/plugins/directshow/player/player.pri6
-rw-r--r--src/plugins/plugins.pro2
53 files changed, 1434 insertions, 747 deletions
diff --git a/src/plugins/android/android.pro b/src/plugins/android/android.pro
index 288ae8528..807f8ece8 100644
--- a/src/plugins/android/android.pro
+++ b/src/plugins/android/android.pro
@@ -3,3 +3,6 @@ TEMPLATE = subdirs
SUBDIRS += src \
jar
+qtHaveModule(quick) {
+ SUBDIRS += videonode
+}
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java
index b0a4954cf..3d891196f 100644
--- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java
@@ -45,7 +45,10 @@ import android.hardware.Camera;
import android.graphics.SurfaceTexture;
import android.util.Log;
-public class QtCamera implements Camera.ShutterCallback, Camera.PictureCallback, Camera.AutoFocusCallback
+public class QtCamera implements Camera.ShutterCallback,
+ Camera.PictureCallback,
+ Camera.AutoFocusCallback,
+ Camera.PreviewCallback
{
private int m_cameraId = -1;
private Camera m_camera = null;
@@ -149,6 +152,11 @@ public class QtCamera implements Camera.ShutterCallback, Camera.PictureCallback,
m_camera.cancelAutoFocus();
}
+ public void requestPreviewFrame()
+ {
+ m_camera.setOneShotPreviewCallback(this);
+ }
+
public void takePicture()
{
try {
@@ -171,6 +179,12 @@ public class QtCamera implements Camera.ShutterCallback, Camera.PictureCallback,
}
@Override
+ public void onPreviewFrame(byte[] data, Camera camera)
+ {
+ notifyPreviewFrame(m_cameraId, data);
+ }
+
+ @Override
public void onAutoFocus(boolean success, Camera camera)
{
notifyAutoFocusComplete(m_cameraId, success);
@@ -179,4 +193,5 @@ public class QtCamera implements Camera.ShutterCallback, Camera.PictureCallback,
private static native void notifyAutoFocusComplete(int id, boolean success);
private static native void notifyPictureExposed(int id);
private static native void notifyPictureCaptured(int id, byte[] data);
+ private static native void notifyPreviewFrame(int id, byte[] data);
}
diff --git a/src/plugins/android/src/common/qandroidmultimediautils.cpp b/src/plugins/android/src/common/qandroidmultimediautils.cpp
index 7ae40358f..9bf38a869 100644
--- a/src/plugins/android/src/common/qandroidmultimediautils.cpp
+++ b/src/plugins/android/src/common/qandroidmultimediautils.cpp
@@ -76,4 +76,29 @@ bool qt_sizeLessThan(const QSize &s1, const QSize &s2)
return s1.width() * s1.height() < s2.width() * s2.height();
}
+void qt_convert_NV21_to_ARGB32(const uchar *yuv, quint32 *rgb, int width, int height)
+{
+ const int frameSize = width * height;
+
+ int a = 0;
+ for (int i = 0, ci = 0; i < height; ++i, ci += 1) {
+ for (int j = 0, cj = 0; j < width; ++j, cj += 1) {
+ int y = (0xff & ((int) yuv[ci * width + cj]));
+ int v = (0xff & ((int) yuv[frameSize + (ci >> 1) * width + (cj & ~1) + 0]));
+ int u = (0xff & ((int) yuv[frameSize + (ci >> 1) * width + (cj & ~1) + 1]));
+ y = y < 16 ? 16 : y;
+
+ int r = (int) (1.164f * (y - 16) + 1.596f * (v - 128));
+ int g = (int) (1.164f * (y - 16) - 0.813f * (v - 128) - 0.391f * (u - 128));
+ int b = (int) (1.164f * (y - 16) + 2.018f * (u - 128));
+
+ r = qBound(0, r, 255);
+ g = qBound(0, g, 255);
+ b = qBound(0, b, 255);
+
+ rgb[a++] = 0xff000000 | (r << 16) | (g << 8) | b;
+ }
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/common/qandroidmultimediautils.h b/src/plugins/android/src/common/qandroidmultimediautils.h
index 1996209b0..792ab06db 100644
--- a/src/plugins/android/src/common/qandroidmultimediautils.h
+++ b/src/plugins/android/src/common/qandroidmultimediautils.h
@@ -53,6 +53,8 @@ int qt_findClosestValue(const QList<int> &list, int value);
bool qt_sizeLessThan(const QSize &s1, const QSize &s2);
+void qt_convert_NV21_to_ARGB32(const uchar *yuv, quint32 *rgb, int width, int height);
+
QT_END_NAMESPACE
#endif // QANDROIDMULTIMEDIAUTILS_H
diff --git a/src/plugins/android/src/common/qandroidvideooutput.h b/src/plugins/android/src/common/qandroidvideooutput.h
index 8110b67b0..6e4a32e3f 100644
--- a/src/plugins/android/src/common/qandroidvideooutput.h
+++ b/src/plugins/android/src/common/qandroidvideooutput.h
@@ -48,26 +48,26 @@
QT_BEGIN_NAMESPACE
-typedef void (*TextureReadyCallback)(void*);
-
class QAndroidVideoOutput
{
public:
- QAndroidVideoOutput() { }
virtual ~QAndroidVideoOutput() { }
virtual jobject surfaceHolder() = 0;
+ virtual jobject surfaceTexture() { return 0; }
- virtual bool isTextureReady() = 0;
- virtual void setTextureReadyCallback(TextureReadyCallback cb, void *context = 0) = 0;
- virtual jobject surfaceTexture() = 0;
+ virtual bool isReady() { return true; }
- virtual void setVideoSize(const QSize &size) = 0;
- virtual void stop() = 0;
+ virtual void setVideoSize(const QSize &) { }
+ virtual void stop() { }
- virtual QImage toImage() = 0;
+ // signals:
+ // void readyChanged(bool);
};
+#define QAndroidVideoOutput_iid "org.qt-project.qt.qandroidvideooutput/5.0"
+Q_DECLARE_INTERFACE(QAndroidVideoOutput, QAndroidVideoOutput_iid)
+
QT_END_NAMESPACE
#endif // QANDROIDVIDEOOUTPUT_H
diff --git a/src/plugins/android/src/common/qandroidvideorendercontrol.cpp b/src/plugins/android/src/common/qandroidvideorendercontrol.cpp
index 0eb8d172f..5306fe918 100644
--- a/src/plugins/android/src/common/qandroidvideorendercontrol.cpp
+++ b/src/plugins/android/src/common/qandroidvideorendercontrol.cpp
@@ -44,39 +44,31 @@
#include <QtCore/private/qjni_p.h>
#include "jsurfacetextureholder.h"
#include <QAbstractVideoSurface>
-#include <QOpenGLContext>
-#include <QOffscreenSurface>
-#include <QOpenGLFramebufferObject>
#include <QVideoSurfaceFormat>
-#include <QOpenGLFunctions>
-#include <QOpenGLShaderProgram>
#include <qevent.h>
+#include <qcoreapplication.h>
+#include <qopenglcontext.h>
+#include <qopenglfunctions.h>
QT_BEGIN_NAMESPACE
-static const GLfloat g_vertex_data[] = {
- -1.f, 1.f,
- 1.f, 1.f,
- 1.f, -1.f,
- -1.f, -1.f
-};
+#define ExternalGLTextureHandle QAbstractVideoBuffer::HandleType(QAbstractVideoBuffer::UserHandle + 1)
-static const GLfloat g_texture_data[] = {
- 0.f, 0.f,
- 1.f, 0.f,
- 1.f, 1.f,
- 0.f, 1.f
-};
+TextureDeleter::~TextureDeleter()
+{
+ glDeleteTextures(1, &m_id);
+}
-class TextureVideoBuffer : public QAbstractVideoBuffer
+class AndroidTextureVideoBuffer : public QAbstractVideoBuffer
{
public:
- TextureVideoBuffer(GLuint textureId)
- : QAbstractVideoBuffer(GLTextureHandle)
- , m_textureId(textureId)
- {}
+ AndroidTextureVideoBuffer(JSurfaceTexture *surface)
+ : QAbstractVideoBuffer(ExternalGLTextureHandle)
+ , m_surfaceTexture(surface)
+ {
+ }
- virtual ~TextureVideoBuffer() {}
+ virtual ~AndroidTextureVideoBuffer() {}
MapMode mapMode() const { return NotMapped; }
uchar *map(MapMode, int*, int*) { return 0; }
@@ -84,67 +76,33 @@ public:
QVariant handle() const
{
- return QVariant::fromValue<unsigned int>(m_textureId);
- }
-
-private:
- GLuint m_textureId;
-};
-
-class ImageVideoBuffer : public QAbstractVideoBuffer
-{
-public:
- ImageVideoBuffer(const QImage &image)
- : QAbstractVideoBuffer(NoHandle)
- , m_image(image)
- , m_mode(NotMapped)
- {
-
- }
-
- MapMode mapMode() const { return m_mode; }
- uchar *map(MapMode mode, int *, int *)
- {
- if (mode != NotMapped && m_mode == NotMapped) {
- m_mode = mode;
- return m_image.bits();
+ if (m_data.isEmpty()) {
+ // update the video texture (called from the render thread)
+ m_surfaceTexture->updateTexImage();
+ m_data << (uint)m_surfaceTexture->textureID() << m_surfaceTexture->getTransformMatrix();
}
- return 0;
- }
-
- void unmap()
- {
- m_mode = NotMapped;
+ return m_data;
}
private:
- QImage m_image;
- MapMode m_mode;
+ mutable JSurfaceTexture *m_surfaceTexture;
+ mutable QVariantList m_data;
};
QAndroidVideoRendererControl::QAndroidVideoRendererControl(QObject *parent)
: QVideoRendererControl(parent)
, m_surface(0)
- , m_offscreenSurface(0)
- , m_glContext(0)
- , m_fbo(0)
- , m_program(0)
- , m_useImage(false)
, m_androidSurface(0)
, m_surfaceTexture(0)
, m_surfaceHolder(0)
, m_externalTex(0)
- , m_textureReadyCallback(0)
- , m_textureReadyContext(0)
+ , m_textureDeleter(0)
{
}
QAndroidVideoRendererControl::~QAndroidVideoRendererControl()
{
- if (m_glContext)
- m_glContext->makeCurrent(m_offscreenSurface);
-
if (m_surfaceTexture) {
m_surfaceTexture->callMethod<void>("release");
delete m_surfaceTexture;
@@ -159,13 +117,8 @@ QAndroidVideoRendererControl::~QAndroidVideoRendererControl()
delete m_surfaceHolder;
m_surfaceHolder = 0;
}
- if (m_externalTex)
- glDeleteTextures(1, &m_externalTex);
-
- delete m_fbo;
- delete m_program;
- delete m_glContext;
- delete m_offscreenSurface;
+ if (m_textureDeleter)
+ m_textureDeleter->deleteLater();
}
QAbstractVideoSurface *QAndroidVideoRendererControl::surface() const
@@ -178,28 +131,23 @@ void QAndroidVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
if (surface == m_surface)
return;
- if (m_surface && m_surface->isActive()) {
- m_surface->stop();
- m_surface->removeEventFilter(this);
+ if (m_surface) {
+ if (m_surface->isActive())
+ m_surface->stop();
+ m_surface->setProperty("_q_GLThreadCallback", QVariant());
}
m_surface = surface;
if (m_surface) {
- m_useImage = !m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).contains(QVideoFrame::Format_BGR32);
- m_surface->installEventFilter(this);
+ m_surface->setProperty("_q_GLThreadCallback",
+ QVariant::fromValue<QObject*>(this));
}
}
-bool QAndroidVideoRendererControl::isTextureReady()
-{
- return QOpenGLContext::currentContext() || (m_surface && m_surface->property("GLContext").isValid());
-}
-
-void QAndroidVideoRendererControl::setTextureReadyCallback(TextureReadyCallback cb, void *context)
+bool QAndroidVideoRendererControl::isReady()
{
- m_textureReadyCallback = cb;
- m_textureReadyContext = context;
+ return QOpenGLContext::currentContext() || m_externalTex;
}
bool QAndroidVideoRendererControl::initSurfaceTexture()
@@ -210,45 +158,15 @@ bool QAndroidVideoRendererControl::initSurfaceTexture()
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<QOpenGLContext*>(m_surface->property("GLContext").value<QObject*>());
- if (!shareContext)
- return false;
-
- m_offscreenSurface = new QOffscreenSurface;
- QSurfaceFormat format;
- format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
- m_offscreenSurface->setFormat(format);
- m_offscreenSurface->create();
-
- m_glContext = new QOpenGLContext;
- m_glContext->setFormat(m_offscreenSurface->requestedFormat());
-
- if (shareContext)
- m_glContext->setShareContext(shareContext);
-
- 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
- if (!m_glContext->shareContext())
- m_useImage = true;
+ // if we have an OpenGL context in the current thread, create a texture. Otherwise, wait
+ // for the GL render thread to call us back to do it.
+ if (QOpenGLContext::currentContext()) {
+ glGenTextures(1, &m_externalTex);
+ m_textureDeleter = new TextureDeleter(m_externalTex);
+ } else if (!m_externalTex) {
+ return false;
}
- if (m_glContext)
- m_glContext->makeCurrent(m_offscreenSurface);
-
- glGenTextures(1, &m_externalTex);
m_surfaceTexture = new JSurfaceTexture(m_externalTex);
if (m_surfaceTexture->isValid()) {
@@ -256,7 +174,9 @@ bool QAndroidVideoRendererControl::initSurfaceTexture()
} else {
delete m_surfaceTexture;
m_surfaceTexture = 0;
- glDeleteTextures(1, &m_externalTex);
+ m_textureDeleter->deleteLater();
+ m_externalTex = 0;
+ m_textureDeleter = 0;
}
return m_surfaceTexture != 0;
@@ -294,9 +214,6 @@ void QAndroidVideoRendererControl::setVideoSize(const QSize &size)
stop();
m_nativeSize = size;
-
- delete m_fbo;
- m_fbo = 0;
}
void QAndroidVideoRendererControl::stop()
@@ -306,133 +223,40 @@ void QAndroidVideoRendererControl::stop()
m_nativeSize = QSize();
}
-QImage QAndroidVideoRendererControl::toImage()
-{
- if (!m_fbo)
- return QImage();
-
- return m_fbo->toImage().mirrored();
-}
-
void QAndroidVideoRendererControl::onFrameAvailable()
{
- if (m_glContext)
- m_glContext->makeCurrent(m_offscreenSurface);
-
- m_surfaceTexture->updateTexImage();
-
- if (!m_nativeSize.isValid())
+ if (!m_nativeSize.isValid() || !m_surface)
return;
- renderFrameToFbo();
+ QAbstractVideoBuffer *buffer = new AndroidTextureVideoBuffer(m_surfaceTexture);
+ QVideoFrame frame(buffer, m_nativeSize, QVideoFrame::Format_BGR32);
- QAbstractVideoBuffer *buffer = 0;
- QVideoFrame frame;
-
- if (m_useImage) {
- buffer = new ImageVideoBuffer(m_fbo->toImage().mirrored());
- frame = QVideoFrame(buffer, m_nativeSize, QVideoFrame::Format_RGB32);
- } else {
- buffer = new TextureVideoBuffer(m_fbo->texture());
- frame = QVideoFrame(buffer, m_nativeSize, QVideoFrame::Format_BGR32);
+ if (m_surface->isActive() && (m_surface->surfaceFormat().pixelFormat() != frame.pixelFormat()
+ || m_surface->nativeResolution() != frame.size())) {
+ m_surface->stop();
}
- if (m_surface && frame.isValid()) {
- if (m_surface->isActive() && (m_surface->surfaceFormat().pixelFormat() != frame.pixelFormat()
- || m_surface->nativeResolution() != frame.size())) {
- m_surface->stop();
- }
-
- if (!m_surface->isActive()) {
- QVideoSurfaceFormat format(frame.size(), frame.pixelFormat(),
- m_useImage ? QAbstractVideoBuffer::NoHandle
- : QAbstractVideoBuffer::GLTextureHandle);
-
- m_surface->start(format);
- }
+ if (!m_surface->isActive()) {
+ QVideoSurfaceFormat format(frame.size(), frame.pixelFormat(), ExternalGLTextureHandle);
+ format.setScanLineDirection(QVideoSurfaceFormat::BottomToTop);
- if (m_surface->isActive())
- m_surface->present(frame);
+ m_surface->start(format);
}
-}
-
-void QAndroidVideoRendererControl::renderFrameToFbo()
-{
- createGLResources();
-
- m_fbo->bind();
-
- glViewport(0, 0, m_nativeSize.width(), m_nativeSize.height());
-
- m_program->bind();
- m_program->enableAttributeArray(0);
- m_program->enableAttributeArray(1);
- m_program->setUniformValue("frameTexture", GLuint(0));
- m_program->setUniformValue("texMatrix", m_surfaceTexture->getTransformMatrix());
-
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, g_vertex_data);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, g_texture_data);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
- m_program->disableAttributeArray(0);
- m_program->disableAttributeArray(1);
- m_program->release();
-
- glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
- m_fbo->release();
-
- glFinish();
-}
-
-void QAndroidVideoRendererControl::createGLResources()
-{
- if (!m_fbo)
- m_fbo = new QOpenGLFramebufferObject(m_nativeSize);
-
- if (!m_program) {
- m_program = new QOpenGLShaderProgram;
-
- QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_program);
- vertexShader->compileSourceCode("attribute highp vec4 vertexCoordsArray; \n" \
- "attribute highp vec2 textureCoordArray; \n" \
- "uniform highp mat4 texMatrix; \n" \
- "varying highp vec2 textureCoords; \n" \
- "void main(void) \n" \
- "{ \n" \
- " gl_Position = vertexCoordsArray; \n" \
- " textureCoords = (texMatrix * vec4(textureCoordArray, 0.0, 1.0)).xy; \n" \
- "}\n");
- m_program->addShader(vertexShader);
-
- QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_program);
- fragmentShader->compileSourceCode("#extension GL_OES_EGL_image_external : require \n" \
- "varying highp vec2 textureCoords; \n" \
- "uniform samplerExternalOES frameTexture; \n" \
- "void main() \n" \
- "{ \n" \
- " gl_FragColor = texture2D(frameTexture, textureCoords); \n" \
- "}\n");
- m_program->addShader(fragmentShader);
-
- m_program->bindAttributeLocation("vertexCoordsArray", 0);
- m_program->bindAttributeLocation("textureCoordArray", 1);
- m_program->link();
- }
+ if (m_surface->isActive())
+ m_surface->present(frame);
}
-bool QAndroidVideoRendererControl::eventFilter(QObject *, QEvent *e)
+void QAndroidVideoRendererControl::customEvent(QEvent *e)
{
- if (e->type() == QEvent::DynamicPropertyChange) {
- QDynamicPropertyChangeEvent *event = static_cast<QDynamicPropertyChangeEvent*>(e);
- if (event->propertyName() == "GLContext" && m_textureReadyCallback) {
- m_textureReadyCallback(m_textureReadyContext);
- m_textureReadyCallback = 0;
- m_textureReadyContext = 0;
+ if (e->type() == QEvent::User) {
+ // This is running in the render thread (OpenGL enabled)
+ if (!m_externalTex) {
+ glGenTextures(1, &m_externalTex);
+ m_textureDeleter = new TextureDeleter(m_externalTex); // will be deleted in the correct thread
+ emit readyChanged(true);
}
}
-
- return false;
}
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/common/qandroidvideorendercontrol.h b/src/plugins/android/src/common/qandroidvideorendercontrol.h
index 25220310e..5d9130c07 100644
--- a/src/plugins/android/src/common/qandroidvideorendercontrol.h
+++ b/src/plugins/android/src/common/qandroidvideorendercontrol.h
@@ -48,15 +48,23 @@
QT_BEGIN_NAMESPACE
-class QOpenGLContext;
-class QOffscreenSurface;
-class QOpenGLFramebufferObject;
-class QOpenGLShaderProgram;
class JSurfaceTextureHolder;
+class TextureDeleter : public QObject
+{
+ Q_OBJECT
+public:
+ TextureDeleter(uint id) : m_id(id) { }
+ ~TextureDeleter();
+
+private:
+ uint m_id;
+};
+
class QAndroidVideoRendererControl : public QVideoRendererControl, public QAndroidVideoOutput
{
Q_OBJECT
+ Q_INTERFACES(QAndroidVideoOutput)
public:
explicit QAndroidVideoRendererControl(QObject *parent = 0);
~QAndroidVideoRendererControl() Q_DECL_OVERRIDE;
@@ -65,38 +73,30 @@ 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;
jobject surfaceTexture() Q_DECL_OVERRIDE;
+ bool isReady() Q_DECL_OVERRIDE;
void setVideoSize(const QSize &size) Q_DECL_OVERRIDE;
void stop() Q_DECL_OVERRIDE;
- QImage toImage() Q_DECL_OVERRIDE;
- bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE;
+ void customEvent(QEvent *) Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void readyChanged(bool);
private Q_SLOTS:
void onFrameAvailable();
private:
bool initSurfaceTexture();
- void renderFrameToFbo();
- void createGLResources();
QAbstractVideoSurface *m_surface;
- QOffscreenSurface *m_offscreenSurface;
- QOpenGLContext *m_glContext;
- QOpenGLFramebufferObject *m_fbo;
- QOpenGLShaderProgram *m_program;
- bool m_useImage;
QSize m_nativeSize;
QJNIObjectPrivate *m_androidSurface;
JSurfaceTexture *m_surfaceTexture;
JSurfaceTextureHolder *m_surfaceHolder;
uint m_externalTex;
-
- TextureReadyCallback m_textureReadyCallback;
- void *m_textureReadyContext;
+ TextureDeleter *m_textureDeleter;
};
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
index 761b716d1..3ee700bf4 100644
--- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
@@ -52,12 +52,6 @@
QT_BEGIN_NAMESPACE
-static void textureReadyCallback(void *context)
-{
- if (context)
- reinterpret_cast<QAndroidCameraSession *>(context)->onSurfaceTextureReady();
-}
-
QAndroidCameraSession::QAndroidCameraSession(QObject *parent)
: QObject(parent)
, m_selectedCamera(0)
@@ -153,8 +147,11 @@ bool QAndroidCameraSession::open()
if (m_camera) {
connect(m_camera, SIGNAL(pictureExposed()), this, SLOT(onCameraPictureExposed()));
connect(m_camera, SIGNAL(pictureCaptured(QByteArray)), this, SLOT(onCameraPictureCaptured(QByteArray)));
+ connect(m_camera, SIGNAL(previewFrameAvailable(QByteArray)), this, SLOT(onCameraPreviewFrameAvailable(QByteArray)));
m_nativeOrientation = m_camera->getNativeOrientation();
m_status = QCamera::LoadedStatus;
+ if (m_camera->getPreviewFormat() != JCamera::NV21)
+ m_camera->setPreviewFormat(JCamera::NV21);
emit opened();
} else {
m_status = QCamera::UnavailableStatus;
@@ -188,12 +185,17 @@ void QAndroidCameraSession::close()
emit statusChanged(m_status);
}
-void QAndroidCameraSession::setVideoPreview(QAndroidVideoOutput *videoOutput)
+void QAndroidCameraSession::setVideoPreview(QObject *videoOutput)
{
if (m_videoOutput)
m_videoOutput->stop();
- m_videoOutput = videoOutput;
+ if (videoOutput) {
+ connect(videoOutput, SIGNAL(readyChanged(bool)), this, SLOT(onVideoOutputReady(bool)));
+ m_videoOutput = qobject_cast<QAndroidVideoOutput *>(videoOutput);
+ } else {
+ m_videoOutput = 0;
+ }
}
void QAndroidCameraSession::adjustViewfinderSize(const QSize &captureSize, bool restartPreview)
@@ -243,12 +245,8 @@ void QAndroidCameraSession::startPreview()
applyImageSettings();
adjustViewfinderSize(m_imageSettings.resolution());
- if (m_videoOutput) {
- if (m_videoOutput->isTextureReady())
- m_camera->setPreviewTexture(m_videoOutput->surfaceTexture());
- else
- m_videoOutput->setTextureReadyCallback(textureReadyCallback, this);
- }
+ if (m_videoOutput && m_videoOutput->isReady())
+ onVideoOutputReady(true);
JMultimediaUtils::enableOrientationListener(true);
@@ -427,6 +425,7 @@ int QAndroidCameraSession::capture(const QString &fileName)
// adjust picture rotation depending on the device orientation
m_camera->setRotation(currentCameraRotation());
+ m_camera->requestPreviewFrame();
m_camera->takePicture();
} else {
emit imageCaptureError(m_lastImageCaptureId, QCameraImageCapture::NotSupportedFeatureError,
@@ -455,10 +454,6 @@ void QAndroidCameraSession::onCameraPictureExposed()
void QAndroidCameraSession::onCameraPictureCaptured(const QByteArray &data)
{
if (!m_captureCanceled) {
- // generate a preview from the viewport
- if (m_videoOutput)
- emit imageCaptured(m_currentImageCaptureId, m_videoOutput->toImage());
-
// Loading and saving the captured image can be slow, do it in a separate thread
QtConcurrent::run(this, &QAndroidCameraSession::processCapturedImage,
m_currentImageCaptureId,
@@ -522,9 +517,37 @@ void QAndroidCameraSession::processCapturedImage(int id,
}
}
-void QAndroidCameraSession::onSurfaceTextureReady()
+void QAndroidCameraSession::onCameraPreviewFrameAvailable(const QByteArray &data)
+{
+ if (m_captureCanceled || m_readyForCapture)
+ return;
+
+ QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage,
+ m_currentImageCaptureId,
+ data);
+}
+
+void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data)
+{
+ QSize frameSize = m_camera->previewSize();
+ QImage preview(frameSize, QImage::Format_ARGB32);
+ qt_convert_NV21_to_ARGB32((const uchar *)data.constData(),
+ (quint32 *)preview.bits(),
+ frameSize.width(),
+ frameSize.height());
+
+ // Preview display of front-facing cameras is flipped horizontally, but the frame data
+ // we get here is not. Flip it ourselves if the camera is front-facing to match what the user
+ // sees on the viewfinder.
+ if (m_camera->getFacing() == JCamera::CameraFacingFront)
+ preview = preview.transformed(QTransform().scale(-1, 1));
+
+ emit imageCaptured(id, preview);
+}
+
+void QAndroidCameraSession::onVideoOutputReady(bool ready)
{
- if (m_camera && m_videoOutput)
+ if (m_camera && m_videoOutput && ready)
m_camera->setPreviewTexture(m_videoOutput->surfaceTexture());
}
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.h b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
index f1cf44eec..de891522b 100644
--- a/src/plugins/android/src/mediacapture/qandroidcamerasession.h
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
@@ -71,7 +71,7 @@ public:
void setCaptureMode(QCamera::CaptureModes mode);
bool isCaptureModeSupported(QCamera::CaptureModes mode) const;
- void setVideoPreview(QAndroidVideoOutput *videoOutput);
+ void setVideoPreview(QObject *videoOutput);
void adjustViewfinderSize(const QSize &captureSize, bool restartPreview = true);
QImageEncoderSettings imageSettings() const { return m_imageSettings; }
@@ -88,8 +88,6 @@ public:
int capture(const QString &fileName);
void cancelCapture();
- void onSurfaceTextureReady();
-
int currentCameraRotation() const;
Q_SIGNALS:
@@ -110,10 +108,13 @@ Q_SIGNALS:
void imageCaptureError(int id, int error, const QString &errorString);
private Q_SLOTS:
+ void onVideoOutputReady(bool ready);
+
void onApplicationStateChanged(Qt::ApplicationState state);
void onCameraPictureExposed();
void onCameraPictureCaptured(const QByteArray &data);
+ void onCameraPreviewFrameAvailable(const QByteArray &data);
private:
bool open();
@@ -123,7 +124,7 @@ private:
void stopPreview();
void applyImageSettings();
- void processPreviewImage(int id);
+ void processPreviewImage(int id, const QByteArray &data);
void processCapturedImage(int id,
const QByteArray &data,
QCameraImageCapture::CaptureDestinations dest,
diff --git a/src/plugins/android/src/mediacapture/qandroidcaptureservice.h b/src/plugins/android/src/mediacapture/qandroidcaptureservice.h
index 71aaf2d64..4050622f2 100644
--- a/src/plugins/android/src/mediacapture/qandroidcaptureservice.h
+++ b/src/plugins/android/src/mediacapture/qandroidcaptureservice.h
@@ -88,7 +88,7 @@ private:
QAndroidVideoDeviceSelectorControl *m_videoInputControl;
QAndroidAudioInputSelectorControl *m_audioInputControl;
QAndroidCameraSession *m_cameraSession;
- QAndroidVideoRendererControl *m_videoRendererControl;
+ QMediaControl *m_videoRendererControl;
QAndroidCameraZoomControl *m_cameraZoomControl;
QAndroidCameraExposureControl *m_cameraExposureControl;
QAndroidCameraFlashControl *m_cameraFlashControl;
diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
index ec458eddb..3962baba8 100644
--- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
@@ -110,25 +110,27 @@ void QAndroidCaptureSession::setAudioInput(const QString &input)
QUrl QAndroidCaptureSession::outputLocation() const
{
- return m_outputLocation;
+ return m_actualOutputLocation;
}
bool QAndroidCaptureSession::setOutputLocation(const QUrl &location)
{
- if (m_outputLocation == location)
+ if (m_requestedOutputLocation == location)
return false;
- m_outputLocation = location;
+ m_actualOutputLocation = QUrl();
+ m_requestedOutputLocation = location;
- if (m_outputLocation.isEmpty())
+ if (m_requestedOutputLocation.isEmpty())
return true;
- if (m_outputLocation.isValid() && (m_outputLocation.isLocalFile() || m_outputLocation.isRelative())) {
- emit actualLocationChanged(m_outputLocation);
+ if (m_requestedOutputLocation.isValid()
+ && (m_requestedOutputLocation.isLocalFile() || m_requestedOutputLocation.isRelative())) {
+ emit actualLocationChanged(m_requestedOutputLocation);
return true;
}
- m_outputLocation = QUrl();
+ m_requestedOutputLocation = QUrl();
return false;
}
@@ -213,15 +215,18 @@ bool QAndroidCaptureSession::start()
// Set output file
- QString filePath = m_mediaStorageLocation.generateFileName(m_outputLocation.isLocalFile() ? m_outputLocation.toLocalFile()
- : m_outputLocation.toString(),
- m_cameraSession ? QAndroidMediaStorageLocation::Camera
- : QAndroidMediaStorageLocation::Audio,
- m_cameraSession ? QLatin1String("VID_")
- : QLatin1String("REC_"),
- m_containerFormat);
- m_outputLocation = QUrl::fromLocalFile(filePath);
- emit actualLocationChanged(m_outputLocation);
+ QString filePath = m_mediaStorageLocation.generateFileName(
+ m_requestedOutputLocation.isLocalFile() ? m_requestedOutputLocation.toLocalFile()
+ : m_requestedOutputLocation.toString(),
+ m_cameraSession ? QAndroidMediaStorageLocation::Camera
+ : QAndroidMediaStorageLocation::Audio,
+ m_cameraSession ? QLatin1String("VID_")
+ : QLatin1String("REC_"),
+ m_containerFormat);
+
+ m_actualOutputLocation = QUrl::fromLocalFile(filePath);
+ if (m_actualOutputLocation != m_requestedOutputLocation)
+ emit actualLocationChanged(m_actualOutputLocation);
m_mediaRecorder->setOutputFile(filePath);
@@ -280,7 +285,7 @@ void QAndroidCaptureSession::stop(bool error)
// if the media is saved into the standard media location, register it
// with the Android media scanner so it appears immediately in apps
// such as the gallery.
- QString mediaPath = m_outputLocation.toLocalFile();
+ QString mediaPath = m_actualOutputLocation.toLocalFile();
QString standardLoc = m_cameraSession ? JMultimediaUtils::getDefaultMediaDirectory(JMultimediaUtils::DCIM)
: JMultimediaUtils::getDefaultMediaDirectory(JMultimediaUtils::Sounds);
if (mediaPath.startsWith(standardLoc))
diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.h b/src/plugins/android/src/mediacapture/qandroidcapturesession.h
index 6d3645c13..fcd87cd02 100644
--- a/src/plugins/android/src/mediacapture/qandroidcapturesession.h
+++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.h
@@ -160,7 +160,8 @@ private:
QMediaRecorder::State m_state;
QMediaRecorder::Status m_status;
- QUrl m_outputLocation;
+ QUrl m_requestedOutputLocation;
+ QUrl m_actualOutputLocation;
CaptureProfile m_defaultSettings;
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
index 753c60662..3f3b599ac 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
@@ -45,12 +45,6 @@
QT_BEGIN_NAMESPACE
-static void textureReadyCallback(void *context)
-{
- if (context)
- reinterpret_cast<QAndroidMediaPlayerControl *>(context)->onSurfaceTextureReady();
-}
-
QAndroidMediaPlayerControl::QAndroidMediaPlayerControl(QObject *parent)
: QMediaPlayerControl(parent),
mMediaPlayer(new JMediaPlayer),
@@ -241,18 +235,18 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
setSeekable(true);
}
-void QAndroidMediaPlayerControl::setVideoOutput(QAndroidVideoOutput *videoOutput)
+void QAndroidMediaPlayerControl::setVideoOutput(QObject *videoOutput)
{
if (mVideoOutput)
mVideoOutput->stop();
- mVideoOutput = videoOutput;
+ mVideoOutput = qobject_cast<QAndroidVideoOutput *>(videoOutput);
if (mVideoOutput && !mMediaPlayer->display()) {
- if (mVideoOutput->isTextureReady())
+ if (mVideoOutput->isReady())
mMediaPlayer->setDisplay(mVideoOutput->surfaceHolder());
else
- mVideoOutput->setTextureReadyCallback(textureReadyCallback, this);
+ connect(videoOutput, SIGNAL(readyChanged(bool)), this, SLOT(onVideoOutputReady(bool)));
}
}
@@ -426,9 +420,9 @@ void QAndroidMediaPlayerControl::onVideoSizeChanged(qint32 width, qint32 height)
mVideoOutput->setVideoSize(mVideoSize);
}
-void QAndroidMediaPlayerControl::onSurfaceTextureReady()
+void QAndroidMediaPlayerControl::onVideoOutputReady(bool ready)
{
- if (!mMediaPlayer->display() && mVideoOutput) {
+ if (!mMediaPlayer->display() && mVideoOutput && ready) {
mMediaPlayer->setDisplay(mVideoOutput->surfaceHolder());
flushPendingStates();
}
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
index 93eced853..ef1d325e5 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
@@ -75,8 +75,7 @@ public:
const QIODevice *mediaStream() const Q_DECL_OVERRIDE;
void setMedia(const QMediaContent &mediaContent, QIODevice *stream) Q_DECL_OVERRIDE;
- void setVideoOutput(QAndroidVideoOutput *videoOutput);
- void onSurfaceTextureReady();
+ void setVideoOutput(QObject *videoOutput);
Q_SIGNALS:
void metaDataUpdated();
@@ -90,6 +89,7 @@ public Q_SLOTS:
void setMuted(bool muted) Q_DECL_OVERRIDE;
private Q_SLOTS:
+ void onVideoOutputReady(bool ready);
void onError(qint32 what, qint32 extra);
void onInfo(qint32 what, qint32 extra);
void onMediaPlayerInfo(qint32 what, qint32 extra);
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaservice.h b/src/plugins/android/src/mediaplayer/qandroidmediaservice.h
index 4d310e8e0..ba4b4ccd2 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaservice.h
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaservice.h
@@ -48,7 +48,6 @@ QT_BEGIN_NAMESPACE
class QAndroidMediaPlayerControl;
class QAndroidMetaDataReaderControl;
-class QAndroidVideoRendererControl;
class QAndroidMediaService : public QMediaService
{
@@ -63,7 +62,7 @@ public:
private:
QAndroidMediaPlayerControl *mMediaControl;
QAndroidMetaDataReaderControl *mMetadataControl;
- QAndroidVideoRendererControl *mVideoRendererControl;
+ QMediaControl *mVideoRendererControl;
};
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/wrappers/jcamera.cpp b/src/plugins/android/src/wrappers/jcamera.cpp
index f53fa4936..f858f4702 100644
--- a/src/plugins/android/src/wrappers/jcamera.cpp
+++ b/src/plugins/android/src/wrappers/jcamera.cpp
@@ -102,6 +102,18 @@ static void notifyPictureCaptured(JNIEnv *env, jobject, int id, jbyteArray data)
}
}
+static void notifyPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data)
+{
+ JCamera *obj = g_objectMap.value(id, 0);
+ if (obj) {
+ QByteArray bytes;
+ int arrayLength = env->GetArrayLength(data);
+ bytes.resize(arrayLength);
+ env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
+ Q_EMIT obj->previewFrameAvailable(bytes);
+ }
+}
+
JCamera::JCamera(int cameraId, jobject cam)
: QObject()
, QJNIObjectPrivate(cam)
@@ -225,6 +237,23 @@ QList<QSize> JCamera::getSupportedPreviewSizes()
return list;
}
+JCamera::ImageFormat JCamera::getPreviewFormat()
+{
+ if (!m_parameters.isValid())
+ return Unknown;
+
+ return JCamera::ImageFormat(m_parameters.callMethod<jint>("getPreviewFormat"));
+}
+
+void JCamera::setPreviewFormat(ImageFormat fmt)
+{
+ if (!m_parameters.isValid())
+ return;
+
+ m_parameters.callMethod<void>("setPreviewFormat", "(I)V", jint(fmt));
+ applyParameters();
+}
+
void JCamera::setPreviewSize(const QSize &size)
{
if (!m_parameters.isValid())
@@ -624,6 +653,11 @@ void JCamera::setJpegQuality(int quality)
applyParameters();
}
+void JCamera::requestPreviewFrame()
+{
+ callMethod<void>("requestPreviewFrame");
+}
+
void JCamera::takePicture()
{
callMethod<void>("takePicture");
@@ -672,7 +706,8 @@ QStringList JCamera::callStringListMethod(const char *methodName)
static JNINativeMethod methods[] = {
{"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete},
{"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed},
- {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured}
+ {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured},
+ {"notifyPreviewFrame", "(I[B)V", (void *)notifyPreviewFrame}
};
bool JCamera::initJNI(JNIEnv *env)
diff --git a/src/plugins/android/src/wrappers/jcamera.h b/src/plugins/android/src/wrappers/jcamera.h
index 0aea81f38..464ca3cb2 100644
--- a/src/plugins/android/src/wrappers/jcamera.h
+++ b/src/plugins/android/src/wrappers/jcamera.h
@@ -58,6 +58,16 @@ public:
CameraFacingFront = 1
};
+ enum ImageFormat { // same values as in android.graphics.ImageFormat Java class
+ Unknown = 0,
+ RGB565 = 4,
+ NV16 = 16,
+ NV21 = 17,
+ YUY2 = 20,
+ JPEG = 256,
+ YV12 = 842094169
+ };
+
~JCamera();
static JCamera *open(int cameraId);
@@ -75,6 +85,9 @@ public:
QSize getPreferredPreviewSizeForVideo();
QList<QSize> getSupportedPreviewSizes();
+ ImageFormat getPreviewFormat();
+ void setPreviewFormat(ImageFormat fmt);
+
QSize previewSize() const { return m_previewSize; }
void setPreviewSize(const QSize &size);
void setPreviewTexture(jobject surfaceTexture);
@@ -131,6 +144,8 @@ public:
void startPreview();
void stopPreview();
+ void requestPreviewFrame();
+
void takePicture();
static bool initJNI(JNIEnv *env);
@@ -143,6 +158,8 @@ Q_SIGNALS:
void whiteBalanceChanged();
+ void previewFrameAvailable(const QByteArray &data);
+
void pictureExposed();
void pictureCaptured(const QByteArray &data);
diff --git a/src/plugins/android/src/wrappers/jsurfacetexture.h b/src/plugins/android/src/wrappers/jsurfacetexture.h
index d65fc01e9..ea53b68ba 100644
--- a/src/plugins/android/src/wrappers/jsurfacetexture.h
+++ b/src/plugins/android/src/wrappers/jsurfacetexture.h
@@ -56,6 +56,7 @@ public:
explicit JSurfaceTexture(unsigned int texName);
~JSurfaceTexture();
+ int textureID() const { return m_texID; }
QMatrix4x4 getTransformMatrix();
void updateTexImage();
diff --git a/src/plugins/android/videonode/android_videonode.json b/src/plugins/android/videonode/android_videonode.json
new file mode 100644
index 000000000..08bb12c3f
--- /dev/null
+++ b/src/plugins/android/videonode/android_videonode.json
@@ -0,0 +1,3 @@
+{
+ "Keys": ["sgvideonodes"]
+}
diff --git a/src/plugins/android/videonode/qandroidsgvideonode.cpp b/src/plugins/android/videonode/qandroidsgvideonode.cpp
new file mode 100644
index 000000000..7f13dc981
--- /dev/null
+++ b/src/plugins/android/videonode/qandroidsgvideonode.cpp
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qandroidsgvideonode.h"
+
+#include <qsgmaterial.h>
+#include <qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidSGVideoNodeMaterialShader : public QSGMaterialShader
+{
+public:
+ void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
+
+ char const *const *attributeNames() const {
+ static const char *names[] = {
+ "qt_VertexPosition",
+ "qt_VertexTexCoord",
+ 0
+ };
+ return names;
+ }
+
+protected:
+ const char *vertexShader() const {
+ return
+ "uniform highp mat4 qt_Matrix; \n"
+ "uniform highp mat4 texMatrix; \n"
+ "attribute highp vec4 qt_VertexPosition; \n"
+ "attribute highp vec2 qt_VertexTexCoord; \n"
+ "varying highp vec2 qt_TexCoord; \n"
+ "void main() { \n"
+ " qt_TexCoord = (texMatrix * vec4(qt_VertexTexCoord, 0.0, 1.0)).xy; \n"
+ " gl_Position = qt_Matrix * qt_VertexPosition; \n"
+ "}";
+ }
+
+ const char *fragmentShader() const {
+ return
+ "#extension GL_OES_EGL_image_external : require \n"
+ "uniform samplerExternalOES videoTexture; \n"
+ "uniform lowp float opacity; \n"
+ "varying highp vec2 qt_TexCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = texture2D(videoTexture, qt_TexCoord) * opacity; \n"
+ "}";
+ }
+
+ void initialize() {
+ m_id_matrix = program()->uniformLocation("qt_Matrix");
+ m_id_texMatrix = program()->uniformLocation("texMatrix");
+ m_id_texture = program()->uniformLocation("videoTexture");
+ m_id_opacity = program()->uniformLocation("opacity");
+ }
+
+ int m_id_matrix;
+ int m_id_texMatrix;
+ int m_id_texture;
+ int m_id_opacity;
+};
+
+class QAndroidSGVideoNodeMaterial : public QSGMaterial
+{
+public:
+ QAndroidSGVideoNodeMaterial()
+ : m_textureId(0)
+ {
+ setFlag(Blending, false);
+ }
+
+ ~QAndroidSGVideoNodeMaterial()
+ {
+ m_frame = QVideoFrame();
+ }
+
+ QSGMaterialType *type() const {
+ static QSGMaterialType theType;
+ return &theType;
+ }
+
+ QSGMaterialShader *createShader() const {
+ return new QAndroidSGVideoNodeMaterialShader;
+ }
+
+ int compare(const QSGMaterial *other) const {
+ const QAndroidSGVideoNodeMaterial *m = static_cast<const QAndroidSGVideoNodeMaterial *>(other);
+ return m_textureId - m->m_textureId;
+ }
+
+ void setVideoFrame(const QVideoFrame &frame) {
+ QMutexLocker lock(&m_frameMutex);
+ m_frame = frame;
+ }
+
+ bool updateTexture()
+ {
+ QMutexLocker lock(&m_frameMutex);
+ bool texMatrixDirty = false;
+
+ if (m_frame.isValid()) {
+ QVariantList list = m_frame.handle().toList();
+
+ GLuint texId = list.at(0).toUInt();
+ QMatrix4x4 mat = qvariant_cast<QMatrix4x4>(list.at(1));
+
+ texMatrixDirty = texId != m_textureId || mat != m_texMatrix;
+
+ m_textureId = texId;
+ m_texMatrix = mat;
+
+ // the texture is already bound and initialized at this point,
+ // no need to call glTexParams
+
+ } else {
+ m_textureId = 0;
+ }
+
+ return texMatrixDirty;
+ }
+
+ QVideoFrame m_frame;
+ QMutex m_frameMutex;
+ GLuint m_textureId;
+ QMatrix4x4 m_texMatrix;
+};
+
+void QAndroidSGVideoNodeMaterialShader::updateState(const RenderState &state,
+ QSGMaterial *newMaterial,
+ QSGMaterial *oldMaterial)
+{
+ Q_UNUSED(oldMaterial);
+ QAndroidSGVideoNodeMaterial *mat = static_cast<QAndroidSGVideoNodeMaterial *>(newMaterial);
+ program()->setUniformValue(m_id_texture, 0);
+
+ if (mat->updateTexture())
+ program()->setUniformValue(m_id_texMatrix, mat->m_texMatrix);
+
+ if (state.isOpacityDirty())
+ program()->setUniformValue(m_id_opacity, state.opacity());
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_id_matrix, state.combinedMatrix());
+}
+
+QAndroidSGVideoNode::QAndroidSGVideoNode(const QVideoSurfaceFormat &format)
+ : m_format(format)
+{
+ setFlag(QSGNode::OwnsMaterial);
+ m_material = new QAndroidSGVideoNodeMaterial;
+ setMaterial(m_material);
+}
+
+void QAndroidSGVideoNode::setCurrentFrame(const QVideoFrame &frame)
+{
+ m_material->setVideoFrame(frame);
+ markDirty(DirtyMaterial);
+}
+
+QVideoFrame::PixelFormat QAndroidSGVideoNode::pixelFormat() const
+{
+ return m_format.pixelFormat();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/videonode/qandroidsgvideonode.h b/src/plugins/android/videonode/qandroidsgvideonode.h
new file mode 100644
index 000000000..b5b383fb6
--- /dev/null
+++ b/src/plugins/android/videonode/qandroidsgvideonode.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+#ifndef QANDROIDSGVIDEONODE_H
+#define QANDROIDSGVIDEONODE_H
+
+#include <private/qsgvideonode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidSGVideoNodeMaterial;
+
+class QAndroidSGVideoNode : public QSGVideoNode
+{
+public:
+ QAndroidSGVideoNode(const QVideoSurfaceFormat &format);
+
+ void setCurrentFrame(const QVideoFrame &frame);
+ QVideoFrame::PixelFormat pixelFormat() const;
+
+private:
+ QVideoSurfaceFormat m_format;
+ QAndroidSGVideoNodeMaterial *m_material;
+ QVideoFrame m_frame;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDSGVIDEONODE_H
diff --git a/src/plugins/android/videonode/qandroidsgvideonodeplugin.cpp b/src/plugins/android/videonode/qandroidsgvideonodeplugin.cpp
new file mode 100644
index 000000000..155c66ada
--- /dev/null
+++ b/src/plugins/android/videonode/qandroidsgvideonodeplugin.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qandroidsgvideonodeplugin.h"
+#include "qandroidsgvideonode.h"
+
+QT_BEGIN_NAMESPACE
+
+#define ExternalGLTextureHandle (QAbstractVideoBuffer::UserHandle + 1)
+
+QList<QVideoFrame::PixelFormat> QAndroidSGVideoNodeFactoryPlugin::supportedPixelFormats(
+ QAbstractVideoBuffer::HandleType handleType) const
+{
+ QList<QVideoFrame::PixelFormat> pixelFormats;
+
+ if (handleType == ExternalGLTextureHandle)
+ pixelFormats.append(QVideoFrame::Format_BGR32);
+
+ return pixelFormats;
+}
+
+QSGVideoNode *QAndroidSGVideoNodeFactoryPlugin::createNode(const QVideoSurfaceFormat &format)
+{
+ if (supportedPixelFormats(format.handleType()).contains(format.pixelFormat()))
+ return new QAndroidSGVideoNode(format);
+
+ return 0;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/videonode/qandroidsgvideonodeplugin.h b/src/plugins/android/videonode/qandroidsgvideonodeplugin.h
new file mode 100644
index 000000000..e7a9d0689
--- /dev/null
+++ b/src/plugins/android/videonode/qandroidsgvideonodeplugin.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+#ifndef QANDROIDSGVIDEONODEPLUGIN_H
+#define QANDROIDSGVIDEONODEPLUGIN_H
+
+#include <private/qsgvideonode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidSGVideoNodeFactoryPlugin : public QSGVideoNodeFactoryPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QSGVideoNodeFactoryInterface_iid
+ FILE "android_videonode.json")
+
+public:
+ QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
+ QSGVideoNode *createNode(const QVideoSurfaceFormat &format);
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDSGVIDEONODEPLUGIN_H
diff --git a/src/plugins/android/videonode/videonode.pro b/src/plugins/android/videonode/videonode.pro
new file mode 100644
index 000000000..4ae2dc36e
--- /dev/null
+++ b/src/plugins/android/videonode/videonode.pro
@@ -0,0 +1,16 @@
+TARGET = qtsgvideonode_android
+QT += quick multimedia-private qtmultimediaquicktools-private
+
+PLUGIN_TYPE = video/videonode
+PLUGIN_CLASS_NAME = QAndroidSGVideoNodeFactoryPlugin
+load(qt_plugin)
+
+HEADERS += \
+ qandroidsgvideonodeplugin.h \
+ qandroidsgvideonode.h
+
+SOURCES += \
+ qandroidsgvideonodeplugin.cpp \
+ qandroidsgvideonode.cpp
+
+OTHER_FILES += android_videonode.json
diff --git a/src/plugins/audiocapture/audiocaptureprobecontrol.cpp b/src/plugins/audiocapture/audiocaptureprobecontrol.cpp
index 38f263be9..323aec622 100644
--- a/src/plugins/audiocapture/audiocaptureprobecontrol.cpp
+++ b/src/plugins/audiocapture/audiocaptureprobecontrol.cpp
@@ -41,6 +41,8 @@
#include "audiocaptureprobecontrol.h"
+QT_BEGIN_NAMESPACE
+
AudioCaptureProbeControl::AudioCaptureProbeControl(QObject *parent):
QMediaAudioProbeControl(parent)
{
@@ -58,3 +60,5 @@ void AudioCaptureProbeControl::bufferProbed(const char *data, quint32 size, cons
QAudioBuffer audioBuffer = QAudioBuffer(QByteArray::fromRawData(data, size), format);
QMetaObject::invokeMethod(this, "audioBufferProbed", Qt::QueuedConnection, Q_ARG(QAudioBuffer, audioBuffer));
}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/audiocapture/audiocaptureprobecontrol.h b/src/plugins/audiocapture/audiocaptureprobecontrol.h
index 64d31601a..f1df8a1c7 100644
--- a/src/plugins/audiocapture/audiocaptureprobecontrol.h
+++ b/src/plugins/audiocapture/audiocaptureprobecontrol.h
@@ -46,7 +46,7 @@
#include <QtCore/qmutex.h>
#include <qaudiobuffer.h>
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
class AudioCaptureProbeControl : public QMediaAudioProbeControl
{
@@ -58,4 +58,6 @@ public:
void bufferProbed(const char *data, quint32 size, const QAudioFormat& format);
};
+QT_END_NAMESPACE
+
#endif
diff --git a/src/plugins/audiocapture/audiocaptureservice.cpp b/src/plugins/audiocapture/audiocaptureservice.cpp
index fa9045646..044ac97a4 100644
--- a/src/plugins/audiocapture/audiocaptureservice.cpp
+++ b/src/plugins/audiocapture/audiocaptureservice.cpp
@@ -47,6 +47,8 @@
#include "audiomediarecordercontrol.h"
#include "audiocaptureprobecontrol.h"
+QT_BEGIN_NAMESPACE
+
AudioCaptureService::AudioCaptureService(QObject *parent):
QMediaService(parent)
{
@@ -94,4 +96,4 @@ void AudioCaptureService::releaseControl(QMediaControl *control)
Q_UNUSED(control)
}
-
+QT_END_NAMESPACE
diff --git a/src/plugins/audiocapture/audiocaptureservice.h b/src/plugins/audiocapture/audiocaptureservice.h
index 2c1e81642..6805168b8 100644
--- a/src/plugins/audiocapture/audiocaptureservice.h
+++ b/src/plugins/audiocapture/audiocaptureservice.h
@@ -46,14 +46,14 @@
#include "qmediaservice.h"
+QT_BEGIN_NAMESPACE
+
class AudioCaptureSession;
class AudioEncoderControl;
class AudioContainerControl;
class AudioMediaRecorderControl;
class AudioInputSelector;
-QT_USE_NAMESPACE
-
class AudioCaptureService : public QMediaService
{
Q_OBJECT
@@ -71,4 +71,6 @@ private:
AudioMediaRecorderControl *m_mediaControl;
};
+QT_END_NAMESPACE
+
#endif
diff --git a/src/plugins/audiocapture/audiocaptureserviceplugin.cpp b/src/plugins/audiocapture/audiocaptureserviceplugin.cpp
index eafe18b8e..c3ae8af27 100644
--- a/src/plugins/audiocapture/audiocaptureserviceplugin.cpp
+++ b/src/plugins/audiocapture/audiocaptureserviceplugin.cpp
@@ -46,6 +46,7 @@
#include "qmediaserviceproviderplugin.h"
+QT_BEGIN_NAMESPACE
QMediaService* AudioCaptureServicePlugin::create(QString const& key)
{
@@ -60,3 +61,4 @@ void AudioCaptureServicePlugin::release(QMediaService *service)
delete service;
}
+QT_END_NAMESPACE
diff --git a/src/plugins/audiocapture/audiocaptureserviceplugin.h b/src/plugins/audiocapture/audiocaptureserviceplugin.h
index eba64a3a7..cf51c7428 100644
--- a/src/plugins/audiocapture/audiocaptureserviceplugin.h
+++ b/src/plugins/audiocapture/audiocaptureserviceplugin.h
@@ -45,7 +45,7 @@
#include "qmediaserviceproviderplugin.h"
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
class AudioCaptureServicePlugin : public QMediaServiceProviderPlugin
{
@@ -58,4 +58,6 @@ public:
void release(QMediaService *service);
};
+QT_END_NAMESPACE
+
#endif // AUDIOCAPTURESERVICEPLUGIN_H
diff --git a/src/plugins/audiocapture/audiocapturesession.cpp b/src/plugins/audiocapture/audiocapturesession.cpp
index e242b4c3b..e34c0ee7d 100644
--- a/src/plugins/audiocapture/audiocapturesession.cpp
+++ b/src/plugins/audiocapture/audiocapturesession.cpp
@@ -49,6 +49,8 @@
#include "audiocapturesession.h"
#include "audiocaptureprobecontrol.h"
+QT_BEGIN_NAMESPACE
+
void FileProbeProxy::startProbes(const QAudioFormat &format)
{
m_format = format;
@@ -87,33 +89,20 @@ qint64 FileProbeProxy::writeData(const char *data, qint64 len)
return QFile::writeData(data, len);
}
-AudioCaptureSession::AudioCaptureSession(QObject *parent):
- QObject(parent)
+AudioCaptureSession::AudioCaptureSession(QObject *parent)
+ : QObject(parent)
+ , m_state(QMediaRecorder::StoppedState)
+ , m_status(QMediaRecorder::UnloadedStatus)
+ , m_audioInput(0)
+ , m_deviceInfo(QAudioDeviceInfo::defaultInputDevice())
+ , m_wavFile(true)
{
- m_deviceInfo = new QAudioDeviceInfo(QAudioDeviceInfo::defaultInputDevice());
- m_audioInput = 0;
- m_position = 0;
- m_state = QMediaRecorder::StoppedState;
-
- m_format.setSampleRate(8000);
- m_format.setChannelCount(1);
- m_format.setSampleSize(8);
- m_format.setSampleType(QAudioFormat::UnSignedInt);
- m_format.setCodec("audio/pcm");
- wavFile = true;
+ m_format = m_deviceInfo.preferredFormat();
}
AudioCaptureSession::~AudioCaptureSession()
{
- stop();
-
- if(m_audioInput)
- delete m_audioInput;
-}
-
-QAudioDeviceInfo* AudioCaptureSession::deviceInfo() const
-{
- return m_deviceInfo;
+ setState(QMediaRecorder::StoppedState);
}
QAudioFormat AudioCaptureSession::format() const
@@ -121,118 +110,96 @@ QAudioFormat AudioCaptureSession::format() const
return m_format;
}
-bool AudioCaptureSession::isFormatSupported(const QAudioFormat &format) const
+void AudioCaptureSession::setFormat(const QAudioFormat &format)
{
- if(m_deviceInfo) {
- if(format.codec().contains(QLatin1String("audio/x-wav"))) {
- QAudioFormat fmt = format;
- fmt.setCodec("audio/pcm");
- return m_deviceInfo->isFormatSupported(fmt);
- } else
- return m_deviceInfo->isFormatSupported(format);
- }
- return false;
+ m_format = format;
}
-bool AudioCaptureSession::setFormat(const QAudioFormat &format)
+void AudioCaptureSession::setContainerFormat(const QString &formatMimeType)
{
- if(m_deviceInfo) {
-
- QAudioFormat fmt = format;
-
- if(m_deviceInfo->isFormatSupported(fmt)) {
- m_format = fmt;
- if(m_audioInput) delete m_audioInput;
- m_audioInput = 0;
- QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
- for(int i=0;i<devices.size();i++) {
- if(qstrcmp(m_deviceInfo->deviceName().toLocal8Bit().constData(),
- devices.at(i).deviceName().toLocal8Bit().constData()) == 0) {
- m_audioInput = new QAudioInput(devices.at(i),m_format);
- connect(m_audioInput,SIGNAL(stateChanged(QAudio::State)),this,SLOT(stateChanged(QAudio::State)));
- connect(m_audioInput,SIGNAL(notify()),this,SLOT(notify()));
- break;
- }
- }
- } else {
- m_format = m_deviceInfo->preferredFormat();
- qWarning()<<"failed to setFormat using preferred...";
- }
- }
- return false;
+ m_wavFile = (formatMimeType.isEmpty()
+ || QString::compare(formatMimeType, QLatin1String("audio/x-wav")) == 0);
}
-QStringList AudioCaptureSession::supportedContainers() const
+QString AudioCaptureSession::containerFormat() const
{
- QStringList list;
- if(m_deviceInfo) {
- if (m_deviceInfo->supportedCodecs().size() > 0) {
- list << "audio/x-wav";
- list << "audio/pcm";
- }
- }
- return list;
+ if (m_wavFile)
+ return QStringLiteral("audio/x-wav");
+
+ return QStringLiteral("audio/x-raw");
}
-QString AudioCaptureSession::containerDescription(const QString &formatMimeType) const
+QUrl AudioCaptureSession::outputLocation() const
{
- if(m_deviceInfo) {
- if (formatMimeType.contains(QLatin1String("audio/pcm")))
- return tr("RAW file format");
- if (formatMimeType.contains(QLatin1String("audio/x-wav")))
- return tr("WAV file format");
- }
- return QString();
+ return m_actualOutputLocation;
}
-void AudioCaptureSession::setContainerFormat(const QString &formatMimeType)
+bool AudioCaptureSession::setOutputLocation(const QUrl& location)
{
- if (!formatMimeType.contains(QLatin1String("audio/x-wav")) &&
- !formatMimeType.contains(QLatin1String("audio/pcm")) &&
- !formatMimeType.isEmpty())
- return;
+ if (m_requestedOutputLocation == location)
+ return false;
- if(m_deviceInfo) {
- if (!m_deviceInfo->supportedCodecs().contains(QLatin1String("audio/pcm")))
- return;
+ m_actualOutputLocation = QUrl();
+ m_requestedOutputLocation = location;
- if (formatMimeType.isEmpty() || formatMimeType.contains(QLatin1String("audio/x-wav"))) {
- wavFile = true;
- m_format.setCodec("audio/pcm");
- } else {
- wavFile = false;
- m_format.setCodec(formatMimeType);
- }
+ if (m_requestedOutputLocation.isEmpty())
+ return true;
+
+ if (m_requestedOutputLocation.isValid() && (m_requestedOutputLocation.isLocalFile()
+ || m_requestedOutputLocation.isRelative())) {
+ emit actualLocationChanged(m_requestedOutputLocation);
+ return true;
}
+
+ m_requestedOutputLocation = QUrl();
+ return false;
}
-QString AudioCaptureSession::containerFormat() const
+qint64 AudioCaptureSession::position() const
{
- if(wavFile)
- return QString("audio/x-wav");
-
- return QString("audio/pcm");
+ if (m_audioInput)
+ return m_audioInput->processedUSecs() / 1000;
+ return 0;
}
-QUrl AudioCaptureSession::outputLocation() const
+void AudioCaptureSession::setState(QMediaRecorder::State state)
{
- return m_actualSink;
+ if (m_state == state)
+ return;
+
+ m_state = state;
+ emit stateChanged(m_state);
+
+ switch (m_state) {
+ case QMediaRecorder::StoppedState:
+ stop();
+ break;
+ case QMediaRecorder::PausedState:
+ pause();
+ break;
+ case QMediaRecorder::RecordingState:
+ record();
+ break;
+ }
}
-bool AudioCaptureSession::setOutputLocation(const QUrl& sink)
+QMediaRecorder::State AudioCaptureSession::state() const
{
- m_sink = m_actualSink = sink;
- return true;
+ return m_state;
}
-qint64 AudioCaptureSession::position() const
+void AudioCaptureSession::setStatus(QMediaRecorder::Status status)
{
- return m_position;
+ if (m_status == status)
+ return;
+
+ m_status = status;
+ emit statusChanged(m_status);
}
-int AudioCaptureSession::state() const
+QMediaRecorder::Status AudioCaptureSession::status() const
{
- return int(m_state);
+ return m_status;
}
QDir AudioCaptureSession::defaultDir() const
@@ -258,9 +225,29 @@ QDir AudioCaptureSession::defaultDir() const
return QDir();
}
-QString AudioCaptureSession::generateFileName(const QDir &dir, const QString &ext) const
+QString AudioCaptureSession::generateFileName(const QString &requestedName,
+ const QString &extension) const
{
+ if (requestedName.isEmpty())
+ return generateFileName(defaultDir(), extension);
+
+ QString path = requestedName;
+
+ if (QFileInfo(path).isRelative())
+ path = defaultDir().absoluteFilePath(path);
+
+ if (QFileInfo(path).isDir())
+ return generateFileName(QDir(path), extension);
+ if (!path.endsWith(extension))
+ path.append(QString(".%1").arg(extension));
+
+ return path;
+}
+
+QString AudioCaptureSession::generateFileName(const QDir &dir,
+ const QString &ext) const
+{
int lastClip = 0;
foreach(QString fileName, dir.entryList(QStringList() << QString("clip_*.%1").arg(ext))) {
int imgNumber = fileName.mid(5, fileName.size()-6-ext.length()).toInt();
@@ -277,25 +264,45 @@ QString AudioCaptureSession::generateFileName(const QDir &dir, const QString &ex
void AudioCaptureSession::record()
{
- if(!m_audioInput) {
- setFormat(m_format);
- }
+ if (m_status == QMediaRecorder::PausedStatus) {
+ m_audioInput->resume();
+ } else {
+ if (m_deviceInfo.isNull()) {
+ emit error(QMediaRecorder::ResourceError,
+ QStringLiteral("No input device available."));
+ m_state = QMediaRecorder::StoppedState;
+ emit stateChanged(m_state);
+ setStatus(QMediaRecorder::UnavailableStatus);
+ return;
+ }
- m_actualSink = m_sink;
+ setStatus(QMediaRecorder::LoadingStatus);
- if (m_actualSink.isEmpty()) {
- QString ext = wavFile ? QLatin1String("wav") : QLatin1String("raw");
- m_actualSink = generateFileName(defaultDir(), ext);
- }
+ m_format = m_deviceInfo.nearestFormat(m_format);
+ m_audioInput = new QAudioInput(m_deviceInfo, m_format);
+ connect(m_audioInput, SIGNAL(stateChanged(QAudio::State)),
+ this, SLOT(audioInputStateChanged(QAudio::State)));
+ connect(m_audioInput, SIGNAL(notify()),
+ this, SLOT(notify()));
- if(m_actualSink.toLocalFile().length() > 0)
- file.setFileName(m_actualSink.toLocalFile());
- else
- file.setFileName(m_actualSink.toString());
- if(m_audioInput) {
- if(m_state == QMediaRecorder::StoppedState) {
- if(file.open(QIODevice::WriteOnly)) {
+ QString filePath = generateFileName(
+ m_requestedOutputLocation.isLocalFile() ? m_requestedOutputLocation.toLocalFile()
+ : m_requestedOutputLocation.toString(),
+ m_wavFile ? QLatin1String("wav")
+ : QLatin1String("raw"));
+
+ m_actualOutputLocation = QUrl::fromLocalFile(filePath);
+ if (m_actualOutputLocation != m_requestedOutputLocation)
+ emit actualLocationChanged(m_actualOutputLocation);
+
+ file.setFileName(filePath);
+
+ setStatus(QMediaRecorder::LoadedStatus);
+ setStatus(QMediaRecorder::StartingStatus);
+
+ if (file.open(QIODevice::WriteOnly)) {
+ if (m_wavFile) {
memset(&header,0,sizeof(CombinedHeader));
memcpy(header.riff.descriptor.id,"RIFF",4);
header.riff.descriptor.size = 0xFFFFFFFF; // This should be updated on stop(), filesize-8
@@ -310,28 +317,26 @@ void AudioCaptureSession::record()
header.wave.bitsPerSample = m_format.sampleSize();
memcpy(header.data.descriptor.id,"data",4);
header.data.descriptor.size = 0xFFFFFFFF; // This should be updated on stop(),samples*channels*sampleSize/8
- if (wavFile)
- file.write((char*)&header,sizeof(CombinedHeader));
-
- file.startProbes(m_format);
- m_audioInput->start(qobject_cast<QIODevice*>(&file));
- } else {
- emit error(1,QString("can't open source, failed"));
- m_state = QMediaRecorder::StoppedState;
- emit stateChanged(m_state);
+ file.write((char*)&header,sizeof(CombinedHeader));
}
+
+ file.startProbes(m_format);
+ m_audioInput->start(qobject_cast<QIODevice*>(&file));
+ } else {
+ delete m_audioInput;
+ m_audioInput = 0;
+ emit error(QMediaRecorder::ResourceError,
+ QStringLiteral("Can't open output location"));
+ m_state = QMediaRecorder::StoppedState;
+ emit stateChanged(m_state);
+ setStatus(QMediaRecorder::UnloadedStatus);
}
}
-
- m_state = QMediaRecorder::RecordingState;
}
void AudioCaptureSession::pause()
{
- if(m_audioInput)
- m_audioInput->stop();
-
- m_state = QMediaRecorder::PausedState;
+ m_audioInput->suspend();
}
void AudioCaptureSession::stop()
@@ -340,7 +345,7 @@ void AudioCaptureSession::stop()
m_audioInput->stop();
file.stopProbes();
file.close();
- if (wavFile) {
+ if (m_wavFile) {
qint32 fileSize = file.size()-8;
file.open(QIODevice::ReadWrite | QIODevice::Unbuffered);
file.read((char*)&header,sizeof(CombinedHeader));
@@ -350,9 +355,10 @@ void AudioCaptureSession::stop()
file.write((char*)&header,sizeof(CombinedHeader));
file.close();
}
- m_position = 0;
+ delete m_audioInput;
+ m_audioInput = 0;
+ setStatus(QMediaRecorder::UnloadedStatus);
}
- m_state = QMediaRecorder::StoppedState;
}
void AudioCaptureSession::addProbe(AudioCaptureProbeControl *probe)
@@ -365,45 +371,41 @@ void AudioCaptureSession::removeProbe(AudioCaptureProbeControl *probe)
file.removeProbe(probe);
}
-void AudioCaptureSession::stateChanged(QAudio::State state)
+void AudioCaptureSession::audioInputStateChanged(QAudio::State state)
{
switch(state) {
- case QAudio::ActiveState:
- emit stateChanged(QMediaRecorder::RecordingState);
- break;
- default:
- if(!((m_state == QMediaRecorder::PausedState)||(m_state == QMediaRecorder::StoppedState)))
- m_state = QMediaRecorder::StoppedState;
-
- emit stateChanged(m_state);
- break;
+ case QAudio::ActiveState:
+ setStatus(QMediaRecorder::RecordingStatus);
+ break;
+ case QAudio::SuspendedState:
+ setStatus(QMediaRecorder::PausedStatus);
+ break;
+ case QAudio::StoppedState:
+ setStatus(QMediaRecorder::FinalizingStatus);
+ break;
+ default:
+ break;
}
}
void AudioCaptureSession::notify()
{
- m_position += m_audioInput->notifyInterval();
- emit positionChanged(m_position);
+ emit positionChanged(position());
}
void AudioCaptureSession::setCaptureDevice(const QString &deviceName)
{
m_captureDevice = deviceName;
- if(m_deviceInfo)
- delete m_deviceInfo;
-
- m_deviceInfo = 0;
QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
- for(int i = 0; i < devices.size(); i++) {
- if(qstrcmp(m_captureDevice.toLocal8Bit().constData(),
- devices.at(i).deviceName().toLocal8Bit().constData())==0){
- m_deviceInfo = new QAudioDeviceInfo(devices.at(i));
+ for (int i = 0; i < devices.size(); ++i) {
+ QAudioDeviceInfo info = devices.at(i);
+ if (m_captureDevice == info.deviceName()){
+ m_deviceInfo = info;
return;
}
}
- m_deviceInfo = new QAudioDeviceInfo(QAudioDeviceInfo::defaultInputDevice());
+ m_deviceInfo = QAudioDeviceInfo::defaultInputDevice();
}
-
-
+QT_END_NAMESPACE
diff --git a/src/plugins/audiocapture/audiocapturesession.h b/src/plugins/audiocapture/audiocapturesession.h
index a6b7fa369..86f98db6c 100644
--- a/src/plugins/audiocapture/audiocapturesession.h
+++ b/src/plugins/audiocapture/audiocapturesession.h
@@ -55,7 +55,7 @@
#include <qaudioinput.h>
#include <qaudiodeviceinfo.h>
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
class AudioCaptureProbeControl;
@@ -85,50 +85,58 @@ public:
~AudioCaptureSession();
QAudioFormat format() const;
- QAudioDeviceInfo* deviceInfo() const;
- bool isFormatSupported(const QAudioFormat &format) const;
- bool setFormat(const QAudioFormat &format);
- QStringList supportedContainers() const;
+ void setFormat(const QAudioFormat &format);
+
QString containerFormat() const;
void setContainerFormat(const QString &formatMimeType);
- QString containerDescription(const QString &formatMimeType) const;
QUrl outputLocation() const;
- bool setOutputLocation(const QUrl& sink);
+ bool setOutputLocation(const QUrl& location);
+
qint64 position() const;
- int state() const;
- void record();
- void pause();
- void stop();
+
+ void setState(QMediaRecorder::State state);
+ QMediaRecorder::State state() const;
+ QMediaRecorder::Status status() const;
+
void addProbe(AudioCaptureProbeControl *probe);
void removeProbe(AudioCaptureProbeControl *probe);
-public slots:
void setCaptureDevice(const QString &deviceName);
signals:
void stateChanged(QMediaRecorder::State state);
+ void statusChanged(QMediaRecorder::Status status);
void positionChanged(qint64 position);
+ void actualLocationChanged(const QUrl &location);
void error(int error, const QString &errorString);
private slots:
- void stateChanged(QAudio::State state);
+ void audioInputStateChanged(QAudio::State state);
void notify();
private:
+ void record();
+ void pause();
+ void stop();
+
+ void setStatus(QMediaRecorder::Status status);
+
QDir defaultDir() const;
- QString generateFileName(const QDir &dir, const QString &ext) const;
+ QString generateFileName(const QString &requestedName,
+ const QString &extension) const;
+ QString generateFileName(const QDir &dir, const QString &extension) const;
FileProbeProxy file;
QString m_captureDevice;
- QUrl m_sink;
- QUrl m_actualSink;
+ QUrl m_requestedOutputLocation;
+ QUrl m_actualOutputLocation;
QMediaRecorder::State m_state;
+ QMediaRecorder::Status m_status;
QAudioInput *m_audioInput;
- QAudioDeviceInfo *m_deviceInfo;
+ QAudioDeviceInfo m_deviceInfo;
QAudioFormat m_format;
- qint64 m_position;
- bool wavFile;
+ bool m_wavFile;
// WAV header stuff
@@ -171,4 +179,6 @@ private:
CombinedHeader header;
};
+QT_END_NAMESPACE
+
#endif
diff --git a/src/plugins/audiocapture/audiocontainercontrol.cpp b/src/plugins/audiocapture/audiocontainercontrol.cpp
index fec190e96..20f373b44 100644
--- a/src/plugins/audiocapture/audiocontainercontrol.cpp
+++ b/src/plugins/audiocapture/audiocontainercontrol.cpp
@@ -42,6 +42,8 @@
#include "audiocontainercontrol.h"
#include "audiocapturesession.h"
+QT_BEGIN_NAMESPACE
+
AudioContainerControl::AudioContainerControl(QObject *parent)
:QMediaContainerControl(parent)
{
@@ -54,7 +56,8 @@ AudioContainerControl::~AudioContainerControl()
QStringList AudioContainerControl::supportedContainers() const
{
- return m_session->supportedContainers();
+ return QStringList() << QStringLiteral("audio/x-wav")
+ << QStringLiteral("audio/x-raw");
}
QString AudioContainerControl::containerFormat() const
@@ -64,11 +67,18 @@ QString AudioContainerControl::containerFormat() const
void AudioContainerControl::setContainerFormat(const QString &formatMimeType)
{
- m_session->setContainerFormat(formatMimeType);
+ if (formatMimeType.isEmpty() || supportedContainers().contains(formatMimeType))
+ m_session->setContainerFormat(formatMimeType);
}
QString AudioContainerControl::containerDescription(const QString &formatMimeType) const
{
- return m_session->containerDescription(formatMimeType);
+ if (QString::compare(formatMimeType, QLatin1String("audio/x-raw")) == 0)
+ return tr("RAW (headerless) file format");
+ if (QString::compare(formatMimeType, QLatin1String("audio/x-wav")) == 0)
+ return tr("WAV file format");
+
+ return QString();
}
+QT_END_NAMESPACE
diff --git a/src/plugins/audiocapture/audiocontainercontrol.h b/src/plugins/audiocapture/audiocontainercontrol.h
index 18a335702..8c0a67cb8 100644
--- a/src/plugins/audiocapture/audiocontainercontrol.h
+++ b/src/plugins/audiocapture/audiocontainercontrol.h
@@ -47,9 +47,9 @@
#include <QtCore/qstringlist.h>
#include <QtCore/qmap.h>
-class AudioCaptureSession;
+QT_BEGIN_NAMESPACE
-QT_USE_NAMESPACE
+class AudioCaptureSession;
class AudioContainerControl : public QMediaContainerControl
{
@@ -67,4 +67,6 @@ private:
AudioCaptureSession* m_session;
};
+QT_END_NAMESPACE
+
#endif
diff --git a/src/plugins/audiocapture/audioencodercontrol.cpp b/src/plugins/audiocapture/audioencodercontrol.cpp
index 09890f45c..6601cfbdc 100644
--- a/src/plugins/audiocapture/audioencodercontrol.cpp
+++ b/src/plugins/audiocapture/audioencodercontrol.cpp
@@ -46,26 +46,43 @@
#include <QtCore/qdebug.h>
+QT_BEGIN_NAMESPACE
+
+static QAudioFormat audioSettingsToAudioFormat(const QAudioEncoderSettings &settings)
+{
+ QAudioFormat fmt;
+ fmt.setCodec(settings.codec());
+ fmt.setChannelCount(settings.channelCount());
+ fmt.setSampleRate(settings.sampleRate());
+ if (settings.sampleRate() == 8000 && settings.bitRate() == 8000) {
+ fmt.setSampleType(QAudioFormat::UnSignedInt);
+ fmt.setSampleSize(8);
+ } else {
+ fmt.setSampleSize(16);
+ fmt.setSampleType(QAudioFormat::SignedInt);
+ }
+ fmt.setByteOrder(QAudioDeviceInfo::defaultInputDevice().preferredFormat().byteOrder());
+ return fmt;
+}
+
+static QAudioEncoderSettings audioFormatToAudioSettings(const QAudioFormat &format)
+{
+ QAudioEncoderSettings settings;
+ settings.setCodec(format.codec());
+ settings.setChannelCount(format.channelCount());
+ settings.setSampleRate(format.sampleRate());
+ settings.setEncodingMode(QMultimedia::ConstantBitRateEncoding);
+ settings.setBitRate(format.channelCount()
+ * format.sampleSize()
+ * format.sampleRate());
+ return settings;
+}
+
AudioEncoderControl::AudioEncoderControl(QObject *parent)
:QAudioEncoderSettingsControl(parent)
{
m_session = qobject_cast<AudioCaptureSession*>(parent);
-
- QT_PREPEND_NAMESPACE(QAudioFormat) fmt;
- fmt.setSampleSize(8);
- fmt.setChannelCount(1);
- fmt.setSampleRate(8000);
- fmt.setSampleType(QT_PREPEND_NAMESPACE(QAudioFormat)::SignedInt);
- fmt.setCodec("audio/pcm");
- fmt.setByteOrder(QAudioFormat::LittleEndian);
- m_session->setFormat(fmt);
-
- m_settings.setEncodingMode(QMultimedia::ConstantQualityEncoding);
- m_settings.setCodec("audio/pcm");
- m_settings.setBitRate(8000);
- m_settings.setChannelCount(1);
- m_settings.setSampleRate(8000);
- m_settings.setQuality(QMultimedia::LowQuality);
+ update();
}
AudioEncoderControl::~AudioEncoderControl()
@@ -74,71 +91,85 @@ AudioEncoderControl::~AudioEncoderControl()
QStringList AudioEncoderControl::supportedAudioCodecs() const
{
- QStringList list;
- if (m_session->supportedContainers().size() > 0)
- list.append("audio/pcm");
-
- return list;
+ return QStringList() << QStringLiteral("audio/pcm");
}
QString AudioEncoderControl::codecDescription(const QString &codecName) const
{
- if (codecName.contains(QLatin1String("audio/pcm")))
- return tr("PCM audio data");
+ if (QString::compare(codecName, QLatin1String("audio/pcm")) == 0)
+ return tr("Linear PCM audio data");
return QString();
}
-QList<int> AudioEncoderControl::supportedSampleRates(const QAudioEncoderSettings &, bool *continuous) const
+QList<int> AudioEncoderControl::supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous) const
{
if (continuous)
*continuous = false;
- return m_session->deviceInfo()->supportedSampleRates();
+ if (settings.codec().isEmpty() || settings.codec() == QLatin1String("audio/pcm"))
+ return m_sampleRates;
+
+ return QList<int>();
}
QAudioEncoderSettings AudioEncoderControl::audioSettings() const
{
- return m_settings;
+ return audioFormatToAudioSettings(m_session->format());
}
void AudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings)
{
- QAudioFormat fmt = m_session->format();
+ QAudioFormat fmt = audioSettingsToAudioFormat(settings);
if (settings.encodingMode() == QMultimedia::ConstantQualityEncoding) {
- if (settings.quality() == QMultimedia::LowQuality) {
+ fmt.setCodec("audio/pcm");
+ switch (settings.quality()) {
+ case QMultimedia::VeryLowQuality:
fmt.setSampleSize(8);
- fmt.setChannelCount(1);
fmt.setSampleRate(8000);
fmt.setSampleType(QAudioFormat::UnSignedInt);
-
- } else if (settings.quality() == QMultimedia::NormalQuality) {
- fmt.setSampleSize(16);
- fmt.setChannelCount(1);
+ break;
+ case QMultimedia::LowQuality:
+ fmt.setSampleSize(8);
fmt.setSampleRate(22050);
+ fmt.setSampleType(QAudioFormat::UnSignedInt);
+ break;
+ case QMultimedia::HighQuality:
+ fmt.setSampleSize(16);
+ fmt.setSampleRate(48000);
fmt.setSampleType(QAudioFormat::SignedInt);
-
- } else {
+ break;
+ case QMultimedia::VeryHighQuality:
fmt.setSampleSize(16);
- fmt.setChannelCount(1);
- fmt.setSampleRate(44100);
+ fmt.setSampleRate(96000);
fmt.setSampleType(QAudioFormat::SignedInt);
- }
-
- } else {
- fmt.setChannelCount(settings.channelCount());
- fmt.setSampleRate(settings.sampleRate());
- if (settings.sampleRate() == 8000 && settings.bitRate() == 8000) {
- fmt.setSampleType(QAudioFormat::UnSignedInt);
- fmt.setSampleSize(8);
- } else {
+ break;
+ case QMultimedia::NormalQuality:
+ default:
fmt.setSampleSize(16);
+ fmt.setSampleRate(44100);
fmt.setSampleType(QAudioFormat::SignedInt);
+ break;
}
}
- fmt.setCodec("audio/pcm");
m_session->setFormat(fmt);
- m_settings = settings;
}
+
+void AudioEncoderControl::update()
+{
+ m_sampleRates.clear();
+ QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
+ for (int i = 0; i < devices.size(); ++i) {
+ QList<int> rates = devices.at(i).supportedSampleRates();
+ for (int j = 0; j < rates.size(); ++j) {
+ int rate = rates.at(j);
+ if (!m_sampleRates.contains(rate))
+ m_sampleRates.append(rate);
+ }
+ }
+ qSort(m_sampleRates);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/audiocapture/audioencodercontrol.h b/src/plugins/audiocapture/audioencodercontrol.h
index c27c9a45e..1508de205 100644
--- a/src/plugins/audiocapture/audioencodercontrol.h
+++ b/src/plugins/audiocapture/audioencodercontrol.h
@@ -49,9 +49,9 @@
#include <qaudioformat.h>
-class AudioCaptureSession;
+QT_BEGIN_NAMESPACE
-QT_USE_NAMESPACE
+class AudioCaptureSession;
class AudioEncoderControl : public QAudioEncoderSettingsControl
{
@@ -68,8 +68,12 @@ public:
void setAudioSettings(const QAudioEncoderSettings&);
private:
+ void update();
+
AudioCaptureSession* m_session;
- QAudioEncoderSettings m_settings;
+ QList<int> m_sampleRates;
};
+QT_END_NAMESPACE
+
#endif
diff --git a/src/plugins/audiocapture/audioinputselector.cpp b/src/plugins/audiocapture/audioinputselector.cpp
index e246b38d5..d88b05d9c 100644
--- a/src/plugins/audiocapture/audioinputselector.cpp
+++ b/src/plugins/audiocapture/audioinputselector.cpp
@@ -44,6 +44,7 @@
#include <qaudiodeviceinfo.h>
+QT_BEGIN_NAMESPACE
AudioInputSelector::AudioInputSelector(QObject *parent)
:QAudioInputSelectorControl(parent)
@@ -79,7 +80,7 @@ QString AudioInputSelector::inputDescription(const QString& name) const
QString AudioInputSelector::defaultInput() const
{
- return QAudioDeviceInfo(QAudioDeviceInfo::defaultInputDevice()).deviceName();
+ return QAudioDeviceInfo::defaultInputDevice().deviceName();
}
QString AudioInputSelector::activeInput() const
@@ -108,3 +109,5 @@ void AudioInputSelector::update()
m_descriptions.append(devices.at(i).deviceName());
}
}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/audiocapture/audioinputselector.h b/src/plugins/audiocapture/audioinputselector.h
index 7a1b6419d..d28fefbe4 100644
--- a/src/plugins/audiocapture/audioinputselector.h
+++ b/src/plugins/audiocapture/audioinputselector.h
@@ -46,9 +46,9 @@
#include "qaudioinputselectorcontrol.h"
-class AudioCaptureSession;
+QT_BEGIN_NAMESPACE
-QT_USE_NAMESPACE
+class AudioCaptureSession;
class AudioInputSelector : public QAudioInputSelectorControl
{
@@ -74,4 +74,6 @@ private:
AudioCaptureSession* m_session;
};
+QT_END_NAMESPACE
+
#endif // AUDIOINPUTSELECTOR_H
diff --git a/src/plugins/audiocapture/audiomediarecordercontrol.cpp b/src/plugins/audiocapture/audiomediarecordercontrol.cpp
index c2b590fb3..9bc040246 100644
--- a/src/plugins/audiocapture/audiomediarecordercontrol.cpp
+++ b/src/plugins/audiocapture/audiomediarecordercontrol.cpp
@@ -44,15 +44,22 @@
#include <QtCore/qdebug.h>
+QT_BEGIN_NAMESPACE
+
AudioMediaRecorderControl::AudioMediaRecorderControl(QObject *parent)
- :QMediaRecorderControl(parent)
- , m_state(QMediaRecorder::StoppedState)
- , m_prevStatus(QMediaRecorder::UnloadedStatus)
+ : QMediaRecorderControl(parent)
{
m_session = qobject_cast<AudioCaptureSession*>(parent);
- connect(m_session,SIGNAL(positionChanged(qint64)),this,SIGNAL(durationChanged(qint64)));
- connect(m_session,SIGNAL(stateChanged(QMediaRecorder::State)), this,SLOT(updateStatus()));
- connect(m_session,SIGNAL(error(int,QString)),this,SLOT(handleSessionError(int,QString)));
+ connect(m_session, SIGNAL(positionChanged(qint64)),
+ this, SIGNAL(durationChanged(qint64)));
+ connect(m_session, SIGNAL(stateChanged(QMediaRecorder::State)),
+ this, SIGNAL(stateChanged(QMediaRecorder::State)));
+ connect(m_session, SIGNAL(statusChanged(QMediaRecorder::Status)),
+ this, SIGNAL(statusChanged(QMediaRecorder::Status)));
+ connect(m_session, SIGNAL(actualLocationChanged(QUrl)),
+ this, SIGNAL(actualLocationChanged(QUrl)));
+ connect(m_session, SIGNAL(error(int,QString)),
+ this, SIGNAL(error(int,QString)));
}
AudioMediaRecorderControl::~AudioMediaRecorderControl()
@@ -71,21 +78,12 @@ bool AudioMediaRecorderControl::setOutputLocation(const QUrl& sink)
QMediaRecorder::State AudioMediaRecorderControl::state() const
{
- return (QMediaRecorder::State)m_session->state();
+ return m_session->state();
}
QMediaRecorder::Status AudioMediaRecorderControl::status() const
{
- static QMediaRecorder::Status statusTable[3][3] = {
- //Stopped recorder state:
- { QMediaRecorder::LoadedStatus, QMediaRecorder::FinalizingStatus, QMediaRecorder::FinalizingStatus },
- //Recording recorder state:
- { QMediaRecorder::StartingStatus, QMediaRecorder::RecordingStatus, QMediaRecorder::PausedStatus },
- //Paused recorder state:
- { QMediaRecorder::StartingStatus, QMediaRecorder::RecordingStatus, QMediaRecorder::PausedStatus }
- };
-
- return statusTable[m_state][m_session->state()];
+ return m_session->status();
}
qint64 AudioMediaRecorderControl::duration() const
@@ -106,47 +104,19 @@ qreal AudioMediaRecorderControl::volume() const
void AudioMediaRecorderControl::setState(QMediaRecorder::State state)
{
- if (m_state == state)
- return;
-
- m_state = state;
-
- switch (state) {
- case QMediaRecorder::StoppedState:
- m_session->stop();
- break;
- case QMediaRecorder::PausedState:
- m_session->pause();
- break;
- case QMediaRecorder::RecordingState:
- m_session->record();
- break;
- }
-
- updateStatus();
+ m_session->setState(state);
}
-void AudioMediaRecorderControl::setMuted(bool)
+void AudioMediaRecorderControl::setMuted(bool muted)
{
+ if (muted)
+ qWarning("Muting the audio recording is not supported.");
}
void AudioMediaRecorderControl::setVolume(qreal volume)
{
if (!qFuzzyCompare(volume, qreal(1.0)))
- qWarning() << "Media service doesn't support recorder audio gain.";
-}
-
-void AudioMediaRecorderControl::updateStatus()
-{
- QMediaRecorder::Status newStatus = status();
- if (m_prevStatus != newStatus) {
- m_prevStatus = newStatus;
- emit statusChanged(m_prevStatus);
- }
+ qWarning("Changing the audio recording volume is not supported.");
}
-void AudioMediaRecorderControl::handleSessionError(int code, const QString &description)
-{
- emit error(code, description);
- setState(QMediaRecorder::StoppedState);
-}
+QT_END_NAMESPACE
diff --git a/src/plugins/audiocapture/audiomediarecordercontrol.h b/src/plugins/audiocapture/audiomediarecordercontrol.h
index 9f029e28e..050d12198 100644
--- a/src/plugins/audiocapture/audiomediarecordercontrol.h
+++ b/src/plugins/audiocapture/audiomediarecordercontrol.h
@@ -47,9 +47,9 @@
#include "qmediarecorder.h"
#include "qmediarecordercontrol.h"
-class AudioCaptureSession;
+QT_BEGIN_NAMESPACE
-QT_USE_NAMESPACE
+class AudioCaptureSession;
class AudioMediaRecorderControl : public QMediaRecorderControl
{
@@ -59,7 +59,7 @@ public:
~AudioMediaRecorderControl();
QUrl outputLocation() const;
- bool setOutputLocation(const QUrl &sink);
+ bool setOutputLocation(const QUrl &location);
QMediaRecorder::State state() const;
QMediaRecorder::Status status() const;
@@ -71,19 +71,14 @@ public:
void applySettings() {}
-public slots:
void setState(QMediaRecorder::State state);
void setMuted(bool);
void setVolume(qreal volume);
-private slots:
- void updateStatus();
- void handleSessionError(int code, const QString &description);
-
private:
AudioCaptureSession* m_session;
- QMediaRecorder::State m_state;
- QMediaRecorder::Status m_prevStatus;
};
+QT_END_NAMESPACE
+
#endif
diff --git a/src/plugins/blackberry/bbserviceplugin.cpp b/src/plugins/blackberry/bbserviceplugin.cpp
index 0a9abd71d..dab3caf9b 100644
--- a/src/plugins/blackberry/bbserviceplugin.cpp
+++ b/src/plugins/blackberry/bbserviceplugin.cpp
@@ -40,10 +40,8 @@
****************************************************************************/
#include "bbserviceplugin.h"
-#ifndef Q_OS_BLACKBERRY_TABLET
#include "bbcameraservice.h"
#include "bbvideodeviceselectorcontrol.h"
-#endif
#include "bbmediaplayerservice.h"
#include <QDebug>
@@ -56,10 +54,8 @@ BbServicePlugin::BbServicePlugin()
QMediaService *BbServicePlugin::create(const QString &key)
{
-#ifndef Q_OS_BLACKBERRY_TABLET
if (key == QLatin1String(Q_MEDIASERVICE_CAMERA))
return new BbCameraService();
-#endif
if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER))
return new BbMediaPlayerService();
@@ -106,9 +102,7 @@ QString BbServicePlugin::deviceDescription(const QByteArray &service, const QByt
void BbServicePlugin::updateDevices() const
{
-#ifndef Q_OS_BLACKBERRY_TABLET
BbVideoDeviceSelectorControl::enumerateDevices(&m_cameraDevices, &m_cameraDescriptions);
-#endif
if (m_cameraDevices.isEmpty()) {
qWarning() << "No camera devices found";
diff --git a/src/plugins/blackberry/blackberry.pro b/src/plugins/blackberry/blackberry.pro
index 5684645fb..e0a6233ce 100644
--- a/src/plugins/blackberry/blackberry.pro
+++ b/src/plugins/blackberry/blackberry.pro
@@ -12,9 +12,7 @@ SOURCES += bbserviceplugin.cpp
include(common/common.pri)
-!blackberry-playbook {
- include(camera/camera.pri)
-}
+include(camera/camera.pri)
include(mediaplayer/mediaplayer.pri)
diff --git a/src/plugins/blackberry/camera/bbcameraexposurecontrol.cpp b/src/plugins/blackberry/camera/bbcameraexposurecontrol.cpp
index a24fdbaf1..b1d637cd0 100644
--- a/src/plugins/blackberry/camera/bbcameraexposurecontrol.cpp
+++ b/src/plugins/blackberry/camera/bbcameraexposurecontrol.cpp
@@ -139,6 +139,7 @@ QVariant BbCameraExposureControl::requestedValue(ExposureParameter parameter) co
QVariant BbCameraExposureControl::actualValue(ExposureParameter parameter) const
{
+#ifndef Q_OS_BLACKBERRY_TABLET
if (parameter != QCameraExposureControl::ExposureMode) // no other parameter supported by BB10 API at the moment
return QVariantList();
@@ -170,6 +171,9 @@ QVariant BbCameraExposureControl::actualValue(ExposureParameter parameter) const
default:
return QVariant();
}
+#else
+ return QVariant();
+#endif
}
bool BbCameraExposureControl::setValue(ExposureParameter parameter, const QVariant& value)
diff --git a/src/plugins/blackberry/camera/bbcameramediarecordercontrol.cpp b/src/plugins/blackberry/camera/bbcameramediarecordercontrol.cpp
index a4a42abf8..44c19fb46 100644
--- a/src/plugins/blackberry/camera/bbcameramediarecordercontrol.cpp
+++ b/src/plugins/blackberry/camera/bbcameramediarecordercontrol.cpp
@@ -45,11 +45,14 @@
#include <QDebug>
#include <QUrl>
+#ifndef Q_OS_BLACKBERRY_TABLET
#include <audio/audio_manager_device.h>
#include <audio/audio_manager_volume.h>
+#endif
QT_BEGIN_NAMESPACE
+#ifndef Q_OS_BLACKBERRY_TABLET
static audio_manager_device_t currentAudioInputDevice()
{
audio_manager_device_t device = AUDIO_DEVICE_HEADSET;
@@ -62,6 +65,7 @@ static audio_manager_device_t currentAudioInputDevice()
return device;
}
+#endif
BbCameraMediaRecorderControl::BbCameraMediaRecorderControl(BbCameraSession *session, QObject *parent)
: QMediaRecorderControl(parent)
@@ -103,12 +107,13 @@ bool BbCameraMediaRecorderControl::isMuted() const
{
bool muted = false;
+#ifndef Q_OS_BLACKBERRY_TABLET
const int result = audio_manager_get_input_mute(currentAudioInputDevice(), &muted);
if (result != EOK) {
emit const_cast<BbCameraMediaRecorderControl*>(this)->error(QMediaRecorder::ResourceError, tr("Unable to retrieve mute status"));
return false;
}
-
+#endif
return muted;
}
@@ -116,11 +121,13 @@ qreal BbCameraMediaRecorderControl::volume() const
{
double level = 0.0;
+#ifndef Q_OS_BLACKBERRY_TABLET
const int result = audio_manager_get_input_level(currentAudioInputDevice(), &level);
if (result != EOK) {
emit const_cast<BbCameraMediaRecorderControl*>(this)->error(QMediaRecorder::ResourceError, tr("Unable to retrieve audio input volume"));
return 0.0;
}
+#endif
return (level / 100);
}
@@ -137,22 +144,26 @@ void BbCameraMediaRecorderControl::setState(QMediaRecorder::State state)
void BbCameraMediaRecorderControl::setMuted(bool muted)
{
+#ifndef Q_OS_BLACKBERRY_TABLET
const int result = audio_manager_set_input_mute(currentAudioInputDevice(), muted);
if (result != EOK) {
emit error(QMediaRecorder::ResourceError, tr("Unable to set mute status"));
} else {
emit mutedChanged(muted);
}
+#endif
}
void BbCameraMediaRecorderControl::setVolume(qreal volume)
{
+#ifndef Q_OS_BLACKBERRY_TABLET
const int result = audio_manager_set_input_level(currentAudioInputDevice(), (volume * 100));
if (result != EOK) {
emit error(QMediaRecorder::ResourceError, tr("Unable to set audio input volume"));
} else {
emit volumeChanged(volume);
}
+#endif
}
QT_END_NAMESPACE
diff --git a/src/plugins/blackberry/camera/bbcameraorientationhandler.cpp b/src/plugins/blackberry/camera/bbcameraorientationhandler.cpp
index 7e89162a8..b715249f9 100644
--- a/src/plugins/blackberry/camera/bbcameraorientationhandler.cpp
+++ b/src/plugins/blackberry/camera/bbcameraorientationhandler.cpp
@@ -70,9 +70,11 @@ BbCameraOrientationHandler::BbCameraOrientationHandler(QObject *parent)
BbCameraOrientationHandler::~BbCameraOrientationHandler()
{
+#ifndef Q_OS_BLACKBERRY_TABLET
const int result = orientation_stop_events(0);
if (result == BPS_FAILURE)
qWarning() << "Unable to unregister for orientation change events";
+#endif
QCoreApplication::eventDispatcher()->removeNativeEventFilter(this);
}
diff --git a/src/plugins/blackberry/camera/bbcamerasession.cpp b/src/plugins/blackberry/camera/bbcamerasession.cpp
index e7f82d5cb..64a075cb9 100644
--- a/src/plugins/blackberry/camera/bbcamerasession.cpp
+++ b/src/plugins/blackberry/camera/bbcamerasession.cpp
@@ -75,8 +75,6 @@ static QString errorToString(camera_error_t error)
return QLatin1String("No permission");
case CAMERA_EBADR:
return QLatin1String("Invalid file descriptor");
- case CAMERA_ENODATA:
- return QLatin1String("Data does not exist");
case CAMERA_ENOENT:
return QLatin1String("File or directory does not exists");
case CAMERA_ENOMEM:
@@ -87,24 +85,28 @@ static QString errorToString(camera_error_t error)
return QLatin1String("Communication timeout");
case CAMERA_EALREADY:
return QLatin1String("Operation already in progress");
- case CAMERA_EBUSY:
- return QLatin1String("Camera busy");
- case CAMERA_ENOSPC:
- return QLatin1String("Disk is full");
case CAMERA_EUNINIT:
return QLatin1String("Camera library not initialized");
case CAMERA_EREGFAULT:
return QLatin1String("Callback registration failed");
case CAMERA_EMICINUSE:
return QLatin1String("Microphone in use already");
+#ifndef Q_OS_BLACKBERRY_TABLET
+ case CAMERA_ENODATA:
+ return QLatin1String("Data does not exist");
+ case CAMERA_EBUSY:
+ return QLatin1String("Camera busy");
case CAMERA_EDESKTOPCAMERAINUSE:
return QLatin1String("Desktop camera in use already");
+ case CAMERA_ENOSPC:
+ return QLatin1String("Disk is full");
case CAMERA_EPOWERDOWN:
return QLatin1String("Camera in power down state");
case CAMERA_3ALOCKED:
return QLatin1String("3A have been locked");
case CAMERA_EVIEWFINDERFROZEN:
return QLatin1String("Freeze flag set");
+#endif
default:
return QLatin1String("Unknown error");
}
@@ -658,6 +660,9 @@ void BbCameraSession::applyVideoSettings()
return;
}
+ const QSize resolution = m_videoEncoderSettings.resolution();
+
+#ifndef Q_OS_BLACKBERRY_TABLET
QString videoCodec = m_videoEncoderSettings.codec();
if (videoCodec.isEmpty())
videoCodec = QLatin1String("h264");
@@ -670,8 +675,6 @@ void BbCameraSession::applyVideoSettings()
else if (videoCodec == QLatin1String("h264"))
cameraVideoCodec = CAMERA_VIDEOCODEC_H264;
- const QSize resolution = m_videoEncoderSettings.resolution();
-
qreal frameRate = m_videoEncoderSettings.frameRate();
if (frameRate == 0) {
const QList<qreal> frameRates = supportedFrameRates(QVideoEncoderSettings(), 0);
@@ -690,12 +693,16 @@ void BbCameraSession::applyVideoSettings()
cameraAudioCodec = CAMERA_AUDIOCODEC_AAC;
else if (audioCodec == QLatin1String("raw"))
cameraAudioCodec = CAMERA_AUDIOCODEC_RAW;
-
result = camera_set_video_property(m_handle,
CAMERA_IMGPROP_WIDTH, resolution.width(),
CAMERA_IMGPROP_HEIGHT, resolution.height(),
CAMERA_IMGPROP_VIDEOCODEC, cameraVideoCodec,
CAMERA_IMGPROP_AUDIOCODEC, cameraAudioCodec);
+#else
+ result = camera_set_video_property(m_handle,
+ CAMERA_IMGPROP_WIDTH, resolution.width(),
+ CAMERA_IMGPROP_HEIGHT, resolution.height());
+#endif
if (result != CAMERA_EOK) {
qWarning() << "Unable to apply video settings:" << result;
@@ -979,10 +986,14 @@ static void viewFinderStatusCallback(camera_handle_t handle, camera_devstatus_t
if (status == CAMERA_STATUS_FOCUS_CHANGE) {
BbCameraSession *session = static_cast<BbCameraSession*>(context);
QMetaObject::invokeMethod(session, "handleFocusStatusChanged", Qt::QueuedConnection, Q_ARG(int, value));
- } else if (status == CAMERA_STATUS_POWERUP) {
+ return;
+ }
+#ifndef Q_OS_BLACKBERRY_TABLET
+ else if (status == CAMERA_STATUS_POWERUP) {
BbCameraSession *session = static_cast<BbCameraSession*>(context);
QMetaObject::invokeMethod(session, "handleCameraPowerUp", Qt::QueuedConnection);
}
+#endif
}
bool BbCameraSession::startViewFinder()
@@ -1159,6 +1170,7 @@ static void videoRecordingStatusCallback(camera_handle_t handle, camera_devstatu
Q_UNUSED(handle)
Q_UNUSED(value)
+#ifndef Q_OS_BLACKBERRY_TABLET
if (status == CAMERA_STATUS_VIDEO_PAUSE) {
BbCameraSession *session = static_cast<BbCameraSession*>(context);
QMetaObject::invokeMethod(session, "handleVideoRecordingPaused", Qt::QueuedConnection);
@@ -1166,6 +1178,7 @@ static void videoRecordingStatusCallback(camera_handle_t handle, camera_devstatu
BbCameraSession *session = static_cast<BbCameraSession*>(context);
QMetaObject::invokeMethod(session, "handleVideoRecordingResumed", Qt::QueuedConnection);
}
+#endif
}
bool BbCameraSession::startVideoRecording()
diff --git a/src/plugins/blackberry/camera/bbcameraviewfindersettingscontrol.cpp b/src/plugins/blackberry/camera/bbcameraviewfindersettingscontrol.cpp
index a63d7a731..5c7671e80 100644
--- a/src/plugins/blackberry/camera/bbcameraviewfindersettingscontrol.cpp
+++ b/src/plugins/blackberry/camera/bbcameraviewfindersettingscontrol.cpp
@@ -156,10 +156,12 @@ QVariant BbCameraViewfinderSettingsControl::viewfinderParameter(ViewfinderParame
return QVideoFrame::Format_Invalid;
case CAMERA_FRAMETYPE_CBYCRY:
return QVideoFrame::Format_Invalid;
+#ifndef Q_OS_BLACKBERRY_TABLET
case CAMERA_FRAMETYPE_COMPRESSEDVIDEO:
return QVideoFrame::Format_Invalid;
case CAMERA_FRAMETYPE_COMPRESSEDAUDIO:
return QVideoFrame::Format_Invalid;
+#endif
default:
return QVideoFrame::Format_Invalid;
}
diff --git a/src/plugins/blackberry/camera/camera.pri b/src/plugins/blackberry/camera/camera.pri
index 8186cdcc6..6665573b0 100644
--- a/src/plugins/blackberry/camera/camera.pri
+++ b/src/plugins/blackberry/camera/camera.pri
@@ -46,4 +46,8 @@ SOURCES += \
$$PWD/bbvideodeviceselectorcontrol.cpp \
$$PWD/bbvideorenderercontrol.cpp
-LIBS += -lcamapi -laudio_manager
+LIBS += -lcamapi
+
+!blackberry-playbook {
+ LIBS += -laudio_manager
+}
diff --git a/src/plugins/directshow/player/directshowmetadatacontrol.cpp b/src/plugins/directshow/player/directshowmetadatacontrol.cpp
index 341d2cf1d..3c81ae180 100644
--- a/src/plugins/directshow/player/directshowmetadatacontrol.cpp
+++ b/src/plugins/directshow/player/directshowmetadatacontrol.cpp
@@ -39,6 +39,12 @@
**
****************************************************************************/
+#include <QtMultimedia/qmediametadata.h>
+#include <QtCore/qcoreapplication.h>
+#include <QSize>
+#include <qdatetime.h>
+#include <qimage.h>
+
#include <dshow.h>
#include <initguid.h>
#include <qnetwork.h>
@@ -46,8 +52,56 @@
#include "directshowmetadatacontrol.h"
#include "directshowplayerservice.h"
-#include <QtMultimedia/qmediametadata.h>
-#include <QtCore/qcoreapplication.h>
+#ifndef QT_NO_WMSDK
+#include <wmsdk.h>
+#endif
+
+#ifndef QT_NO_SHELLITEM
+#include <ShlObj.h>
+#include <propkeydef.h>
+#include <private/qsystemlibrary_p.h>
+
+DEFINE_PROPERTYKEY(PKEY_Author, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 4);
+DEFINE_PROPERTYKEY(PKEY_Title, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 2);
+DEFINE_PROPERTYKEY(PKEY_Media_SubTitle, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 38);
+DEFINE_PROPERTYKEY(PKEY_ParentalRating, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 21);
+DEFINE_PROPERTYKEY(PKEY_Comment, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 6);
+DEFINE_PROPERTYKEY(PKEY_Copyright, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 11);
+DEFINE_PROPERTYKEY(PKEY_Media_ProviderStyle, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 40);
+DEFINE_PROPERTYKEY(PKEY_Media_Year, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 5);
+DEFINE_PROPERTYKEY(PKEY_Media_DateEncoded, 0x2E4B640D, 0x5019, 0x46D8, 0x88, 0x81, 0x55, 0x41, 0x4C, 0xC5, 0xCA, 0xA0, 100);
+DEFINE_PROPERTYKEY(PKEY_Rating, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 9);
+DEFINE_PROPERTYKEY(PKEY_Keywords, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 5);
+DEFINE_PROPERTYKEY(PKEY_Language, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 28);
+DEFINE_PROPERTYKEY(PKEY_Media_Publisher, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 30);
+DEFINE_PROPERTYKEY(PKEY_Media_Duration, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 3);
+DEFINE_PROPERTYKEY(PKEY_Audio_EncodingBitrate, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 4);
+DEFINE_PROPERTYKEY(PKEY_Media_AverageLevel, 0x09EDD5B6, 0xB301, 0x43C5, 0x99, 0x90, 0xD0, 0x03, 0x02, 0xEF, 0xFD, 0x46, 100);
+DEFINE_PROPERTYKEY(PKEY_Audio_ChannelCount, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 7);
+DEFINE_PROPERTYKEY(PKEY_Audio_PeakValue, 0x2579E5D0, 0x1116, 0x4084, 0xBD, 0x9A, 0x9B, 0x4F, 0x7C, 0xB4, 0xDF, 0x5E, 100);
+DEFINE_PROPERTYKEY(PKEY_Audio_SampleRate, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 5);
+DEFINE_PROPERTYKEY(PKEY_Music_AlbumTitle, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 4);
+DEFINE_PROPERTYKEY(PKEY_Music_AlbumArtist, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 13);
+DEFINE_PROPERTYKEY(PKEY_Music_Artist, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 2);
+DEFINE_PROPERTYKEY(PKEY_Music_Composer, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 19);
+DEFINE_PROPERTYKEY(PKEY_Music_Conductor, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 36);
+DEFINE_PROPERTYKEY(PKEY_Music_Lyrics, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 12);
+DEFINE_PROPERTYKEY(PKEY_Music_Mood, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 39);
+DEFINE_PROPERTYKEY(PKEY_Music_TrackNumber, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 7);
+DEFINE_PROPERTYKEY(PKEY_Music_Genre, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 11);
+DEFINE_PROPERTYKEY(PKEY_ThumbnailStream, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 27);
+DEFINE_PROPERTYKEY(PKEY_Video_FrameHeight, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 4);
+DEFINE_PROPERTYKEY(PKEY_Video_FrameWidth, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 3);
+DEFINE_PROPERTYKEY(PKEY_Video_HorizontalAspectRatio, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 42);
+DEFINE_PROPERTYKEY(PKEY_Video_VerticalAspectRatio, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 45);
+DEFINE_PROPERTYKEY(PKEY_Video_FrameRate, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 6);
+DEFINE_PROPERTYKEY(PKEY_Video_EncodingBitrate, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 8);
+DEFINE_PROPERTYKEY(PKEY_Video_Director, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 20);
+DEFINE_PROPERTYKEY(PKEY_Media_Writer, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 23);
+
+typedef HRESULT (WINAPI *q_SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **);
+static q_SHCreateItemFromParsingName sHCreateItemFromParsingName = 0;
+#endif
#ifndef QT_NO_WMSDK
namespace
@@ -70,12 +124,12 @@ static const QWMMetaDataKeyLookup qt_wmMetaDataKeys[] =
{ QMediaMetaData::Genre, L"WM/Genre" },
//{ QMediaMetaData::Date, 0 },
{ QMediaMetaData::Year, L"WM/Year" },
- { QMediaMetaData::UserRating, L"UserRating" },
+ { QMediaMetaData::UserRating, L"Rating" },
//{ QMediaMetaData::MetaDatawords, 0 },
- { QMediaMetaData::Language, L"Language" },
+ { QMediaMetaData::Language, L"WM/Language" },
{ QMediaMetaData::Publisher, L"WM/Publisher" },
{ QMediaMetaData::Copyright, L"Copyright" },
- { QMediaMetaData::ParentalRating, L"ParentalRating" },
+ { QMediaMetaData::ParentalRating, L"WM/ParentalRating" },
//{ QMediaMetaData::RatingOrganisation, L"RatingOrganisation" },
// Media
@@ -103,11 +157,11 @@ static const QWMMetaDataKeyLookup qt_wmMetaDataKeys[] =
//{ QMediaMetaData::CoverArtUriLarge, 0 },
// Image/Video
- //{ QMediaMetaData::Resolution, 0 },
- //{ QMediaMetaData::PixelAspectRatio, 0 },
+ { QMediaMetaData::Resolution, L"WM/VideoHeight" },
+ { QMediaMetaData::PixelAspectRatio, L"AspectRatioX" },
// Video
- //{ QMediaMetaData::FrameRate, 0 },
+ { QMediaMetaData::VideoFrameRate, L"WM/VideoFrameRate" },
{ QMediaMetaData::VideoBitRate, L"VideoBitRate" },
{ QMediaMetaData::VideoCodec, L"VideoCodec" },
@@ -118,12 +172,6 @@ static const QWMMetaDataKeyLookup qt_wmMetaDataKeys[] =
{ QMediaMetaData::Director, L"WM/Director" },
{ QMediaMetaData::LeadPerformer, L"LeadPerformer" },
{ QMediaMetaData::Writer, L"WM/Writer" },
-
- // Photos
- { QMediaMetaData::CameraManufacturer, L"CameraManufacturer" },
- { QMediaMetaData::CameraModel, L"CameraModel" },
- { QMediaMetaData::Event, L"Event" },
- { QMediaMetaData::Subject, L"Subject" }
};
static QVariant getValue(IWMHeaderInfo *header, const wchar_t *key)
@@ -150,7 +198,7 @@ static QVariant getValue(IWMHeaderInfo *header, const wchar_t *key)
case WMT_TYPE_STRING:
{
QString string;
- string.resize(size / 2 - 1);
+ string.resize(size / 2); // size is in bytes, string is in UTF16
if (header->GetAttributeByName(
&streamNumber,
@@ -227,12 +275,58 @@ static QVariant getValue(IWMHeaderInfo *header, const wchar_t *key)
}
#endif
+#ifndef QT_NO_SHELLITEM
+static QVariant convertValue(const PROPVARIANT& var)
+{
+ QVariant value;
+ switch (var.vt) {
+ case VT_LPWSTR:
+ value = QString::fromUtf16(reinterpret_cast<const ushort*>(var.pwszVal));
+ break;
+ case VT_UI4:
+ value = uint(var.ulVal);
+ break;
+ case VT_UI8:
+ value = qulonglong(var.uhVal.QuadPart);
+ break;
+ case VT_BOOL:
+ value = bool(var.boolVal);
+ break;
+ case VT_FILETIME:
+ SYSTEMTIME sysDate;
+ if (!FileTimeToSystemTime(&var.filetime, &sysDate))
+ break;
+ value = QDate(sysDate.wYear, sysDate.wMonth, sysDate.wDay);
+ break;
+ case VT_STREAM:
+ {
+ STATSTG stat;
+ if (FAILED(var.pStream->Stat(&stat, STATFLAG_NONAME)))
+ break;
+ void *data = malloc(stat.cbSize.QuadPart);
+ ULONG read = 0;
+ if (FAILED(var.pStream->Read(data, stat.cbSize.QuadPart, &read))) {
+ free(data);
+ break;
+ }
+ value = QImage::fromData(reinterpret_cast<const uchar*>(data), read);
+ free(data);
+ }
+ break;
+ case VT_VECTOR | VT_LPWSTR:
+ QStringList vList;
+ for (ULONG i = 0; i < var.calpwstr.cElems; ++i)
+ vList.append(QString::fromUtf16(reinterpret_cast<const ushort*>(var.calpwstr.pElems[i])));
+ value = vList;
+ break;
+ }
+ return value;
+}
+#endif
+
DirectShowMetaDataControl::DirectShowMetaDataControl(QObject *parent)
: QMetaDataReaderControl(parent)
- , m_content(0)
-#ifndef QT_NO_WMSDK
- , m_headerInfo(0)
-#endif
+ , m_available(false)
{
}
@@ -242,75 +336,229 @@ DirectShowMetaDataControl::~DirectShowMetaDataControl()
bool DirectShowMetaDataControl::isMetaDataAvailable() const
{
-#ifndef QT_NO_WMSDK
- return m_content || m_headerInfo;
-#else
- return m_content;
-#endif
+ return m_available;
}
QVariant DirectShowMetaDataControl::metaData(const QString &key) const
{
- QVariant value;
+ return m_metadata.value(key);
+}
+
+QStringList DirectShowMetaDataControl::availableMetaData() const
+{
+ return m_metadata.keys();
+}
+
+static QString convertBSTR(BSTR *string)
+{
+ QString value = QString::fromUtf16(reinterpret_cast<ushort *>(*string),
+ ::SysStringLen(*string));
+
+ ::SysFreeString(*string);
+ string = 0;
+
+ return value;
+}
+
+void DirectShowMetaDataControl::updateGraph(IFilterGraph2 *graph, IBaseFilter *source, const QString &fileSrc)
+{
+ m_metadata.clear();
+
+#ifndef QT_NO_SHELLITEM
+ if (!sHCreateItemFromParsingName) {
+ QSystemLibrary lib(QStringLiteral("shell32"));
+ sHCreateItemFromParsingName = (q_SHCreateItemFromParsingName)(lib.resolve("SHCreateItemFromParsingName"));
+ }
+
+ if (!fileSrc.isEmpty() && sHCreateItemFromParsingName) {
+ IShellItem2* shellItem = 0;
+ if (sHCreateItemFromParsingName(reinterpret_cast<const WCHAR*>(fileSrc.utf16()),
+ 0, IID_PPV_ARGS(&shellItem)) == S_OK) {
+
+ IPropertyStore *pStore = 0;
+ if (shellItem->GetPropertyStore(GPS_DEFAULT, IID_PPV_ARGS(&pStore)) == S_OK) {
+ DWORD cProps;
+ if (SUCCEEDED(pStore->GetCount(&cProps))) {
+ for (DWORD i = 0; i < cProps; ++i)
+ {
+ PROPERTYKEY key;
+ PROPVARIANT var;
+ PropVariantInit(&var);
+ if (FAILED(pStore->GetAt(i, &key)))
+ continue;
+ if (FAILED(pStore->GetValue(key, &var)))
+ continue;
+
+ if (key == PKEY_Author) {
+ m_metadata.insert(QMediaMetaData::Author, convertValue(var));
+ } else if (key == PKEY_Title) {
+ m_metadata.insert(QMediaMetaData::Title, convertValue(var));
+ } else if (key == PKEY_Media_SubTitle) {
+ m_metadata.insert(QMediaMetaData::SubTitle, convertValue(var));
+ } else if (key == PKEY_ParentalRating) {
+ m_metadata.insert(QMediaMetaData::ParentalRating, convertValue(var));
+ } else if (key == PKEY_Comment) {
+ m_metadata.insert(QMediaMetaData::Description, convertValue(var));
+ } else if (key == PKEY_Copyright) {
+ m_metadata.insert(QMediaMetaData::Copyright, convertValue(var));
+ } else if (key == PKEY_Media_ProviderStyle) {
+ m_metadata.insert(QMediaMetaData::Genre, convertValue(var));
+ } else if (key == PKEY_Media_Year) {
+ m_metadata.insert(QMediaMetaData::Year, convertValue(var));
+ } else if (key == PKEY_Media_DateEncoded) {
+ m_metadata.insert(QMediaMetaData::Date, convertValue(var));
+ } else if (key == PKEY_Rating) {
+ m_metadata.insert(QMediaMetaData::UserRating,
+ int((convertValue(var).toUInt() - 1) / qreal(98) * 100));
+ } else if (key == PKEY_Keywords) {
+ m_metadata.insert(QMediaMetaData::Keywords, convertValue(var));
+ } else if (key == PKEY_Language) {
+ m_metadata.insert(QMediaMetaData::Language, convertValue(var));
+ } else if (key == PKEY_Media_Publisher) {
+ m_metadata.insert(QMediaMetaData::Publisher, convertValue(var));
+ } else if (key == PKEY_Media_Duration) {
+ m_metadata.insert(QMediaMetaData::Duration,
+ (convertValue(var).toLongLong() + 10000) / 10000);
+ } else if (key == PKEY_Audio_EncodingBitrate) {
+ m_metadata.insert(QMediaMetaData::AudioBitRate, convertValue(var));
+ } else if (key == PKEY_Media_AverageLevel) {
+ m_metadata.insert(QMediaMetaData::AverageLevel, convertValue(var));
+ } else if (key == PKEY_Audio_ChannelCount) {
+ m_metadata.insert(QMediaMetaData::ChannelCount, convertValue(var));
+ } else if (key == PKEY_Audio_PeakValue) {
+ m_metadata.insert(QMediaMetaData::PeakValue, convertValue(var));
+ } else if (key == PKEY_Audio_SampleRate) {
+ m_metadata.insert(QMediaMetaData::SampleRate, convertValue(var));
+ } else if (key == PKEY_Music_AlbumTitle) {
+ m_metadata.insert(QMediaMetaData::AlbumTitle, convertValue(var));
+ } else if (key == PKEY_Music_AlbumArtist) {
+ m_metadata.insert(QMediaMetaData::AlbumArtist, convertValue(var));
+ } else if (key == PKEY_Music_Artist) {
+ m_metadata.insert(QMediaMetaData::ContributingArtist, convertValue(var));
+ } else if (key == PKEY_Music_Composer) {
+ m_metadata.insert(QMediaMetaData::Composer, convertValue(var));
+ } else if (key == PKEY_Music_Conductor) {
+ m_metadata.insert(QMediaMetaData::Conductor, convertValue(var));
+ } else if (key == PKEY_Music_Lyrics) {
+ m_metadata.insert(QMediaMetaData::Lyrics, convertValue(var));
+ } else if (key == PKEY_Music_Mood) {
+ m_metadata.insert(QMediaMetaData::Mood, convertValue(var));
+ } else if (key == PKEY_Music_TrackNumber) {
+ m_metadata.insert(QMediaMetaData::TrackNumber, convertValue(var));
+ } else if (key == PKEY_Music_Genre) {
+ m_metadata.insert(QMediaMetaData::Genre, convertValue(var));
+ } else if (key == PKEY_ThumbnailStream) {
+ m_metadata.insert(QMediaMetaData::ThumbnailImage, convertValue(var));
+ } else if (key == PKEY_Video_FrameHeight) {
+ QSize res;
+ res.setHeight(convertValue(var).toUInt());
+ if (SUCCEEDED(pStore->GetValue(PKEY_Video_FrameWidth, &var)))
+ res.setWidth(convertValue(var).toUInt());
+ m_metadata.insert(QMediaMetaData::Resolution, res);
+ } else if (key == PKEY_Video_HorizontalAspectRatio) {
+ QSize aspectRatio;
+ aspectRatio.setWidth(convertValue(var).toUInt());
+ if (SUCCEEDED(pStore->GetValue(PKEY_Video_VerticalAspectRatio, &var)))
+ aspectRatio.setHeight(convertValue(var).toUInt());
+ m_metadata.insert(QMediaMetaData::PixelAspectRatio, aspectRatio);
+ } else if (key == PKEY_Video_FrameRate) {
+ m_metadata.insert(QMediaMetaData::VideoFrameRate,
+ convertValue(var).toReal() / 1000);
+ } else if (key == PKEY_Video_EncodingBitrate) {
+ m_metadata.insert(QMediaMetaData::VideoBitRate, convertValue(var));
+ } else if (key == PKEY_Video_Director) {
+ m_metadata.insert(QMediaMetaData::Director, convertValue(var));
+ } else if (key == PKEY_Media_Writer) {
+ m_metadata.insert(QMediaMetaData::Writer, convertValue(var));
+ }
+
+ PropVariantClear(&var);
+ }
+ }
+
+ pStore->Release();
+ }
+
+ shellItem->Release();
+ }
+ }
+
+ if (!m_metadata.isEmpty())
+ goto send_event;
+#endif
#ifndef QT_NO_WMSDK
- if (m_headerInfo) {
+ IWMHeaderInfo *info = com_cast<IWMHeaderInfo>(source, IID_IWMHeaderInfo);
+
+ if (info) {
static const int count = sizeof(qt_wmMetaDataKeys) / sizeof(QWMMetaDataKeyLookup);
for (int i = 0; i < count; ++i) {
- if (qt_wmMetaDataKeys[i].key == key) {
- value = getValue(m_headerInfo, qt_wmMetaDataKeys[i].token);
- break;
+ QVariant var = getValue(info, qt_wmMetaDataKeys[i].token);
+ if (var.isValid()) {
+ QString key = qt_wmMetaDataKeys[i].key;
+
+ if (key == QMediaMetaData::Duration) {
+ // duration is provided in 100-nanosecond units, convert to milliseconds
+ var = (var.toLongLong() + 10000) / 10000;
+ } else if (key == QMediaMetaData::Resolution) {
+ QSize res;
+ res.setHeight(var.toUInt());
+ res.setWidth(getValue(info, L"WM/VideoWidth").toUInt());
+ var = res;
+ } else if (key == QMediaMetaData::VideoFrameRate) {
+ var = var.toReal() / 1000.f;
+ } else if (key == QMediaMetaData::PixelAspectRatio) {
+ QSize aspectRatio;
+ aspectRatio.setWidth(var.toUInt());
+ aspectRatio.setHeight(getValue(info, L"AspectRatioY").toUInt());
+ var = aspectRatio;
+ } else if (key == QMediaMetaData::UserRating) {
+ var = (var.toUInt() - 1) / qreal(98) * 100;
+ }
+
+ m_metadata.insert(key, var);
}
}
- } else if (m_content) {
-#else
- if (m_content) {
+
+ info->Release();
+ }
+
+ if (!m_metadata.isEmpty())
+ goto send_event;
#endif
- BSTR string = 0;
-
- if (key == QMediaMetaData::Author)
- m_content->get_AuthorName(&string);
- else if (key == QMediaMetaData::Title)
- m_content->get_Title(&string);
- else if (key == QMediaMetaData::ParentalRating)
- m_content->get_Rating(&string);
- else if (key == QMediaMetaData::Description)
- m_content->get_Description(&string);
- else if (key == QMediaMetaData::Copyright)
- m_content->get_Copyright(&string);
-
- if (string) {
- value = QString::fromUtf16(reinterpret_cast<ushort *>(string), ::SysStringLen(string));
-
- ::SysFreeString(string);
+ {
+ IAMMediaContent *content = 0;
+
+ if ((!graph || graph->QueryInterface(
+ IID_IAMMediaContent, reinterpret_cast<void **>(&content)) != S_OK)
+ && (!source || source->QueryInterface(
+ IID_IAMMediaContent, reinterpret_cast<void **>(&content)) != S_OK)) {
+ content = 0;
}
- }
- return value;
-}
-QStringList DirectShowMetaDataControl::availableMetaData() const
-{
- return QStringList();
-}
+ if (content) {
+ BSTR string = 0;
-void DirectShowMetaDataControl::updateGraph(IFilterGraph2 *graph, IBaseFilter *source)
-{
- if (m_content)
- m_content->Release();
+ if (content->get_AuthorName(&string) == S_OK)
+ m_metadata.insert(QMediaMetaData::Author, convertBSTR(&string));
- if (!graph || graph->QueryInterface(
- IID_IAMMediaContent, reinterpret_cast<void **>(&m_content)) != S_OK) {
- m_content = 0;
- }
+ if (content->get_Title(&string) == S_OK)
+ m_metadata.insert(QMediaMetaData::Title, convertBSTR(&string));
-#ifdef QT_NO_WMSDK
- Q_UNUSED(source);
-#else
- if (m_headerInfo)
- m_headerInfo->Release();
+ if (content->get_Description(&string) == S_OK)
+ m_metadata.insert(QMediaMetaData::Description, convertBSTR(&string));
- m_headerInfo = com_cast<IWMHeaderInfo>(source, IID_IWMHeaderInfo);
-#endif
+ if (content->get_Rating(&string) == S_OK)
+ m_metadata.insert(QMediaMetaData::UserRating, convertBSTR(&string));
+
+ if (content->get_Copyright(&string) == S_OK)
+ m_metadata.insert(QMediaMetaData::Copyright, convertBSTR(&string));
+
+ content->Release();
+ }
+ }
+
+send_event:
// DirectShowMediaPlayerService holds a lock at this point so defer emitting signals to a later
// time.
QCoreApplication::postEvent(this, new QEvent(QEvent::Type(MetaDataChanged)));
@@ -321,12 +569,12 @@ void DirectShowMetaDataControl::customEvent(QEvent *event)
if (event->type() == QEvent::Type(MetaDataChanged)) {
event->accept();
+ bool oldAvailable = m_available;
+ m_available = !m_metadata.isEmpty();
+ if (m_available != oldAvailable)
+ emit metaDataAvailableChanged(m_available);
+
emit metaDataChanged();
-#ifndef QT_NO_WMSDK
- emit metaDataAvailableChanged(m_content || m_headerInfo);
-#else
- emit metaDataAvailableChanged(m_content);
-#endif
} else {
QMetaDataReaderControl::customEvent(event);
}
diff --git a/src/plugins/directshow/player/directshowmetadatacontrol.h b/src/plugins/directshow/player/directshowmetadatacontrol.h
index fb740ee1c..935e75ee0 100644
--- a/src/plugins/directshow/player/directshowmetadatacontrol.h
+++ b/src/plugins/directshow/player/directshowmetadatacontrol.h
@@ -46,12 +46,6 @@
#include "directshowglobal.h"
-#include <qnetwork.h>
-
-#ifndef QT_NO_WMSDK
-#include <wmsdk.h>
-#endif
-
#include <QtCore/qcoreevent.h>
class DirectShowPlayerService;
@@ -70,7 +64,8 @@ public:
QVariant metaData(const QString &key) const;
QStringList availableMetaData() const;
- void updateGraph(IFilterGraph2 *graph, IBaseFilter *source);
+ void updateGraph(IFilterGraph2 *graph, IBaseFilter *source,
+ const QString &fileSrc = QString());
protected:
void customEvent(QEvent *event);
@@ -81,10 +76,8 @@ private:
MetaDataChanged = QEvent::User
};
- IAMMediaContent *m_content;
-#ifndef QT_NO_WMSDK
- IWMHeaderInfo *m_headerInfo;
-#endif
+ QVariantMap m_metadata;
+ bool m_available;
};
#endif
diff --git a/src/plugins/directshow/player/directshowplayerservice.cpp b/src/plugins/directshow/player/directshowplayerservice.cpp
index 70049e245..9d74be592 100644
--- a/src/plugins/directshow/player/directshowplayerservice.cpp
+++ b/src/plugins/directshow/player/directshowplayerservice.cpp
@@ -50,6 +50,10 @@
#include "vmr9videowindowcontrol.h"
#endif
+#ifndef QT_NO_WMSDK
+#include <wmsdk.h>
+#endif
+
#include "qmediacontent.h"
#include <QtCore/qcoreapplication.h>
@@ -268,11 +272,10 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker)
IBaseFilter *source = 0;
QMediaResource resource = m_resources.takeFirst();
- QUrl url = resource.url();
+ m_url = resource.url();
HRESULT hr = E_FAIL;
-
- if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https")) {
+ if (m_url.scheme() == QLatin1String("http") || m_url.scheme() == QLatin1String("https")) {
static const GUID clsid_WMAsfReader = {
0x187463a0, 0x5bb7, 0x11d3, {0xac, 0xbe, 0x00, 0x80, 0xc7, 0x5e, 0x24, 0x6e} };
@@ -283,7 +286,7 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker)
if (IFileSourceFilter *fileSource = com_new<IFileSourceFilter>(
clsid_WMAsfReader, iid_IFileSourceFilter)) {
locker->unlock();
- hr = fileSource->Load(reinterpret_cast<const OLECHAR *>(url.toString().utf16()), 0);
+ hr = fileSource->Load(reinterpret_cast<const OLECHAR *>(m_url.toString().utf16()), 0);
if (SUCCEEDED(hr)) {
source = com_cast<IBaseFilter>(fileSource, IID_IBaseFilter);
@@ -296,11 +299,11 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker)
fileSource->Release();
locker->relock();
}
- } else if (url.scheme() == QLatin1String("qrc")) {
+ } else if (m_url.scheme() == QLatin1String("qrc")) {
DirectShowRcSource *rcSource = new DirectShowRcSource(m_loop);
locker->unlock();
- if (rcSource->open(url) && SUCCEEDED(hr = m_graph->AddFilter(rcSource, L"Source")))
+ if (rcSource->open(m_url) && SUCCEEDED(hr = m_graph->AddFilter(rcSource, L"Source")))
source = rcSource;
else
rcSource->Release();
@@ -310,7 +313,7 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker)
if (!SUCCEEDED(hr)) {
locker->unlock();
hr = m_graph->AddSourceFilter(
- reinterpret_cast<const OLECHAR *>(url.toString().utf16()), L"Source", &source);
+ reinterpret_cast<const OLECHAR *>(m_url.toString().utf16()), L"Source", &source);
locker->relock();
}
@@ -1128,7 +1131,7 @@ void DirectShowPlayerService::customEvent(QEvent *event)
QMutexLocker locker(&m_mutex);
m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
- m_metaDataControl->updateGraph(m_graph, m_source);
+ m_metaDataControl->updateGraph(m_graph, m_source, m_url.toString());
updateStatus();
} else if (event->type() == QEvent::Type(Error)) {
diff --git a/src/plugins/directshow/player/player.pri b/src/plugins/directshow/player/player.pri
index e9675c2c9..c5c934a38 100644
--- a/src/plugins/directshow/player/player.pri
+++ b/src/plugins/directshow/player/player.pri
@@ -43,5 +43,11 @@ qtHaveModule(widgets):!simulator {
$$PWD/vmr9videowindowcontrol.cpp
}
+config_wshellitem {
+ QT += core-private
+} else {
+ DEFINES += QT_NO_SHELLITEM
+}
+
LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 -lgdi32
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index 5da1bb739..15d5a0b9b 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -17,7 +17,7 @@ blackberry {
}
qnx {
- SUBDIRS += qnx
+ SUBDIRS += audiocapture qnx
}
win32 {