Merge remote-tracking branch 'origin/5.5' into dev

Change-Id: I7ac7db69c37cc9e5c5241a25b9a874986a23a886
This commit is contained in:
Liang Qi
2015-06-03 10:58:51 +02:00
63 changed files with 1848 additions and 363 deletions

View File

@@ -98,7 +98,10 @@ QGstreamerVideoWidgetControl::QGstreamerVideoWidgetControl(QObject *parent)
, m_widget(0)
, m_fullScreen(false)
{
m_videoSink = gst_element_factory_make ("xvimagesink", NULL);
// The QWidget needs to have a native X window handle to be able to use xvimagesink.
// Bail out if Qt is not using xcb (the control will then be ignored by the plugin)
if (QGuiApplication::platformName().compare(QLatin1String("xcb"), Qt::CaseInsensitive) == 0)
m_videoSink = gst_element_factory_make ("xvimagesink", NULL);
if (m_videoSink) {
// Check if the xv sink is usable

View File

@@ -35,6 +35,7 @@
#include <private/qgstutils_p.h>
#include <QtCore/qdebug.h>
#include <QtGui/qguiapplication.h>
#include <gst/gst.h>
@@ -57,7 +58,9 @@ QGstreamerVideoWindow::QGstreamerVideoWindow(QObject *parent, const char *elemen
{
if (elementName) {
m_videoSink = gst_element_factory_make(elementName, NULL);
} else {
} else if (QGuiApplication::platformName().compare(QLatin1String("xcb"), Qt::CaseInsensitive) == 0) {
// We need a native X window handle to be able to use xvimagesink.
// Bail out if Qt is not using xcb (the control will then be ignored by the plugin)
m_videoSink = gst_element_factory_make("xvimagesink", NULL);
}
@@ -68,8 +71,6 @@ QGstreamerVideoWindow::QGstreamerVideoWindow(QObject *parent, const char *elemen
addProbeToPad(pad);
gst_object_unref(GST_OBJECT(pad));
}
else
qDebug() << "No m_videoSink available!";
}
QGstreamerVideoWindow::~QGstreamerVideoWindow()

View File

@@ -222,6 +222,17 @@ bool QVideoSurfaceGstDelegate::proposeAllocation(GstQuery *query)
}
}
void QVideoSurfaceGstDelegate::flush()
{
QMutexLocker locker(&m_mutex);
m_flush = true;
m_renderBuffer = 0;
m_renderCondition.wakeAll();
notify();
}
GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer)
{
QMutexLocker locker(&m_mutex);
@@ -388,6 +399,8 @@ QGstVideoRendererSink *QGstVideoRendererSink::createSink(QAbstractVideoSurface *
sink->delegate = new QVideoSurfaceGstDelegate(surface);
g_signal_connect(G_OBJECT(sink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), sink);
return sink;
}
@@ -472,13 +485,41 @@ void QGstVideoRendererSink::finalize(GObject *object)
G_OBJECT_CLASS(sink_parent_class)->finalize(object);
}
void QGstVideoRendererSink::handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d)
{
Q_UNUSED(o);
Q_UNUSED(p);
QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(d);
gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default
g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, NULL);
if (!showPrerollFrame) {
GstState state = GST_STATE_VOID_PENDING;
gst_element_get_state(GST_ELEMENT(sink), &state, NULL, GST_CLOCK_TIME_NONE);
// show-preroll-frame being set to 'false' while in GST_STATE_PAUSED means
// the QMediaPlayer was stopped from the paused state.
// We need to flush the current frame.
if (state == GST_STATE_PAUSED)
sink->delegate->flush();
}
}
GstStateChangeReturn QGstVideoRendererSink::change_state(
GstElement *element, GstStateChange transition)
{
Q_UNUSED(element);
QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(element);
return GST_ELEMENT_CLASS(sink_parent_class)->change_state(
element, transition);
gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default
g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, NULL);
// If show-preroll-frame is 'false' when transitioning from GST_STATE_PLAYING to
// GST_STATE_PAUSED, it means the QMediaPlayer was stopped.
// We need to flush the current frame.
if (transition == GST_STATE_CHANGE_PLAYING_TO_PAUSED && !showPrerollFrame)
sink->delegate->flush();
return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition);
}
GstCaps *QGstVideoRendererSink::get_caps(GstBaseSink *base, GstCaps *filter)

View File

@@ -184,6 +184,21 @@ void QVideoSurfaceGstDelegate::clearPoolBuffers()
m_pool->clear();
}
void QVideoSurfaceGstDelegate::flush()
{
QMutexLocker locker(&m_mutex);
m_frame = QVideoFrame();
m_renderCondition.wakeAll();
if (QThread::currentThread() == thread()) {
if (!m_surface.isNull())
m_surface->present(m_frame);
} else {
QMetaObject::invokeMethod(this, "queuedFlush", Qt::QueuedConnection);
}
}
GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer)
{
if (!m_surface) {
@@ -244,6 +259,14 @@ void QVideoSurfaceGstDelegate::queuedStop()
m_setupCondition.wakeAll();
}
void QVideoSurfaceGstDelegate::queuedFlush()
{
QMutexLocker locker(&m_mutex);
if (!m_surface.isNull())
m_surface->present(QVideoFrame());
}
void QVideoSurfaceGstDelegate::queuedRender()
{
QMutexLocker locker(&m_mutex);
@@ -316,6 +339,8 @@ QVideoSurfaceGstSink *QVideoSurfaceGstSink::createSink(QAbstractVideoSurface *su
sink->delegate = new QVideoSurfaceGstDelegate(surface);
g_signal_connect(G_OBJECT(sink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), sink);
return sink;
}
@@ -420,13 +445,40 @@ void QVideoSurfaceGstSink::finalize(GObject *object)
G_OBJECT_CLASS(sink_parent_class)->finalize(object);
}
GstStateChangeReturn QVideoSurfaceGstSink::change_state(
GstElement *element, GstStateChange transition)
void QVideoSurfaceGstSink::handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d)
{
Q_UNUSED(element);
Q_UNUSED(o);
Q_UNUSED(p);
QVideoSurfaceGstSink *sink = reinterpret_cast<QVideoSurfaceGstSink *>(d);
return GST_ELEMENT_CLASS(sink_parent_class)->change_state(
element, transition);
gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default
g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, NULL);
if (!showPrerollFrame) {
GstState state = GST_STATE_VOID_PENDING;
gst_element_get_state(GST_ELEMENT(sink), &state, NULL, GST_CLOCK_TIME_NONE);
// show-preroll-frame being set to 'false' while in GST_STATE_PAUSED means
// the QMediaPlayer was stopped from the paused state.
// We need to flush the current frame.
if (state == GST_STATE_PAUSED)
sink->delegate->flush();
}
}
GstStateChangeReturn QVideoSurfaceGstSink::change_state(GstElement *element, GstStateChange transition)
{
QVideoSurfaceGstSink *sink = reinterpret_cast<QVideoSurfaceGstSink *>(element);
gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default
g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, NULL);
// If show-preroll-frame is 'false' when transitioning from GST_STATE_PLAYING to
// GST_STATE_PAUSED, it means the QMediaPlayer was stopped.
// We need to flush the current frame.
if (transition == GST_STATE_CHANGE_PLAYING_TO_PAUSED && !showPrerollFrame)
sink->delegate->flush();
return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition);
}
GstCaps *QVideoSurfaceGstSink::get_caps(GstBaseSink *base)

View File

@@ -113,7 +113,10 @@ bool QDeclarativeCameraFlash::isFlashReady() const
\row \li Camera.FlashAuto \li Automatic flash.
\row \li Camera.FlashRedEyeReduction \li Red eye reduction flash.
\row \li Camera.FlashFill \li Use flash to fillin shadows.
\row \li Camera.FlashTorch \li Constant light source, useful for focusing and video capture.
\row \li Camera.FlashTorch \li Constant light source. If supported, torch can be
enabled without loading the camera.
\row \li Camera.FlashVideoLight \li Constant light source, useful for video capture.
The light is turned on only while the camera is active.
\row \li Camera.FlashSlowSyncFrontCurtain
\li Use the flash in conjunction with a slow shutter speed.
This mode allows better exposure of distant objects and/or motion blur effect.

View File

@@ -96,7 +96,7 @@ QCameraViewfinderSettingsControl::~QCameraViewfinderSettingsControl()
Viewfinder pixel format, QVideoFrame::PixelFormat
\value UserParameter
The base value for platform specific extended parameters.
For such parameters the sequential values starting from UserParameter shuld be used.
For such parameters the sequential values starting from UserParameter should be used.
*/
/*!

View File

@@ -130,6 +130,11 @@
\endlist
\section2 Platform Notes
The \l{Qt Multimedia Backends} wiki provides a summary of features
supported by each platform plugin made available by this module. The
following topics provide more platform-specific information.
\list
\li \l{Qt Multimedia on BlackBerry}{BlackBerry}
\li \l{Qt Multimedia on Windows}{Windows}

View File

@@ -99,6 +99,8 @@ public:
void unlock();
bool proposeAllocation(GstQuery *query);
void flush();
GstFlowReturn render(GstBuffer *buffer);
bool event(QEvent *event);
@@ -145,6 +147,8 @@ private:
static void finalize(GObject *object);
static void handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d);
static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition);
static GstCaps *get_caps(GstBaseSink *sink, GstCaps *filter);

View File

@@ -96,11 +96,14 @@ public:
QMutex *poolMutex() { return &m_poolMutex; }
void clearPoolBuffers();
void flush();
GstFlowReturn render(GstBuffer *buffer);
private slots:
void queuedStart();
void queuedStop();
void queuedFlush();
void queuedRender();
void updateSupportedFormats();
@@ -139,6 +142,8 @@ private:
static void finalize(GObject *object);
static void handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d);
static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition);
static GstCaps *get_caps(GstBaseSink *sink);

View File

@@ -277,26 +277,28 @@ void QAndroidCameraSession::adjustViewfinderSize(const QSize &captureSize, bool
return;
QSize currentViewfinderResolution = m_camera->previewSize();
const qreal aspectRatio = qreal(captureSize.width()) / qreal(captureSize.height());
if (currentViewfinderResolution.isValid() &&
qAbs(aspectRatio - (qreal(currentViewfinderResolution.width()) / currentViewfinderResolution.height())) < 0.01) {
return;
}
QSize adjustedViewfinderResolution;
QList<QSize> previewSizes = m_camera->getSupportedPreviewSizes();
for (int i = previewSizes.count() - 1; i >= 0; --i) {
const QSize &size = previewSizes.at(i);
// search for viewfinder resolution with the same aspect ratio
if (qAbs(aspectRatio - (qreal(size.width()) / size.height())) < 0.01) {
adjustedViewfinderResolution = size;
break;
}
}
if (!adjustedViewfinderResolution.isValid()) {
qWarning("Cannot find a viewfinder resolution matching the capture aspect ratio.");
return;
if (m_captureMode.testFlag(QCamera::CaptureVideo) && m_camera->getPreferredPreviewSizeForVideo().isEmpty()) {
// According to the Android doc, if getPreferredPreviewSizeForVideo() returns null, it means
// the preview size cannot be different from the capture size
adjustedViewfinderResolution = captureSize;
} else {
// search for viewfinder resolution with the same aspect ratio
const qreal aspectRatio = qreal(captureSize.width()) / qreal(captureSize.height());
QList<QSize> previewSizes = m_camera->getSupportedPreviewSizes();
for (int i = previewSizes.count() - 1; i >= 0; --i) {
const QSize &size = previewSizes.at(i);
if (qAbs(aspectRatio - (qreal(size.width()) / size.height())) < 0.01) {
adjustedViewfinderResolution = size;
break;
}
}
if (!adjustedViewfinderResolution.isValid()) {
qWarning("Cannot find a viewfinder resolution matching the capture aspect ratio.");
return;
}
}
if (currentViewfinderResolution != adjustedViewfinderResolution) {

View File

@@ -48,7 +48,6 @@ QAndroidCaptureSession::QAndroidCaptureSession(QAndroidCameraSession *cameraSess
, m_duration(0)
, m_state(QMediaRecorder::StoppedState)
, m_status(QMediaRecorder::UnloadedStatus)
, m_resolutionDirty(false)
, m_containerFormatDirty(true)
, m_videoSettingsDirty(true)
, m_audioSettingsDirty(true)
@@ -321,9 +320,6 @@ void QAndroidCaptureSession::setVideoSettings(const QVideoEncoderSettings &setti
if (!m_cameraSession || m_videoSettings == settings)
return;
if (m_videoSettings.resolution() != settings.resolution())
m_resolutionDirty = true;
m_videoSettings = settings;
m_videoSettingsDirty = true;
}
@@ -376,7 +372,6 @@ void QAndroidCaptureSession::applySettings()
if (m_cameraSession && m_cameraSession->camera() && m_videoSettingsDirty) {
if (m_videoSettings.resolution().isEmpty()) {
m_videoSettings.setResolution(m_defaultSettings.videoResolution);
m_resolutionDirty = true;
} else if (!m_supportedResolutions.contains(m_videoSettings.resolution())) {
// if the requested resolution is not supported, find the closest one
QSize reqSize = m_videoSettings.resolution();
@@ -388,7 +383,6 @@ void QAndroidCaptureSession::applySettings()
}
int closestIndex = qt_findClosestValue(supportedPixelCounts, reqPixelCount);
m_videoSettings.setResolution(m_supportedResolutions.at(closestIndex));
m_resolutionDirty = true;
}
if (m_videoSettings.frameRate() <= 0)
@@ -413,12 +407,8 @@ void QAndroidCaptureSession::applySettings()
void QAndroidCaptureSession::updateViewfinder()
{
if (!m_resolutionDirty)
return;
m_cameraSession->camera()->stopPreview();
m_cameraSession->adjustViewfinderSize(m_videoSettings.resolution(), false);
m_resolutionDirty = false;
}
void QAndroidCaptureSession::restartViewfinder()

View File

@@ -161,7 +161,6 @@ private:
QString m_containerFormat;
QAudioEncoderSettings m_audioSettings;
QVideoEncoderSettings m_videoSettings;
bool m_resolutionDirty;
bool m_containerFormatDirty;
bool m_videoSettingsDirty;
bool m_audioSettingsDirty;

View File

@@ -786,6 +786,9 @@ QSize AndroidCameraPrivate::getPreferredPreviewSizeForVideo()
QJNIObjectPrivate size = m_parameters.callObjectMethod("getPreferredPreviewSizeForVideo",
"()Landroid/hardware/Camera$Size;");
if (!size.isValid())
return QSize();
return QSize(size.getField<jint>("width"), size.getField<jint>("height"));
}

View File

@@ -63,6 +63,11 @@ public:
AVCaptureVideoDataOutput *videoDataOutput() const;
#ifdef Q_OS_IOS
AVFCaptureFramesDelegate *captureDelegate() const;
void resetCaptureDelegate() const;
#endif
Q_SIGNALS:
void surfaceChanged(QAbstractVideoSurface *surface);
@@ -80,6 +85,7 @@ private:
QVideoFrame m_lastViewfinderFrame;
QMutex m_vfMutex;
dispatch_queue_t m_delegateQueue;
};
QT_END_NAMESPACE

View File

@@ -143,6 +143,7 @@ private:
- (void) captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection;
@end
@implementation AVFCaptureFramesDelegate
@@ -163,25 +164,23 @@ private:
Q_UNUSED(connection);
Q_UNUSED(captureOutput);
// NB: on iOS captureOutput/connection can be nil (when recording a video -
// avfmediaassetwriter).
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
int width = CVPixelBufferGetWidth(imageBuffer);
int height = CVPixelBufferGetHeight(imageBuffer);
QVideoFrame::PixelFormat format =
AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat(CVPixelBufferGetPixelFormatType(imageBuffer));
QAbstractVideoBuffer *buffer = new CVPixelBufferVideoBuffer(imageBuffer);
if (format == QVideoFrame::Format_Invalid)
return;
QVideoFrame::PixelFormat format = QVideoFrame::Format_RGB32;
if ([captureOutput isKindOfClass:[AVCaptureVideoDataOutput class]]) {
NSDictionary *settings = ((AVCaptureVideoDataOutput *)captureOutput).videoSettings;
if (settings && [settings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]) {
NSNumber *avf = [settings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey];
format = AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat([avf unsignedIntValue]);
}
}
QVideoFrame frame(buffer, QSize(width, height), format);
QVideoFrame frame(new CVPixelBufferVideoBuffer(imageBuffer), QSize(width, height), format);
m_renderer->syncHandleViewfinderFrame(frame);
}
@end
@@ -197,6 +196,8 @@ AVFCameraRendererControl::~AVFCameraRendererControl()
{
[m_cameraSession->captureSession() removeOutput:m_videoDataOutput];
[m_viewfinderFramesDelegate release];
if (m_delegateQueue)
dispatch_release(m_delegateQueue);
}
QAbstractVideoSurface *AVFCameraRendererControl::surface() const
@@ -223,17 +224,10 @@ void AVFCameraRendererControl::configureAVCaptureSession(AVFCameraSession *camer
m_videoDataOutput = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
// Configure video output
dispatch_queue_t queue = dispatch_queue_create("vf_queue", NULL);
m_delegateQueue = dispatch_queue_create("vf_queue", NULL);
[m_videoDataOutput
setSampleBufferDelegate:m_viewfinderFramesDelegate
queue:queue];
dispatch_release(queue);
// Specify the pixel format
m_videoDataOutput.videoSettings =
[NSDictionary dictionaryWithObject:
[NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
queue:m_delegateQueue];
[m_cameraSession->captureSession() addOutput:m_videoDataOutput];
}
@@ -291,6 +285,20 @@ AVCaptureVideoDataOutput *AVFCameraRendererControl::videoDataOutput() const
return m_videoDataOutput;
}
#ifdef Q_OS_IOS
AVFCaptureFramesDelegate *AVFCameraRendererControl::captureDelegate() const
{
return m_viewfinderFramesDelegate;
}
void AVFCameraRendererControl::resetCaptureDelegate() const
{
[m_videoDataOutput setSampleBufferDelegate:m_viewfinderFramesDelegate queue:m_delegateQueue];
}
#endif
void AVFCameraRendererControl::handleViewfinderFrame()
{
QVideoFrame frame;
@@ -301,8 +309,10 @@ void AVFCameraRendererControl::handleViewfinderFrame()
}
if (m_surface && frame.isValid()) {
if (m_surface->isActive() && m_surface->surfaceFormat().pixelFormat() != frame.pixelFormat())
if (m_surface->isActive() && (m_surface->surfaceFormat().pixelFormat() != frame.pixelFormat()
|| m_surface->surfaceFormat().frameSize() != frame.size())) {
m_surface->stop();
}
if (!m_surface->isActive()) {
QVideoSurfaceFormat format(frame.size(), frame.pixelFormat());

View File

@@ -41,13 +41,13 @@
QT_BEGIN_NAMESPACE
class QCameraControl;
class QMediaRecorderControl;
class AVFCameraControl;
class AVFCameraInfoControl;
class AVFCameraMetaDataControl;
class AVFVideoWindowControl;
class AVFVideoWidgetControl;
class AVFCameraRendererControl;
class AVFMediaRecorderControl;
class AVFImageCaptureControl;
class AVFCameraSession;
class AVFCameraDeviceControl;
@@ -59,6 +59,8 @@ class AVFCameraViewfinderSettingsControl2;
class AVFCameraViewfinderSettingsControl;
class AVFImageEncoderControl;
class AVFCameraFlashControl;
class AVFMediaRecorderControl;
class AVFMediaRecorderControlIOS;
class AVFCameraService : public QMediaService
{
@@ -75,7 +77,8 @@ public:
AVFCameraDeviceControl *videoDeviceControl() const { return m_videoDeviceControl; }
AVFAudioInputSelectorControl *audioInputSelectorControl() const { return m_audioInputSelectorControl; }
AVFCameraMetaDataControl *metaDataControl() const { return m_metaDataControl; }
AVFMediaRecorderControl *recorderControl() const { return m_recorderControl; }
AVFMediaRecorderControl *recorderControl() const;
AVFMediaRecorderControlIOS *recorderControlIOS() const;
AVFImageCaptureControl *imageCaptureControl() const { return m_imageCaptureControl; }
AVFCameraFocusControl *cameraFocusControl() const { return m_cameraFocusControl; }
AVFCameraExposureControl *cameraExposureControl() const {return m_cameraExposureControl; }
@@ -94,7 +97,7 @@ private:
AVFAudioInputSelectorControl *m_audioInputSelectorControl;
AVFCameraRendererControl *m_videoOutput;
AVFCameraMetaDataControl *m_metaDataControl;
AVFMediaRecorderControl *m_recorderControl;
QMediaRecorderControl *m_recorderControl;
AVFImageCaptureControl *m_imageCaptureControl;
AVFCameraFocusControl *m_cameraFocusControl;
AVFCameraExposureControl *m_cameraExposureControl;

View File

@@ -56,6 +56,7 @@
#ifdef Q_OS_IOS
#include "avfcamerazoomcontrol.h"
#include "avfmediarecordercontrol_ios.h"
#endif
#include <private/qmediaplaylistnavigator_p.h>
@@ -74,7 +75,14 @@ AVFCameraService::AVFCameraService(QObject *parent):
m_audioInputSelectorControl = new AVFAudioInputSelectorControl(this);
m_metaDataControl = new AVFCameraMetaDataControl(this);
#ifndef Q_OS_IOS
// This will connect a slot to 'captureModeChanged'
// and will break viewfinder by attaching AVCaptureMovieFileOutput
// in this slot.
m_recorderControl = new AVFMediaRecorderControl(this);
#else
m_recorderControl = new AVFMediaRecorderControlIOS(this);
#endif
m_imageCaptureControl = new AVFImageCaptureControl(this);
m_cameraFocusControl = new AVFCameraFocusControl(this);
m_cameraExposureControl = 0;
@@ -97,6 +105,10 @@ AVFCameraService::~AVFCameraService()
{
m_cameraControl->setState(QCamera::UnloadedState);
#ifdef Q_OS_IOS
delete m_recorderControl;
#endif
if (m_videoOutput) {
m_session->setVideoOutput(0);
delete m_videoOutput;
@@ -205,4 +217,23 @@ void AVFCameraService::releaseControl(QMediaControl *control)
}
AVFMediaRecorderControl *AVFCameraService::recorderControl() const
{
#ifdef Q_OS_IOS
return 0;
#else
return static_cast<AVFMediaRecorderControl *>(m_recorderControl);
#endif
}
AVFMediaRecorderControlIOS *AVFCameraService::recorderControlIOS() const
{
#ifdef Q_OS_OSX
return 0;
#else
return static_cast<AVFMediaRecorderControlIOS *>(m_recorderControl);
#endif
}
#include "moc_avfcameraservice.cpp"

View File

@@ -83,6 +83,8 @@ public:
void removeProbe(AVFMediaVideoProbeControl *probe);
FourCharCode defaultCodec();
AVCaptureDeviceInput *videoInput() const {return m_videoInput;}
public Q_SLOTS:
void setState(QCamera::State state);

View File

@@ -283,12 +283,12 @@ void AVFCameraSession::setState(QCamera::State newState)
if (m_state == QCamera::ActiveState) {
Q_EMIT readyToConfigureConnections();
[m_captureSession commitConfiguration];
[m_captureSession startRunning];
m_defaultCodec = 0;
defaultCodec();
applyImageEncoderSettings();
applyViewfinderSettings();
[m_captureSession commitConfiguration];
[m_captureSession startRunning];
}
if (oldState == QCamera::ActiveState) {
@@ -374,8 +374,7 @@ void AVFCameraSession::applyViewfinderSettings()
}
}
if (!vfSettings.isNull())
vfControl->applySettings();
vfControl->applySettings();
}
}

View File

@@ -78,6 +78,74 @@ private:
bool m_locked;
};
struct AVFObjectDeleter {
static void cleanup(NSObject *obj)
{
if (obj)
[obj release];
}
};
template<class T>
class AVFScopedPointer : public QScopedPointer<NSObject, AVFObjectDeleter>
{
public:
AVFScopedPointer() {}
explicit AVFScopedPointer(T *ptr) : QScopedPointer(ptr) {}
operator T*() const
{
// Quite handy operator to enable Obj-C messages: [ptr someMethod];
return data();
}
T *data() const
{
return static_cast<T *>(QScopedPointer::data());
}
T *take()
{
return static_cast<T *>(QScopedPointer::take());
}
};
template<>
class AVFScopedPointer<dispatch_queue_t>
{
public:
AVFScopedPointer() : m_queue(0) {}
explicit AVFScopedPointer(dispatch_queue_t q) : m_queue(q) {}
~AVFScopedPointer()
{
if (m_queue)
dispatch_release(m_queue);
}
operator dispatch_queue_t() const
{
// Quite handy operator to enable Obj-C messages: [ptr someMethod];
return m_queue;
}
dispatch_queue_t data() const
{
return m_queue;
}
void reset(dispatch_queue_t q = 0)
{
if (m_queue)
dispatch_release(m_queue);
m_queue = q;
}
private:
dispatch_queue_t m_queue;
Q_DISABLE_COPY(AVFScopedPointer);
};
inline QSysInfo::MacVersion qt_OS_limit(QSysInfo::MacVersion osxVersion,
QSysInfo::MacVersion iosVersion)
{

View File

@@ -59,13 +59,20 @@ AVFPSRange qt_connection_framerates(AVCaptureConnection *videoConnection)
}
}
if (videoConnection.supportsVideoMaxFrameDuration) {
const CMTime cmMax = videoConnection.videoMaxFrameDuration;
if (CMTimeCompare(cmMax, kCMTimeInvalid)) {
if (const Float64 maxSeconds = CMTimeGetSeconds(cmMax))
newRange.first = 1. / maxSeconds;
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_5_0)
#if QT_OSX_DEPLOYMENT_TARGET_BELOW(__MAC_10_9)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9)
#endif
{
if (videoConnection.supportsVideoMaxFrameDuration) {
const CMTime cmMax = videoConnection.videoMaxFrameDuration;
if (CMTimeCompare(cmMax, kCMTimeInvalid)) {
if (const Float64 maxSeconds = CMTimeGetSeconds(cmMax))
newRange.first = 1. / maxSeconds;
}
}
}
#endif
return newRange;
}

View File

@@ -76,31 +76,40 @@ void qt_set_framerate_limits(AVCaptureConnection *videoConnection,
return;
}
const qreal minFPS = settings.minimumFrameRate();
const qreal maxFPS = settings.maximumFrameRate();
CMTime minDuration = kCMTimeInvalid;
CMTime maxDuration = kCMTimeInvalid;
if (minFPS > 0. || maxFPS > 0.) {
if (maxFPS) {
if (!videoConnection.supportsVideoMinFrameDuration)
qDebugCamera() << Q_FUNC_INFO << "maximum framerate is not supported";
else
minDuration = CMTimeMake(1, maxFPS);
}
if (maxFPS > 0.) {
if (!videoConnection.supportsVideoMinFrameDuration)
qDebugCamera() << Q_FUNC_INFO << "maximum framerate is not supported";
else
minDuration = CMTimeMake(1, maxFPS);
}
if (videoConnection.supportsVideoMinFrameDuration)
videoConnection.videoMinFrameDuration = minDuration;
if (minFPS) {
const qreal minFPS = settings.minimumFrameRate();
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_5_0)
#if QT_OSX_DEPLOYMENT_TARGET_BELOW(__MAC_10_9)
if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_9) {
if (minFPS > 0.)
qDebugCamera() << Q_FUNC_INFO << "minimum framerate is not supported";
} else
#endif
{
CMTime maxDuration = kCMTimeInvalid;
if (minFPS > 0.) {
if (!videoConnection.supportsVideoMaxFrameDuration)
qDebugCamera() << Q_FUNC_INFO << "minimum framerate is not supported";
else
maxDuration = CMTimeMake(1, minFPS);
}
if (videoConnection.supportsVideoMaxFrameDuration)
videoConnection.videoMaxFrameDuration = maxDuration;
}
if (videoConnection.supportsVideoMinFrameDuration)
videoConnection.videoMinFrameDuration = minDuration;
if (videoConnection.supportsVideoMaxFrameDuration)
videoConnection.videoMaxFrameDuration = maxDuration;
#else
if (minFPS > 0.)
qDebugCamera() << Q_FUNC_INFO << "minimum framerate is not supported";
#endif
}
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
@@ -171,12 +180,21 @@ void qt_set_framerate_limits(AVCaptureDevice *captureDevice,
#ifdef Q_OS_IOS
[captureDevice setActiveVideoMinFrameDuration:minFrameDuration];
[captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration];
#else
#else // Q_OS_OSX
if (CMTimeCompare(minFrameDuration, kCMTimeInvalid))
[captureDevice setActiveVideoMinFrameDuration:minFrameDuration];
if (CMTimeCompare(maxFrameDuration, kCMTimeInvalid))
[captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration];
#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
#if QT_OSX_DEPLOYMENT_TARGET_BELOW(__MAC_10_9)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9)
#endif
{
if (CMTimeCompare(maxFrameDuration, kCMTimeInvalid))
[captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration];
}
#endif // QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
#endif // Q_OS_OSX
}
#endif // Platform SDK >= 10.9, >= 7.0.
@@ -197,15 +215,23 @@ AVFPSRange qt_current_framerates(AVCaptureDevice *captureDevice, AVCaptureConnec
fps.second = 1. / minSeconds; // Max FPS = 1 / MinDuration.
}
const CMTime maxDuration = captureDevice.activeVideoMaxFrameDuration;
if (CMTimeCompare(maxDuration, kCMTimeInvalid)) {
if (const Float64 maxSeconds = CMTimeGetSeconds(maxDuration))
fps.first = 1. / maxSeconds; // Min FPS = 1 / MaxDuration.
}
} else {
#else
{
#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
#if QT_OSX_DEPLOYMENT_TARGET_BELOW(__MAC_10_9)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9)
#endif
{
const CMTime maxDuration = captureDevice.activeVideoMaxFrameDuration;
if (CMTimeCompare(maxDuration, kCMTimeInvalid)) {
if (const Float64 maxSeconds = CMTimeGetSeconds(maxDuration))
fps.first = 1. / maxSeconds; // Min FPS = 1 / MaxDuration.
}
}
#endif // QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
} else {
#else // OSX < 10.7 or iOS < 7.0
{
#endif // QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
fps = qt_connection_framerates(videoConnection);
}
@@ -459,13 +485,7 @@ QVector<QVideoFrame::PixelFormat> AVFCameraViewfinderSettingsControl2::viewfinde
Q_ASSERT(m_videoOutput);
QVector<QVideoFrame::PixelFormat> qtFormats;
QList<QVideoFrame::PixelFormat> filter;
NSArray *pixelFormats = [m_videoOutput availableVideoCVPixelFormatTypes];
const QAbstractVideoSurface *surface = m_service->videoOutput() ? m_service->videoOutput()->surface() : 0;
if (surface)
filter = surface->supportedPixelFormats();
for (NSObject *obj in pixelFormats) {
if (![obj isKindOfClass:[NSNumber class]])
@@ -474,8 +494,8 @@ QVector<QVideoFrame::PixelFormat> AVFCameraViewfinderSettingsControl2::viewfinde
NSNumber *formatAsNSNumber = static_cast<NSNumber *>(obj);
// It's actually FourCharCode (== UInt32):
const QVideoFrame::PixelFormat qtFormat(QtPixelFormatFromCVFormat([formatAsNSNumber unsignedIntValue]));
if (qtFormat != QVideoFrame::Format_Invalid && (!surface || filter.contains(qtFormat))
&& !qtFormats.contains(qtFormat)) { // Can happen, for example, with 8BiPlanar existing in video/full range.
if (qtFormat != QVideoFrame::Format_Invalid
&& !qtFormats.contains(qtFormat)) { // Can happen, for example, with 8BiPlanar existing in video/full range.
qtFormats << qtFormat;
}
}
@@ -550,22 +570,33 @@ void AVFCameraViewfinderSettingsControl2::applySettings()
#endif
unsigned avfPixelFormat = 0;
if (m_settings.pixelFormat() != QVideoFrame::Format_Invalid &&
convertPixelFormatIfSupported(m_settings.pixelFormat(), avfPixelFormat)) {
[videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
} else {
// We have to set the pixel format, otherwise AVFoundation can change it to something we do not support.
if (NSObject *oldFormat = [m_videoOutput.videoSettings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]) {
[videoSettings setObject:oldFormat forKey:(id)kCVPixelBufferPixelFormatTypeKey];
} else {
[videoSettings setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
if (!convertPixelFormatIfSupported(m_settings.pixelFormat(), avfPixelFormat)) {
// If the the pixel format is not specified or invalid, pick the preferred video surface
// format, or if no surface is set, the preferred capture device format
const QVector<QVideoFrame::PixelFormat> deviceFormats = viewfinderPixelFormats();
QList<QVideoFrame::PixelFormat> surfaceFormats;
if (m_service->videoOutput() && m_service->videoOutput()->surface())
surfaceFormats = m_service->videoOutput()->surface()->supportedPixelFormats();
QVideoFrame::PixelFormat format = deviceFormats.first();
for (int i = 0; i < surfaceFormats.count(); ++i) {
const QVideoFrame::PixelFormat surfaceFormat = surfaceFormats.at(i);
if (deviceFormats.contains(surfaceFormat)) {
format = surfaceFormat;
break;
}
}
CVPixelFormatFromQtFormat(format, avfPixelFormat);
}
if (videoSettings.count)
if (avfPixelFormat != 0) {
[videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
m_videoOutput.videoSettings = videoSettings;
}
qt_set_framerate_limits(m_captureDevice, m_videoConnection, m_settings);
}

View File

@@ -128,11 +128,11 @@ void AVFCameraZoomControl::cameraStateChanged()
return;
}
if (captureDevice.activeFormat.videoMaxZoomFactor > 1.
&& !qFuzzyCompare(m_maxZoomFactor, captureDevice.activeFormat.videoMaxZoomFactor)) {
m_maxZoomFactor = captureDevice.activeFormat.videoMaxZoomFactor;
Q_EMIT maximumDigitalZoomChanged(m_maxZoomFactor);
if (captureDevice.activeFormat.videoMaxZoomFactor > 1.) {
if (!qFuzzyCompare(m_maxZoomFactor, captureDevice.activeFormat.videoMaxZoomFactor)) {
m_maxZoomFactor = captureDevice.activeFormat.videoMaxZoomFactor;
Q_EMIT maximumDigitalZoomChanged(m_maxZoomFactor);
}
} else if (!qFuzzyCompare(m_maxZoomFactor, CGFloat(1.))) {
m_maxZoomFactor = 1.;

View File

@@ -0,0 +1,119 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef AVFMEDIAASSETWRITER_H
#define AVFMEDIAASSETWRITER_H
#include "avfcamerautility.h"
#include <QtCore/qglobal.h>
#include <QtCore/qatomic.h>
#include <QtCore/qmutex.h>
#include <AVFoundation/AVFoundation.h>
QT_BEGIN_NAMESPACE
class AVFCameraService;
class AVFMediaAssetWriterDelegate
{
public:
virtual ~AVFMediaAssetWriterDelegate();
virtual void assetWriterStarted() = 0;
virtual void assetWriterFailedToStart() = 0;
virtual void assetWriterFailedToStop() = 0;
virtual void assetWriterFinished() = 0;
};
typedef QAtomicInteger<bool> AVFAtomicBool;
typedef QAtomicInteger<qint64> AVFAtomicInt64;
QT_END_NAMESPACE
// TODO: any reasonable error handling requires smart pointers, otherwise it's getting crappy immediately.
@interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) : NSObject<AVCaptureVideoDataOutputSampleBufferDelegate,
AVCaptureAudioDataOutputSampleBufferDelegate>
{
@private
AVFCameraService *m_service;
QT_MANGLE_NAMESPACE(AVFScopedPointer)<AVAssetWriterInput> m_cameraWriterInput;
QT_MANGLE_NAMESPACE(AVFScopedPointer)<AVCaptureDeviceInput> m_audioInput;
QT_MANGLE_NAMESPACE(AVFScopedPointer)<AVCaptureAudioDataOutput> m_audioOutput;
QT_MANGLE_NAMESPACE(AVFScopedPointer)<AVAssetWriterInput> m_audioWriterInput;
// High priority serial queue for video output:
QT_MANGLE_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_videoQueue;
// Serial queue for audio output:
QT_MANGLE_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_audioQueue;
// Queue to write sample buffers:
__weak dispatch_queue_t m_writerQueue;
QT_MANGLE_NAMESPACE(AVFScopedPointer)<AVAssetWriter> m_assetWriter;
// Delegate's queue.
__weak dispatch_queue_t m_delegateQueue;
// TODO: QPointer??
QT_PREPEND_NAMESPACE(AVFMediaAssetWriterDelegate) *m_delegate;
bool m_setStartTime;
QT_MANGLE_NAMESPACE(AVFAtomicBool) m_stopped;
bool m_stoppedInternal;
bool m_aborted;
QT_MANGLE_NAMESPACE(QMutex) m_writerMutex;
@public
QT_MANGLE_NAMESPACE(AVFAtomicInt64) m_durationInMs;
@private
CMTime m_startTime;
CMTime m_lastTimeStamp;
}
- (id)initWithQueue:(dispatch_queue_t)writerQueue
delegate:(QT_PREPEND_NAMESPACE(AVFMediaAssetWriterDelegate) *)delegate
delegateQueue:(dispatch_queue_t)delegateQueue;
- (bool)setupWithFileURL:(NSURL *)fileURL
cameraService:(QT_PREPEND_NAMESPACE(AVFCameraService) *)service;
- (void)start;
- (void)stop;
// This to be called if control's dtor gets called,
// on the control's thread.
- (void)abort;
@end
#endif // AVFMEDIAASSETWRITER_H

View File

@@ -0,0 +1,474 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "avfaudioinputselectorcontrol.h"
#include "avfcamerarenderercontrol.h"
#include "avfmediaassetwriter.h"
#include "avfcameraservice.h"
#include "avfcamerasession.h"
#include "avfcameradebug.h"
//#include <QtCore/qmutexlocker.h>
#include <QtCore/qsysinfo.h>
QT_USE_NAMESPACE
namespace {
bool qt_camera_service_isValid(AVFCameraService *service)
{
if (!service || !service->session())
return false;
AVFCameraSession *session = service->session();
if (!session->captureSession())
return false;
if (!session->videoInput())
return false;
if (!service->videoOutput()
|| !service->videoOutput()->videoDataOutput()) {
return false;
}
return true;
}
}
AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate()
{
}
@interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) (PrivateAPI)
- (bool)addAudioCapture;
- (bool)addWriterInputs;
- (void)setQueues;
- (NSDictionary *)videoSettings;
- (NSDictionary *)audioSettings;
- (void)updateDuration:(CMTime)newTimeStamp;
@end
@implementation QT_MANGLE_NAMESPACE(AVFMediaAssetWriter)
- (id)initWithQueue:(dispatch_queue_t)writerQueue
delegate:(AVFMediaAssetWriterDelegate *)delegate
delegateQueue:(dispatch_queue_t)delegateQueue
{
Q_ASSERT(writerQueue);
Q_ASSERT(delegate);
Q_ASSERT(delegateQueue);
if (self = [super init]) {
m_writerQueue = writerQueue;
m_delegate = delegate;
m_delegateQueue = delegateQueue;
m_setStartTime = true;
m_stopped.store(true);
m_stoppedInternal = false;
m_aborted = false;
m_startTime = kCMTimeInvalid;
m_lastTimeStamp = kCMTimeInvalid;
m_durationInMs.store(0);
}
return self;
}
- (bool)setupWithFileURL:(NSURL *)fileURL
cameraService:(AVFCameraService *)service
{
Q_ASSERT(fileURL);
if (!qt_camera_service_isValid(service)) {
qDebugCamera() << Q_FUNC_INFO << "invalid camera service";
return false;
}
m_service = service;
m_videoQueue.reset(dispatch_queue_create("video-output-queue", DISPATCH_QUEUE_SERIAL));
if (!m_videoQueue) {
qDebugCamera() << Q_FUNC_INFO << "failed to create video queue";
return false;
}
dispatch_set_target_queue(m_videoQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
m_audioQueue.reset(dispatch_queue_create("audio-output-queue", DISPATCH_QUEUE_SERIAL));
if (!m_audioQueue) {
qDebugCamera() << Q_FUNC_INFO << "failed to create audio queue";
// But we still can write video!
}
m_assetWriter.reset([[AVAssetWriter alloc] initWithURL:fileURL fileType:AVFileTypeQuickTimeMovie error:nil]);
if (!m_assetWriter) {
qDebugCamera() << Q_FUNC_INFO << "failed to create asset writer";
return false;
}
bool audioCaptureOn = false;
if (m_audioQueue)
audioCaptureOn = [self addAudioCapture];
if (![self addWriterInputs]) {
if (audioCaptureOn) {
AVCaptureSession *session = m_service->session()->captureSession();
[session removeOutput:m_audioOutput];
[session removeInput:m_audioInput];
m_audioOutput.reset();
m_audioInput.reset();
}
m_assetWriter.reset();
return false;
}
// Ready to start ...
return true;
}
- (void)start
{
// To be executed on a writer's queue.
const QMutexLocker lock(&m_writerMutex);
if (m_aborted)
return;
[self setQueues];
m_setStartTime = true;
m_stopped.store(false);
m_stoppedInternal = false;
[m_assetWriter startWriting];
AVCaptureSession *session = m_service->session()->captureSession();
if (!session.running)
[session startRunning];
}
- (void)stop
{
// To be executed on a writer's queue.
const QMutexLocker lock(&m_writerMutex);
if (m_aborted)
return;
if (m_stopped.load()) {
// Should never happen, but ...
// if something went wrong in a recorder control
// and we set state stopped without starting first ...
// m_stoppedIntenal will be false, but m_stopped - true.
return;
}
m_stopped.store(true);
m_stoppedInternal = true;
[m_assetWriter finishWritingWithCompletionHandler:^{
// TODO: make sure the session exist and we can call stop/remove on it.
AVCaptureSession *session = m_service->session()->captureSession();
[session stopRunning];
[session removeOutput:m_audioOutput];
[session removeInput:m_audioInput];
dispatch_async(m_delegateQueue, ^{
m_delegate->assetWriterFinished();
});
}];
}
- (void)abort
{
// To be executed on any thread, prevents writer from
// accessing any external object (probably deleted by this time)
const QMutexLocker lock(&m_writerMutex);
m_aborted = true;
if (m_stopped.load())
return;
[m_assetWriter finishWritingWithCompletionHandler:^{
}];
}
- (void)setStartTimeFrom:(CMSampleBufferRef)sampleBuffer
{
// Writer's queue only.
Q_ASSERT(m_setStartTime);
Q_ASSERT(sampleBuffer);
dispatch_async(m_delegateQueue, ^{
m_delegate->assetWriterStarted();
});
m_durationInMs.store(0);
m_startTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
m_lastTimeStamp = m_startTime;
[m_assetWriter startSessionAtSourceTime:m_startTime];
m_setStartTime = false;
}
- (void)writeVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer
{
Q_ASSERT(sampleBuffer);
// This code is executed only on a writer's queue, but
// it can access potentially deleted objects, so we
// need a lock and m_aborted flag test.
{
const QMutexLocker lock(&m_writerMutex);
if (!m_aborted && !m_stoppedInternal) {
if (m_setStartTime)
[self setStartTimeFrom:sampleBuffer];
if (m_cameraWriterInput.data().readyForMoreMediaData) {
[self updateDuration:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
[m_cameraWriterInput appendSampleBuffer:sampleBuffer];
}
}
}
CFRelease(sampleBuffer);
}
- (void)writeAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer
{
// This code is executed only on a writer's queue.
// it does not touch any shared/external data.
Q_ASSERT(sampleBuffer);
{
const QMutexLocker lock(&m_writerMutex);
if (!m_aborted && !m_stoppedInternal) {
if (m_setStartTime)
[self setStartTimeFrom:sampleBuffer];
if (m_audioWriterInput.data().readyForMoreMediaData) {
[self updateDuration:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
[m_audioWriterInput appendSampleBuffer:sampleBuffer];
}
}
}
CFRelease(sampleBuffer);
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
Q_UNUSED(connection)
// This method can be called on either video or audio queue, never on a writer's
// queue - it does not access any shared data except this atomic flag below.
if (m_stopped.load())
return;
// Even if we are stopped now, we still do not access any data.
if (!CMSampleBufferDataIsReady(sampleBuffer)) {
qDebugCamera() << Q_FUNC_INFO << "sample buffer is not ready, skipping.";
return;
}
CFRetain(sampleBuffer);
if (captureOutput != m_audioOutput.data()) {
{
const QMutexLocker lock(&m_writerMutex);
if (m_aborted || m_stoppedInternal) {
CFRelease(sampleBuffer);
return;
}
// Find renderercontrol's delegate and invoke its method to
// show updated viewfinder's frame.
if (m_service && m_service->videoOutput()) {
NSObject<AVCaptureVideoDataOutputSampleBufferDelegate> *vfDelegate =
(NSObject<AVCaptureVideoDataOutputSampleBufferDelegate> *)m_service->videoOutput()->captureDelegate();
if (vfDelegate)
[vfDelegate captureOutput:nil didOutputSampleBuffer:sampleBuffer fromConnection:nil];
}
}
dispatch_async(m_writerQueue, ^{
[self writeVideoSampleBuffer:sampleBuffer];
});
} else {
dispatch_async(m_writerQueue, ^{
[self writeAudioSampleBuffer:sampleBuffer];
});
}
}
- (bool)addAudioCapture
{
Q_ASSERT(m_service && m_service->session() && m_service->session()->captureSession());
if (!m_service->audioInputSelectorControl())
return false;
AVCaptureSession *captureSession = m_service->session()->captureSession();
AVCaptureDevice *audioDevice = m_service->audioInputSelectorControl()->createCaptureDevice();
if (!audioDevice) {
qWarning() << Q_FUNC_INFO << "no audio input device available";
return false;
} else {
NSError *error = nil;
m_audioInput.reset([[AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error] retain]);
if (!m_audioInput || error) {
qWarning() << Q_FUNC_INFO << "failed to create audio device input";
m_audioInput.reset();
return false;
} else if (![captureSession canAddInput:m_audioInput]) {
qWarning() << Q_FUNC_INFO << "could not connect the audio input";
m_audioInput.reset();
return false;
} else {
[captureSession addInput:m_audioInput];
}
}
m_audioOutput.reset([[AVCaptureAudioDataOutput alloc] init]);
if (m_audioOutput && [captureSession canAddOutput:m_audioOutput]) {
[captureSession addOutput:m_audioOutput];
} else {
qDebugCamera() << Q_FUNC_INFO << "failed to add audio output";
[captureSession removeInput:m_audioInput];
m_audioInput.reset();
m_audioOutput.reset();
return false;
}
return true;
}
- (bool)addWriterInputs
{
Q_ASSERT(m_service && m_service->videoOutput()
&& m_service->videoOutput()->videoDataOutput());
Q_ASSERT(m_assetWriter);
m_cameraWriterInput.reset([[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:[self videoSettings]]);
if (!m_cameraWriterInput) {
qDebugCamera() << Q_FUNC_INFO << "failed to create camera writer input";
return false;
}
if ([m_assetWriter canAddInput:m_cameraWriterInput]) {
[m_assetWriter addInput:m_cameraWriterInput];
} else {
qDebugCamera() << Q_FUNC_INFO << "failed to add camera writer input";
m_cameraWriterInput.reset();
return false;
}
m_cameraWriterInput.data().expectsMediaDataInRealTime = YES;
if (m_audioOutput) {
m_audioWriterInput.reset([[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio outputSettings:[self audioSettings]]);
if (!m_audioWriterInput) {
qDebugCamera() << Q_FUNC_INFO << "failed to create audio writer input";
// But we still can record video.
} else if ([m_assetWriter canAddInput:m_audioWriterInput]) {
[m_assetWriter addInput:m_audioWriterInput];
m_audioWriterInput.data().expectsMediaDataInRealTime = YES;
} else {
qDebugCamera() << Q_FUNC_INFO << "failed to add audio writer input";
m_audioWriterInput.reset();
// We can (still) write video though ...
}
}
return true;
}
- (void)setQueues
{
Q_ASSERT(m_service && m_service->videoOutput() && m_service->videoOutput()->videoDataOutput());
Q_ASSERT(m_videoQueue);
[m_service->videoOutput()->videoDataOutput() setSampleBufferDelegate:self queue:m_videoQueue];
if (m_audioOutput) {
Q_ASSERT(m_audioQueue);
[m_audioOutput setSampleBufferDelegate:self queue:m_audioQueue];
}
}
- (NSDictionary *)videoSettings
{
// TODO: these settings should be taken from
// the video encoding settings control.
// For now we either take recommended (iOS >= 7.0)
// or some hardcoded values - they are still better than nothing (nil).
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0)
AVCaptureVideoDataOutput *videoOutput = m_service->videoOutput()->videoDataOutput();
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0 && videoOutput)
return [videoOutput recommendedVideoSettingsForAssetWriterWithOutputFileType:AVFileTypeQuickTimeMovie];
#endif
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:1280], AVVideoWidthKey,
[NSNumber numberWithInt:720], AVVideoHeightKey, nil];
return videoSettings;
}
- (NSDictionary *)audioSettings
{
// TODO: these settings should be taken from
// the video/audio encoder settings control.
// For now we either take recommended (iOS >= 7.0)
// or nil - this seems to be good enough.
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0 && m_audioOutput)
return [m_audioOutput recommendedAudioSettingsForAssetWriterWithOutputFileType:AVFileTypeQuickTimeMovie];
#endif
return nil;
}
- (void)updateDuration:(CMTime)newTimeStamp
{
Q_ASSERT(CMTimeCompare(m_startTime, kCMTimeInvalid));
Q_ASSERT(CMTimeCompare(m_lastTimeStamp, kCMTimeInvalid));
if (CMTimeCompare(newTimeStamp, m_lastTimeStamp) > 0) {
const CMTime duration = CMTimeSubtract(newTimeStamp, m_startTime);
if (!CMTimeCompare(duration, kCMTimeInvalid))
return;
m_durationInMs.store(CMTimeGetSeconds(duration) * 1000);
m_lastTimeStamp = newTimeStamp;
}
}
@end

View File

@@ -0,0 +1,108 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef AVFMEDIARECORDERCONTROL_IOS_H
#define AVFMEDIARECORDERCONTROL_IOS_H
#include "avfmediaassetwriter.h"
#include "avfstoragelocation.h"
#include "avfcamerautility.h"
#include <QtMultimedia/qmediarecordercontrol.h>
#include <QtCore/qglobal.h>
#include <QtCore/qurl.h>
#include <AVFoundation/AVFoundation.h>
QT_BEGIN_NAMESPACE
class AVFCameraService;
class QString;
class QUrl;
class AVFMediaRecorderControlIOS : public QMediaRecorderControl, public AVFMediaAssetWriterDelegate
{
Q_OBJECT
public:
AVFMediaRecorderControlIOS(AVFCameraService *service, QObject *parent = 0);
~AVFMediaRecorderControlIOS();
QUrl outputLocation() const Q_DECL_OVERRIDE;
bool setOutputLocation(const QUrl &location) Q_DECL_OVERRIDE;
QMediaRecorder::State state() const Q_DECL_OVERRIDE;
QMediaRecorder::Status status() const Q_DECL_OVERRIDE;
qint64 duration() const Q_DECL_OVERRIDE;
bool isMuted() const Q_DECL_OVERRIDE;
qreal volume() const Q_DECL_OVERRIDE;
void applySettings() Q_DECL_OVERRIDE;
public Q_SLOTS:
void setState(QMediaRecorder::State state) Q_DECL_OVERRIDE;
void setMuted(bool muted) Q_DECL_OVERRIDE;
void setVolume(qreal volume) Q_DECL_OVERRIDE;
// Writer delegate:
private:
void assetWriterStarted() Q_DECL_OVERRIDE;
void assetWriterFailedToStart() Q_DECL_OVERRIDE;
void assetWriterFailedToStop() Q_DECL_OVERRIDE;
void assetWriterFinished() Q_DECL_OVERRIDE;
private Q_SLOTS:
void captureModeChanged(QCamera::CaptureModes);
void cameraStatusChanged(QCamera::Status newStatus);
private:
void stopWriter();
AVFCameraService *m_service;
AVFScopedPointer<dispatch_queue_t> m_writerQueue;
AVFScopedPointer<QT_MANGLE_NAMESPACE(AVFMediaAssetWriter)> m_writer;
QUrl m_outputLocation;
AVFStorageLocation m_storageLocation;
QMediaRecorder::State m_state;
QMediaRecorder::Status m_lastStatus;
};
QT_END_NAMESPACE
#endif // AVFMEDIARECORDERCONTROL_IOS_H

View File

@@ -0,0 +1,349 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "avfmediarecordercontrol_ios.h"
#include "avfcamerarenderercontrol.h"
#include "avfcamerasession.h"
#include "avfcameracontrol.h"
#include "avfcameraservice.h"
#include "avfcameradebug.h"
#include <QtCore/qdebug.h>
QT_USE_NAMESPACE
namespace {
bool qt_is_writable_file_URL(NSURL *fileURL)
{
Q_ASSERT(fileURL);
if (![fileURL isFileURL])
return false;
if (NSString *path = [[fileURL path] stringByExpandingTildeInPath]) {
return [[NSFileManager defaultManager]
isWritableFileAtPath:[path stringByDeletingLastPathComponent]];
}
return false;
}
bool qt_file_exists(NSURL *fileURL)
{
Q_ASSERT(fileURL);
if (NSString *path = [[fileURL path] stringByExpandingTildeInPath])
return [[NSFileManager defaultManager] fileExistsAtPath:path];
return false;
}
}
AVFMediaRecorderControlIOS::AVFMediaRecorderControlIOS(AVFCameraService *service, QObject *parent)
: QMediaRecorderControl(parent)
, m_service(service)
, m_state(QMediaRecorder::StoppedState)
, m_lastStatus(QMediaRecorder::UnloadedStatus)
{
Q_ASSERT(service);
m_writerQueue.reset(dispatch_queue_create("asset-writer-queue", DISPATCH_QUEUE_SERIAL));
if (!m_writerQueue) {
qDebugCamera() << Q_FUNC_INFO << "failed to create an asset writer's queue";
return;
}
m_writer.reset([[QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) alloc] initWithQueue:m_writerQueue
delegate:this delegateQueue:dispatch_get_main_queue()]);
if (!m_writer) {
qDebugCamera() << Q_FUNC_INFO << "failed to create an asset writer";
return;
}
AVFCameraControl *cameraControl = m_service->cameraControl();
if (!cameraControl) {
qDebugCamera() << Q_FUNC_INFO << "camera control is nil";
return;
}
connect(cameraControl, SIGNAL(captureModeChanged(QCamera::CaptureModes)),
SLOT(captureModeChanged(QCamera::CaptureModes)));
connect(cameraControl, SIGNAL(statusChanged(QCamera::Status)),
SLOT(cameraStatusChanged(QCamera::Status)));
}
AVFMediaRecorderControlIOS::~AVFMediaRecorderControlIOS()
{
[m_writer abort];
}
QUrl AVFMediaRecorderControlIOS::outputLocation() const
{
return m_outputLocation;
}
bool AVFMediaRecorderControlIOS::setOutputLocation(const QUrl &location)
{
m_outputLocation = location;
return location.scheme() == QLatin1String("file") || location.scheme().isEmpty();
}
QMediaRecorder::State AVFMediaRecorderControlIOS::state() const
{
return m_state;
}
QMediaRecorder::Status AVFMediaRecorderControlIOS::status() const
{
return m_lastStatus;
}
qint64 AVFMediaRecorderControlIOS::duration() const
{
return m_writer.data()->m_durationInMs.load();
}
bool AVFMediaRecorderControlIOS::isMuted() const
{
return false;
}
qreal AVFMediaRecorderControlIOS::volume() const
{
return 1.;
}
void AVFMediaRecorderControlIOS::applySettings()
{
}
void AVFMediaRecorderControlIOS::setState(QMediaRecorder::State state)
{
Q_ASSERT(m_service->session()
&& m_service->session()->captureSession());
if (!m_writer) {
qDebugCamera() << Q_FUNC_INFO << "Invalid recorder";
return;
}
if (state == m_state)
return;
switch (state) {
case QMediaRecorder::RecordingState:
{
AVFCameraControl *cameraControl = m_service->cameraControl();
Q_ASSERT(cameraControl);
if (!(cameraControl->captureMode() & QCamera::CaptureVideo)) {
qDebugCamera() << Q_FUNC_INFO << "wrong capture mode, CaptureVideo expected";
Q_EMIT error(QMediaRecorder::ResourceError, tr("Failed to start recording"));
return;
}
if (cameraControl->status() != QCamera::ActiveStatus) {
qDebugCamera() << Q_FUNC_INFO << "can not start record while camera is not active";
Q_EMIT error(QMediaRecorder::ResourceError, tr("Failed to start recording"));
return;
}
const QString path(m_outputLocation.scheme() == QLatin1String("file") ?
m_outputLocation.path() : m_outputLocation.toString());
const QUrl fileURL(QUrl::fromLocalFile(m_storageLocation.generateFileName(path, QCamera::CaptureVideo,
QLatin1String("clip_"), QLatin1String("mp4"))));
NSURL *nsFileURL = fileURL.toNSURL();
if (!nsFileURL) {
qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL;
Q_EMIT error(QMediaRecorder::ResourceError, tr("Invalid output file URL"));
return;
}
if (!qt_is_writable_file_URL(nsFileURL)) {
qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL
<< "(the location is not writable)";
Q_EMIT error(QMediaRecorder::ResourceError, tr("Non-writeable file location"));
return;
}
if (qt_file_exists(nsFileURL)) {
// We test for/handle this error here since AWAssetWriter will raise an
// Objective-C exception, which is not good at all.
qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL
<< "(file already exists)";
Q_EMIT error(QMediaRecorder::ResourceError, tr("File already exists"));
return;
}
AVCaptureSession *session = m_service->session()->captureSession();
// We stop session now so that no more frames for renderer's queue
// generated, will restart in assetWriterStarted.
[session stopRunning];
if ([m_writer setupWithFileURL:nsFileURL cameraService:m_service]) {
m_state = QMediaRecorder::RecordingState;
m_lastStatus = QMediaRecorder::StartingStatus;
Q_EMIT actualLocationChanged(fileURL);
Q_EMIT stateChanged(m_state);
Q_EMIT statusChanged(m_lastStatus);
dispatch_async(m_writerQueue, ^{
[m_writer start];
});
} else {
[session startRunning];
Q_EMIT error(QMediaRecorder::FormatError, tr("Failed to start recording"));
}
} break;
case QMediaRecorder::PausedState:
{
Q_EMIT error(QMediaRecorder::FormatError, tr("Recording pause not supported"));
return;
} break;
case QMediaRecorder::StoppedState:
{
// Do not check the camera status, we can stop if we started.
stopWriter();
}
}
}
void AVFMediaRecorderControlIOS::setMuted(bool muted)
{
Q_UNUSED(muted)
qDebugCamera() << Q_FUNC_INFO << "not implemented";
}
void AVFMediaRecorderControlIOS::setVolume(qreal volume)
{
Q_UNUSED(volume);
qDebugCamera() << Q_FUNC_INFO << "not implemented";
}
void AVFMediaRecorderControlIOS::assetWriterStarted()
{
m_lastStatus = QMediaRecorder::RecordingStatus;
Q_EMIT statusChanged(QMediaRecorder::RecordingStatus);
}
void AVFMediaRecorderControlIOS::assetWriterFailedToStart()
{
}
void AVFMediaRecorderControlIOS::assetWriterFailedToStop()
{
}
void AVFMediaRecorderControlIOS::assetWriterFinished()
{
AVFCameraControl *cameraControl = m_service->cameraControl();
Q_ASSERT(cameraControl);
const QMediaRecorder::Status lastStatus = m_lastStatus;
if (cameraControl->captureMode() & QCamera::CaptureVideo)
m_lastStatus = QMediaRecorder::LoadedStatus;
else
m_lastStatus = QMediaRecorder::UnloadedStatus;
m_service->videoOutput()->resetCaptureDelegate();
[m_service->session()->captureSession() startRunning];
if (m_lastStatus != lastStatus)
Q_EMIT statusChanged(m_lastStatus);
}
void AVFMediaRecorderControlIOS::captureModeChanged(QCamera::CaptureModes newMode)
{
AVFCameraControl *cameraControl = m_service->cameraControl();
Q_ASSERT(cameraControl);
const QMediaRecorder::Status lastStatus = m_lastStatus;
if (newMode & QCamera::CaptureVideo) {
if (cameraControl->status() == QCamera::ActiveStatus)
m_lastStatus = QMediaRecorder::LoadedStatus;
} else {
if (m_lastStatus == QMediaRecorder::RecordingStatus)
return stopWriter();
else
m_lastStatus = QMediaRecorder::UnloadedStatus;
}
if (m_lastStatus != lastStatus)
Q_EMIT statusChanged(m_lastStatus);
}
void AVFMediaRecorderControlIOS::cameraStatusChanged(QCamera::Status newStatus)
{
AVFCameraControl *cameraControl = m_service->cameraControl();
Q_ASSERT(cameraControl);
const QMediaRecorder::Status lastStatus = m_lastStatus;
const bool isCapture = cameraControl->captureMode() & QCamera::CaptureVideo;
if (newStatus == QCamera::StartingStatus) {
if (isCapture && m_lastStatus == QMediaRecorder::UnloadedStatus)
m_lastStatus = QMediaRecorder::LoadingStatus;
} else if (newStatus == QCamera::ActiveStatus) {
if (isCapture && m_lastStatus == QMediaRecorder::LoadingStatus)
m_lastStatus = QMediaRecorder::LoadedStatus;
} else {
if (m_lastStatus == QMediaRecorder::RecordingStatus)
return stopWriter();
if (newStatus == QCamera::UnloadedStatus)
m_lastStatus = QMediaRecorder::UnloadedStatus;
}
if (lastStatus != m_lastStatus)
Q_EMIT statusChanged(m_lastStatus);
}
void AVFMediaRecorderControlIOS::stopWriter()
{
if (m_lastStatus == QMediaRecorder::RecordingStatus) {
m_state = QMediaRecorder::StoppedState;
m_lastStatus = QMediaRecorder::FinalizingStatus;
Q_EMIT stateChanged(m_state);
Q_EMIT statusChanged(m_lastStatus);
dispatch_async(m_writerQueue, ^{
[m_writer stop];
});
}
}
#include "moc_avfmediarecordercontrol_ios.cpp"

View File

@@ -27,7 +27,6 @@ HEADERS += \
avfcameracontrol.h \
avfcamerametadatacontrol.h \
avfimagecapturecontrol.h \
avfmediarecordercontrol.h \
avfcameraservice.h \
avfcamerasession.h \
avfstoragelocation.h \
@@ -49,7 +48,6 @@ OBJECTIVE_SOURCES += \
avfcameracontrol.mm \
avfcamerametadatacontrol.mm \
avfimagecapturecontrol.mm \
avfmediarecordercontrol.mm \
avfcameraservice.mm \
avfcamerasession.mm \
avfstoragelocation.mm \
@@ -66,9 +64,20 @@ OBJECTIVE_SOURCES += \
avfimageencodercontrol.mm \
avfcameraflashcontrol.mm
ios {
osx {
HEADERS += avfcamerazoomcontrol.h
OBJECTIVE_SOURCES += avfcamerazoomcontrol.mm
HEADERS += avfmediarecordercontrol.h
OBJECTIVE_SOURCES += avfmediarecordercontrol.mm
}
ios {
HEADERS += avfcamerazoomcontrol.h \
avfmediaassetwriter.h \
avfmediarecordercontrol_ios.h
OBJECTIVE_SOURCES += avfcamerazoomcontrol.mm \
avfmediaassetwriter.mm \
avfmediarecordercontrol_ios.mm
}

View File

@@ -728,7 +728,7 @@ void AVFMediaPlayerSession::setVolume(int volume)
return;
}
[player setVolume:m_volume / 100.0f];
[player setVolume:volume / 100.0f];
m_volume = volume;
Q_EMIT volumeChanged(m_volume);
@@ -752,7 +752,7 @@ void AVFMediaPlayerSession::setMuted(bool muted)
return;
}
[player setMuted:m_muted];
[player setMuted:muted];
m_muted = muted;
Q_EMIT mutedChanged(muted);

View File

@@ -60,6 +60,8 @@ QSGVivanteVideoMaterial::QSGVivanteVideoMaterial() :
#endif
setFlag(Blending, false);
mShader = new QSGVivanteVideoMaterialShader;
}
QSGVivanteVideoMaterial::~QSGVivanteVideoMaterial()
@@ -73,7 +75,7 @@ QSGMaterialType *QSGVivanteVideoMaterial::type() const {
}
QSGMaterialShader *QSGVivanteVideoMaterial::createShader() const {
return new QSGVivanteVideoMaterialShader;
return mShader;
}
int QSGVivanteVideoMaterial::compare(const QSGMaterial *other) const {
@@ -175,18 +177,49 @@ GLuint QSGVivanteVideoMaterial::vivanteMapping(QVideoFrame vF)
glGenTextures(1, &tmpTexId);
mBitsToTextureMap.insert(vF.bits(), tmpTexId);
// Determine the full width & height. Full means: actual width/height plus extra padding pixels.
// The full width can be deduced from the bytesPerLine value. The full height is calculated
// by calculating the distance between the start of the first and second planes, and dividing
// it by the stride (= the bytesPerLine). If there is only one plane, we don't worry about
// extra padding rows, since there are no adjacent extra planes.
// XXX: This assumes the distance between bits(1) and bits(0) is exactly the size of the first
// plane (the Y plane in the case of YUV data). A better way would be to have a dedicated
// planeSize() or planeOffset() getter.
// Also, this assumes that planes are tightly packed, that is, there is no space between them.
// It is okay to assume this here though, because the Vivante direct textures also assume that.
// In other words, if the planes aren't tightly packed, then the direct textures won't be able
// to render the frame correctly anyway.
int fullWidth = vF.bytesPerLine() / QSGVivanteVideoNode::getBytesForPixelFormat(vF.pixelFormat());
int fullHeight = (vF.planeCount() > 1) ? ((vF.bits(1) - vF.bits(0)) / vF.bytesPerLine()) : vF.height();
// The uscale is the ratio of actual width to the full width (same for vscale and height).
// Since the vivante direct textures do not offer a way to explicitly specify the amount of padding
// columns and rows, we use a trick. We show the full frame - including the padding pixels - in the
// texture, but render only a subset of that texture. This subset goes from (0,0) to (uScale, vScale).
// In the shader, the texture coordinates (which go from (0.0, 0.0) to (1.0, 1.0)) are multiplied by
// the u/v scale values. Since 1.0 * x = x, this effectively limits the texture coordinates from
// (0.0, 0.0) - (1.0, 1.0) to (0.0, 0.0) - (uScale, vScale).
float uScale = float(vF.width()) / float(fullWidth);
float vScale = float(vF.height()) / float(fullHeight);
mShader->setUVScale(uScale, vScale);
const uchar *constBits = vF.bits();
void *bits = (void*)constBits;
#ifdef QT_VIVANTE_VIDEO_DEBUG
qDebug() << Q_FUNC_INFO << "new texture, texId: " << tmpTexId << "; constBits: " << constBits;
qDebug() << Q_FUNC_INFO
<< "new texture, texId: " << tmpTexId
<< "; constBits: " << constBits
<< "; actual/full width: " << vF.width() << "/" << fullWidth
<< "; actual/full height: " << vF.height() << "/" << fullHeight
<< "; UV scale: U " << uScale << " V " << vScale;
#endif
GLuint physical = ~0U;
glBindTexture(GL_TEXTURE_2D, tmpTexId);
glTexDirectVIVMap_LOCAL(GL_TEXTURE_2D,
vF.width(), vF.height(),
fullWidth, fullHeight,
QSGVivanteVideoNode::getVideoFormat2GLFormatMap().value(vF.pixelFormat()),
&bits, &physical);

View File

@@ -43,6 +43,8 @@
#include <private/qsgvideonode_p.h>
class QSGVivanteVideoMaterialShader;
class QSGVivanteVideoMaterial : public QSGMaterial
{
public:
@@ -78,6 +80,8 @@ private:
GLuint mTexDirectTexture;
GLvoid *mTexDirectPlanes[3];
QSGVivanteVideoMaterialShader *mShader;
};
#endif // QSGVIDEOMATERIAL_VIVMAP_H

View File

@@ -35,6 +35,13 @@
#include "qsgvivantevideonode.h"
#include "qsgvivantevideomaterial.h"
QSGVivanteVideoMaterialShader::QSGVivanteVideoMaterialShader() :
mUScale(1),
mVScale(1),
mNewUVScale(true)
{
}
void QSGVivanteVideoMaterialShader::updateState(const RenderState &state,
QSGMaterial *newMaterial,
QSGMaterial *oldMaterial)
@@ -48,6 +55,10 @@ void QSGVivanteVideoMaterialShader::updateState(const RenderState &state,
mat->setOpacity(state.opacity());
program()->setUniformValue(mIdOpacity, state.opacity());
}
if (mNewUVScale) {
program()->setUniformValue(mIdUVScale, mUScale, mVScale);
mNewUVScale = false;
}
if (state.isMatrixDirty())
program()->setUniformValue(mIdMatrix, state.combinedMatrix());
}
@@ -61,6 +72,13 @@ const char * const *QSGVivanteVideoMaterialShader::attributeNames() const {
return names;
}
void QSGVivanteVideoMaterialShader::setUVScale(float uScale, float vScale)
{
mUScale = uScale;
mVScale = vScale;
mNewUVScale = true;
}
const char *QSGVivanteVideoMaterialShader::vertexShader() const {
static const char *shader =
"uniform highp mat4 qt_Matrix; \n"
@@ -78,12 +96,13 @@ const char *QSGVivanteVideoMaterialShader::fragmentShader() const {
static const char *shader =
"uniform sampler2D texture;"
"uniform lowp float opacity;"
"uniform highp vec2 uvScale;"
""
"varying highp vec2 qt_TexCoord;"
""
"void main()"
"{"
" gl_FragColor = vec4(texture2D( texture, qt_TexCoord ).rgb, 1.0) * opacity;\n"
" gl_FragColor = vec4(texture2D( texture, qt_TexCoord * uvScale ).rgb, 1.0) * opacity;\n"
"}";
return shader;
}
@@ -93,4 +112,5 @@ void QSGVivanteVideoMaterialShader::initialize() {
mIdMatrix = program()->uniformLocation("qt_Matrix");
mIdTexture = program()->uniformLocation("texture");
mIdOpacity = program()->uniformLocation("opacity");
mIdUVScale = program()->uniformLocation("uvScale");
}

View File

@@ -39,9 +39,13 @@
class QSGVivanteVideoMaterialShader : public QSGMaterialShader
{
public:
QSGVivanteVideoMaterialShader();
void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
virtual char const *const *attributeNames() const;
void setUVScale(float uScale, float vScale);
protected:
virtual const char *vertexShader() const;
virtual const char *fragmentShader() const;
@@ -51,6 +55,11 @@ private:
int mIdMatrix;
int mIdTexture;
int mIdOpacity;
int mIdUVScale;
float mUScale;
float mVScale;
bool mNewUVScale;
};
#endif // QSGVIDEOMATERIALSHADER_VIVANTE_H

View File

@@ -78,4 +78,23 @@ const QMap<QVideoFrame::PixelFormat, GLenum>& QSGVivanteVideoNode::getVideoForma
}
int QSGVivanteVideoNode::getBytesForPixelFormat(QVideoFrame::PixelFormat pixelformat)
{
switch (pixelformat) {
case QVideoFrame::Format_YUV420P: return 1;
case QVideoFrame::Format_YV12: return 1;
case QVideoFrame::Format_NV12: return 1;
case QVideoFrame::Format_NV21: return 1;
case QVideoFrame::Format_UYVY: return 2;
case QVideoFrame::Format_YUYV: return 2;
case QVideoFrame::Format_RGB32: return 4;
case QVideoFrame::Format_ARGB32: return 4;
case QVideoFrame::Format_BGR32: return 4;
case QVideoFrame::Format_BGRA32: return 4;
case QVideoFrame::Format_RGB565: return 2;
default: return 1;
}
}

View File

@@ -49,6 +49,7 @@ public:
void setCurrentFrame(const QVideoFrame &frame, FrameFlags flags);
static const QMap<QVideoFrame::PixelFormat, GLenum>& getVideoFormat2GLFormatMap();
static int getBytesForPixelFormat(QVideoFrame::PixelFormat pixelformat);
private:
QVideoSurfaceFormat mFormat;

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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 2.0 or later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -389,7 +389,8 @@ void MFAudioDecoderControl::handleSampleAdded()
s->Release();
}
}
m_cachedAudioBuffer = QAudioBuffer(abuf, m_audioFormat, qint64(sampleStartTime / 10000));
// WMF uses 100-nanosecond units, QAudioDecoder uses milliseconds, QAudioBuffer uses microseconds...
m_cachedAudioBuffer = QAudioBuffer(abuf, m_audioFormat, qint64(sampleStartTime / 10));
m_bufferReady = true;
emit positionChanged(m_position);
emit bufferAvailableChanged(m_bufferReady);

View File

@@ -41,6 +41,10 @@
#include <private/qmediapluginloader_p.h>
#include <QtCore/qloggingcategory.h>
static void initResource() {
Q_INIT_RESOURCE(qtmultimediaquicktools);
}
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(qLcVideo, "qt.multimedia.video")
@@ -130,6 +134,7 @@ QDeclarativeVideoOutput::QDeclarativeVideoOutput(QQuickItem *parent) :
m_autoOrientation(false),
m_screenOrientationHandler(0)
{
initResource();
setFlag(ItemHasContents, true);
}

View File

@@ -318,7 +318,8 @@ void QSGVideoMaterial_YUV::bind()
m_frame = QVideoFrame();
} else {
for (int i = 0; i < m_planeCount; ++i) {
// Go backwards to finish with GL_TEXTURE0
for (int i = m_planeCount - 1; i >= 0; --i) {
functions->glActiveTexture(GL_TEXTURE0 + i);
functions->glBindTexture(GL_TEXTURE_2D, m_textureIds[i]);
}