diff options
Diffstat (limited to 'src/plugins/gstreamer/camerabin/camerabinsession.cpp')
-rw-r--r-- | src/plugins/gstreamer/camerabin/camerabinsession.cpp | 1587 |
1 files changed, 0 insertions, 1587 deletions
diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.cpp b/src/plugins/gstreamer/camerabin/camerabinsession.cpp deleted file mode 100644 index 22f5fb116..000000000 --- a/src/plugins/gstreamer/camerabin/camerabinsession.cpp +++ /dev/null @@ -1,1587 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 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-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtMultimedia/private/qtmultimediaglobal_p.h> -#include "camerabinsession.h" -#include "camerabincontrol.h" -#include "camerabinrecorder.h" -#include "camerabincontainer.h" -#include "camerabinaudioencoder.h" -#include "camerabinvideoencoder.h" -#include "camerabinimageencoder.h" - -#if QT_CONFIG(gstreamer_photography) -#include "camerabinexposure.h" -#include "camerabinflash.h" -#include "camerabinfocus.h" -#include "camerabinlocks.h" -#endif - -#include "camerabinzoom.h" -#include "camerabinimageprocessing.h" -#include "camerabinviewfindersettings.h" - -#include "camerabincapturedestination.h" -#include "camerabincapturebufferformat.h" -#include <private/qgstreamerbushelper_p.h> -#include <private/qgstreamervideorendererinterface_p.h> -#include <private/qgstutils_p.h> -#include <qmediarecorder.h> -#include <qvideosurfaceformat.h> - -#if QT_CONFIG(gstreamer_photography) -#include <gst/interfaces/photography.h> -#endif - -#include <gst/gsttagsetter.h> -#include <gst/gstversion.h> - -#include <QtCore/qdebug.h> -#include <QCoreApplication> -#include <QtCore/qmetaobject.h> -#include <QtGui/qdesktopservices.h> - -#include <QtGui/qimage.h> -#include <QtCore/qdatetime.h> - -#include <algorithm> - -//#define CAMERABIN_DEBUG 1 -//#define CAMERABIN_DEBUG_DUMP_BIN 1 -#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) - -#define FILENAME_PROPERTY "location" -#define MODE_PROPERTY "mode" -#define MUTE_PROPERTY "mute" -#define IMAGE_PP_PROPERTY "image-post-processing" -#define IMAGE_ENCODER_PROPERTY "image-encoder" -#define VIDEO_PP_PROPERTY "video-post-processing" -#define VIEWFINDER_SINK_PROPERTY "viewfinder-sink" -#define CAMERA_SOURCE_PROPERTY "camera-source" -#define AUDIO_SOURCE_PROPERTY "audio-source" -#define SUPPORTED_IMAGE_CAPTURE_CAPS_PROPERTY "image-capture-supported-caps" -#define SUPPORTED_VIDEO_CAPTURE_CAPS_PROPERTY "video-capture-supported-caps" -#define SUPPORTED_VIEWFINDER_CAPS_PROPERTY "viewfinder-supported-caps" -#define AUDIO_CAPTURE_CAPS_PROPERTY "audio-capture-caps" -#define IMAGE_CAPTURE_CAPS_PROPERTY "image-capture-caps" -#define VIDEO_CAPTURE_CAPS_PROPERTY "video-capture-caps" -#define VIEWFINDER_CAPS_PROPERTY "viewfinder-caps" -#define PREVIEW_CAPS_PROPERTY "preview-caps" -#define POST_PREVIEWS_PROPERTY "post-previews" - - -#define CAPTURE_START "start-capture" -#define CAPTURE_STOP "stop-capture" - -#define FILESINK_BIN_NAME "videobin-filesink" - -#define CAMERABIN_IMAGE_MODE 1 -#define CAMERABIN_VIDEO_MODE 2 - -#define PREVIEW_CAPS_4_3 \ - "video/x-raw-rgb, width = (int) 640, height = (int) 480" - -QT_BEGIN_NAMESPACE - -CameraBinSession::CameraBinSession(GstElementFactory *sourceFactory, QObject *parent) - :QObject(parent), - m_recordingActive(false), - m_status(QCamera::UnloadedStatus), - m_pendingState(QCamera::UnloadedState), - m_muted(false), - m_busy(false), - m_captureMode(QCamera::CaptureStillImage), - m_audioInputFactory(0), - m_videoInputFactory(0), - m_viewfinder(0), - m_viewfinderInterface(0), -#if QT_CONFIG(gstreamer_photography) - m_cameraExposureControl(0), - m_cameraFlashControl(0), - m_cameraFocusControl(0), - m_cameraLocksControl(0), -#endif - m_cameraSrc(0), - m_videoSrc(0), - m_viewfinderElement(0), - m_sourceFactory(sourceFactory), - m_viewfinderHasChanged(true), - m_inputDeviceHasChanged(true), - m_usingWrapperCameraBinSrc(false), - m_viewfinderProbe(this), - m_audioSrc(0), - m_audioConvert(0), - m_capsFilter(0), - m_fileSink(0), - m_audioEncoder(0), - m_videoEncoder(0), - m_muxer(0) -{ - if (m_sourceFactory) - gst_object_ref(GST_OBJECT(m_sourceFactory)); - m_camerabin = gst_element_factory_make(QT_GSTREAMER_CAMERABIN_ELEMENT_NAME, "camerabin"); - - g_signal_connect(G_OBJECT(m_camerabin), "notify::idle", G_CALLBACK(updateBusyStatus), this); - g_signal_connect(G_OBJECT(m_camerabin), "element-added", G_CALLBACK(elementAdded), this); - g_signal_connect(G_OBJECT(m_camerabin), "element-removed", G_CALLBACK(elementRemoved), this); - qt_gst_object_ref_sink(m_camerabin); - - m_bus = gst_element_get_bus(m_camerabin); - - m_busHelper = new QGstreamerBusHelper(m_bus, this); - m_busHelper->installMessageFilter(this); - - m_cameraControl = new CameraBinControl(this); - m_audioEncodeControl = new CameraBinAudioEncoder(this); - m_videoEncodeControl = new CameraBinVideoEncoder(this); - m_imageEncodeControl = new CameraBinImageEncoder(this); - m_recorderControl = new CameraBinRecorder(this); - m_mediaContainerControl = new CameraBinContainer(this); - m_cameraZoomControl = new CameraBinZoom(this); - m_imageProcessingControl = new CameraBinImageProcessing(this); - m_captureDestinationControl = new CameraBinCaptureDestination(this); - m_captureBufferFormatControl = new CameraBinCaptureBufferFormat(this); - - QByteArray envFlags = qgetenv("QT_GSTREAMER_CAMERABIN_FLAGS"); - if (!envFlags.isEmpty()) - g_object_set(G_OBJECT(m_camerabin), "flags", envFlags.toInt(), NULL); - - //post image preview in RGB format - g_object_set(G_OBJECT(m_camerabin), POST_PREVIEWS_PROPERTY, TRUE, NULL); - -#if GST_CHECK_VERSION(1,0,0) - GstCaps *previewCaps = gst_caps_new_simple( - "video/x-raw", - "format", G_TYPE_STRING, "RGBx", - NULL); -#else - GstCaps *previewCaps = gst_caps_from_string("video/x-raw-rgb"); -#endif - - g_object_set(G_OBJECT(m_camerabin), PREVIEW_CAPS_PROPERTY, previewCaps, NULL); - gst_caps_unref(previewCaps); -} - -CameraBinSession::~CameraBinSession() -{ - if (m_camerabin) { - if (m_viewfinderInterface) - m_viewfinderInterface->stopRenderer(); - - gst_element_set_state(m_camerabin, GST_STATE_NULL); - gst_element_get_state(m_camerabin, NULL, NULL, GST_CLOCK_TIME_NONE); - gst_object_unref(GST_OBJECT(m_bus)); - gst_object_unref(GST_OBJECT(m_camerabin)); - } - if (m_viewfinderElement) - gst_object_unref(GST_OBJECT(m_viewfinderElement)); - - if (m_sourceFactory) - gst_object_unref(GST_OBJECT(m_sourceFactory)); - - if (m_cameraSrc) - gst_object_unref(GST_OBJECT(m_cameraSrc)); - - if (m_videoSrc) - gst_object_unref(GST_OBJECT(m_videoSrc)); -} - -#if QT_CONFIG(gstreamer_photography) -GstPhotography *CameraBinSession::photography() -{ - if (GST_IS_PHOTOGRAPHY(m_camerabin)) { - return GST_PHOTOGRAPHY(m_camerabin); - } - - GstElement * const source = buildCameraSource(); - - if (source && GST_IS_PHOTOGRAPHY(source)) - return GST_PHOTOGRAPHY(source); - - return 0; -} - -CameraBinExposure *CameraBinSession::cameraExposureControl() -{ - if (!m_cameraExposureControl && photography()) - m_cameraExposureControl = new CameraBinExposure(this); - return m_cameraExposureControl; -} - -CameraBinFlash *CameraBinSession::cameraFlashControl() -{ - if (!m_cameraFlashControl && photography()) - m_cameraFlashControl = new CameraBinFlash(this); - return m_cameraFlashControl; -} - -CameraBinFocus *CameraBinSession::cameraFocusControl() -{ - if (!m_cameraFocusControl && photography()) - m_cameraFocusControl = new CameraBinFocus(this); - return m_cameraFocusControl; -} - -CameraBinLocks *CameraBinSession::cameraLocksControl() -{ - if (!m_cameraLocksControl && photography()) - m_cameraLocksControl = new CameraBinLocks(this); - return m_cameraLocksControl; -} -#endif - -bool CameraBinSession::setupCameraBin() -{ - if (!buildCameraSource()) - return false; - - if (m_viewfinderHasChanged) { - if (m_viewfinderElement) { - GstPad *pad = gst_element_get_static_pad(m_viewfinderElement, "sink"); - m_viewfinderProbe.removeProbeFromPad(pad); - gst_object_unref(GST_OBJECT(pad)); - gst_object_unref(GST_OBJECT(m_viewfinderElement)); - } - - m_viewfinderElement = m_viewfinderInterface ? m_viewfinderInterface->videoSink() : 0; -#if CAMERABIN_DEBUG - qDebug() << Q_FUNC_INFO << "Viewfinder changed, reconfigure."; -#endif - m_viewfinderHasChanged = false; - if (!m_viewfinderElement) { - if (m_pendingState == QCamera::ActiveState) - qWarning() << "Starting camera without viewfinder available"; - m_viewfinderElement = gst_element_factory_make("fakesink", NULL); - } - - GstPad *pad = gst_element_get_static_pad(m_viewfinderElement, "sink"); - m_viewfinderProbe.addProbeToPad(pad); - gst_object_unref(GST_OBJECT(pad)); - - g_object_set(G_OBJECT(m_viewfinderElement), "sync", FALSE, NULL); - qt_gst_object_ref_sink(GST_OBJECT(m_viewfinderElement)); - gst_element_set_state(m_camerabin, GST_STATE_NULL); - g_object_set(G_OBJECT(m_camerabin), VIEWFINDER_SINK_PROPERTY, m_viewfinderElement, NULL); - } - - return true; -} - -static GstCaps *resolutionToCaps(const QSize &resolution, - qreal frameRate = 0.0, - QVideoFrame::PixelFormat pixelFormat = QVideoFrame::Format_Invalid) -{ - GstCaps *caps = 0; - if (pixelFormat == QVideoFrame::Format_Invalid) - caps = QGstUtils::videoFilterCaps(); - else - caps = QGstUtils::capsForFormats(QList<QVideoFrame::PixelFormat>() << pixelFormat); - - if (!resolution.isEmpty()) { - gst_caps_set_simple( - caps, - "width", G_TYPE_INT, resolution.width(), - "height", G_TYPE_INT, resolution.height(), - NULL); - } - - if (frameRate > 0.0) { - gint numerator; - gint denominator; - qt_gst_util_double_to_fraction(frameRate, &numerator, &denominator); - - gst_caps_set_simple( - caps, - "framerate", GST_TYPE_FRACTION, numerator, denominator, - NULL); - } - - return caps; -} - -void CameraBinSession::setupCaptureResolution() -{ - QSize viewfinderResolution = m_viewfinderSettings.resolution(); - qreal viewfinderFrameRate = m_viewfinderSettings.maximumFrameRate(); - QVideoFrame::PixelFormat viewfinderPixelFormat = m_viewfinderSettings.pixelFormat(); - const QSize imageResolution = m_imageEncodeControl->imageSettings().resolution(); - const QSize videoResolution = m_videoEncodeControl->actualVideoSettings().resolution(); - - // WrapperCameraBinSrc cannot have different caps on its imgsrc, vidsrc and vfsrc pads. - // If capture resolution is specified, use it also for the viewfinder to avoid caps negotiation - // to fail. - if (m_usingWrapperCameraBinSrc) { - if (viewfinderResolution.isEmpty()) { - if (m_captureMode == QCamera::CaptureStillImage && !imageResolution.isEmpty()) - viewfinderResolution = imageResolution; - else if (m_captureMode == QCamera::CaptureVideo && !videoResolution.isEmpty()) - viewfinderResolution = videoResolution; - } - - // Make sure we don't use incompatible frame rate and pixel format with the new resolution - if (viewfinderResolution != m_viewfinderSettings.resolution() && - (!qFuzzyIsNull(viewfinderFrameRate) || viewfinderPixelFormat != QVideoFrame::Format_Invalid)) { - - enum { - Nothing = 0x0, - OnlyFrameRate = 0x1, - OnlyPixelFormat = 0x2, - Both = 0x4 - }; - quint8 found = Nothing; - auto viewfinderSettings = supportedViewfinderSettings(); - for (int i = 0; i < viewfinderSettings.count() && !(found & Both); ++i) { - const QCameraViewfinderSettings &s = viewfinderSettings.at(i); - if (s.resolution() == viewfinderResolution) { - if ((qFuzzyIsNull(viewfinderFrameRate) || s.maximumFrameRate() == viewfinderFrameRate) - && (viewfinderPixelFormat == QVideoFrame::Format_Invalid || s.pixelFormat() == viewfinderPixelFormat)) - found |= Both; - else if (s.maximumFrameRate() == viewfinderFrameRate) - found |= OnlyFrameRate; - else if (s.pixelFormat() == viewfinderPixelFormat) - found |= OnlyPixelFormat; - } - } - - if (found & Both) { - // no-op - } else if (found & OnlyPixelFormat) { - viewfinderFrameRate = qreal(0); - } else if (found & OnlyFrameRate) { - viewfinderPixelFormat = QVideoFrame::Format_Invalid; - } else { - viewfinderPixelFormat = QVideoFrame::Format_Invalid; - viewfinderFrameRate = qreal(0); - } - } - } - - GstCaps *caps = resolutionToCaps(imageResolution); - g_object_set(m_camerabin, IMAGE_CAPTURE_CAPS_PROPERTY, caps, NULL); - gst_caps_unref(caps); - - qreal framerate = m_videoEncodeControl->videoSettings().frameRate(); - caps = resolutionToCaps(videoResolution, framerate); - g_object_set(m_camerabin, VIDEO_CAPTURE_CAPS_PROPERTY, caps, NULL); - gst_caps_unref(caps); - - caps = resolutionToCaps(viewfinderResolution, viewfinderFrameRate, viewfinderPixelFormat); - g_object_set(m_camerabin, VIEWFINDER_CAPS_PROPERTY, caps, NULL); - gst_caps_unref(caps); - - // Special case when using mfw_v4lsrc - if (m_videoSrc && qstrcmp(qt_gst_element_get_factory_name(m_videoSrc), "mfw_v4lsrc") == 0) { - int capMode = 0; - if (viewfinderResolution == QSize(320, 240)) - capMode = 1; - else if (viewfinderResolution == QSize(720, 480)) - capMode = 2; - else if (viewfinderResolution == QSize(720, 576)) - capMode = 3; - else if (viewfinderResolution == QSize(1280, 720)) - capMode = 4; - else if (viewfinderResolution == QSize(1920, 1080)) - capMode = 5; - g_object_set(G_OBJECT(m_videoSrc), "capture-mode", capMode, NULL); - - if (!qFuzzyIsNull(viewfinderFrameRate)) { - int n, d; - qt_gst_util_double_to_fraction(viewfinderFrameRate, &n, &d); - g_object_set(G_OBJECT(m_videoSrc), "fps-n", n, NULL); - g_object_set(G_OBJECT(m_videoSrc), "fps-d", d, NULL); - } - } - - if (m_videoEncoder) - m_videoEncodeControl->applySettings(m_videoEncoder); -} - -void CameraBinSession::setAudioCaptureCaps() -{ - QAudioEncoderSettings settings = m_audioEncodeControl->audioSettings(); - const int sampleRate = settings.sampleRate(); - const int channelCount = settings.channelCount(); - - if (sampleRate <= 0 && channelCount <=0) - return; - -#if GST_CHECK_VERSION(1,0,0) - GstStructure *structure = gst_structure_new_empty(QT_GSTREAMER_RAW_AUDIO_MIME); -#else - GstStructure *structure = gst_structure_new( - QT_GSTREAMER_RAW_AUDIO_MIME, - "endianness", G_TYPE_INT, 1234, - "signed", G_TYPE_BOOLEAN, TRUE, - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - NULL); -#endif - if (sampleRate > 0) - gst_structure_set(structure, "rate", G_TYPE_INT, sampleRate, NULL); - if (channelCount > 0) - gst_structure_set(structure, "channels", G_TYPE_INT, channelCount, NULL); - - GstCaps *caps = gst_caps_new_full(structure, NULL); - g_object_set(G_OBJECT(m_camerabin), AUDIO_CAPTURE_CAPS_PROPERTY, caps, NULL); - gst_caps_unref(caps); - - if (m_audioEncoder) - m_audioEncodeControl->applySettings(m_audioEncoder); -} - -GstElement *CameraBinSession::buildCameraSource() -{ -#if CAMERABIN_DEBUG - qDebug() << Q_FUNC_INFO; -#endif - if (m_inputDevice.isEmpty()) - return nullptr; - - if (!m_inputDeviceHasChanged) - return m_cameraSrc; - - m_inputDeviceHasChanged = false; - m_usingWrapperCameraBinSrc = false; - - GstElement *camSrc = 0; - g_object_get(G_OBJECT(m_camerabin), CAMERA_SOURCE_PROPERTY, &camSrc, NULL); - - if (!m_cameraSrc && m_sourceFactory) - m_cameraSrc = gst_element_factory_create(m_sourceFactory, "camera_source"); - - // If gstreamer has set a default source use it. - if (!m_cameraSrc) - m_cameraSrc = camSrc; - - if (m_cameraSrc) { -#if CAMERABIN_DEBUG - qDebug() << "set camera device" << m_inputDevice; -#endif - m_usingWrapperCameraBinSrc = qstrcmp(qt_gst_element_get_factory_name(m_cameraSrc), "wrappercamerabinsrc") == 0; - - if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_cameraSrc), "video-source")) { - if (!m_videoSrc) { - /* QT_GSTREAMER_CAMERABIN_VIDEOSRC can be used to set the video source element. - - --- Usage - - QT_GSTREAMER_CAMERABIN_VIDEOSRC=[drivername=elementname[,drivername2=elementname2 ...],][elementname] - - --- Examples - - Always use 'somevideosrc': - QT_GSTREAMER_CAMERABIN_VIDEOSRC="somevideosrc" - - Use 'somevideosrc' when the device driver is 'somedriver', otherwise use default: - QT_GSTREAMER_CAMERABIN_VIDEOSRC="somedriver=somevideosrc" - - Use 'somevideosrc' when the device driver is 'somedriver', otherwise use 'somevideosrc2' - QT_GSTREAMER_CAMERABIN_VIDEOSRC="somedriver=somevideosrc,somevideosrc2" - */ - const QByteArray envVideoSource = qgetenv("QT_GSTREAMER_CAMERABIN_VIDEOSRC"); - - if (!envVideoSource.isEmpty()) { - const QList<QByteArray> sources = envVideoSource.split(','); - for (const QByteArray &source : sources) { - QList<QByteArray> keyValue = source.split('='); - QByteArray name = keyValue.at(0); - if (keyValue.count() > 1 && keyValue.at(0) == QGstUtils::cameraDriver(m_inputDevice, m_sourceFactory)) - name = keyValue.at(1); - - GError *error = NULL; - GstElement *element = gst_parse_launch(name, &error); - - if (error) { - g_printerr("ERROR: %s: %s\n", name.constData(), GST_STR_NULL(error->message)); - g_clear_error(&error); - } - if (element) { - m_videoSrc = element; - break; - } - } - } else if (m_videoInputFactory) { - m_videoSrc = m_videoInputFactory->buildElement(); - } - - if (!m_videoSrc) - m_videoSrc = gst_element_factory_make("v4l2src", "camera_source"); - - if (!m_videoSrc) - m_videoSrc = gst_element_factory_make("ksvideosrc", "camera_source"); - - if (!m_videoSrc) - m_videoSrc = gst_element_factory_make("avfvideosrc", "camera_source"); - - if (m_videoSrc) - g_object_set(G_OBJECT(m_cameraSrc), "video-source", m_videoSrc, NULL); - } - - if (m_videoSrc) { - if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSrc), "device")) - g_object_set(G_OBJECT(m_videoSrc), "device", m_inputDevice.toUtf8().constData(), NULL); - - if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSrc), "device-path")) - g_object_set(G_OBJECT(m_videoSrc), "device-path", m_inputDevice.toUtf8().constData(), NULL); - - if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSrc), "device-index")) - g_object_set(G_OBJECT(m_videoSrc), "device-index", m_inputDevice.toInt(), NULL); - } - } else if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_cameraSrc), "camera-device")) { - if (m_inputDevice == QLatin1String("secondary")) { - g_object_set(G_OBJECT(m_cameraSrc), "camera-device", 1, NULL); - } else { - g_object_set(G_OBJECT(m_cameraSrc), "camera-device", 0, NULL); - } - } - } - - if (m_cameraSrc != camSrc) { - g_object_set(G_OBJECT(m_camerabin), CAMERA_SOURCE_PROPERTY, m_cameraSrc, NULL); - // Unref only if camSrc is not m_cameraSrc to prevent double unrefing. - if (camSrc) - gst_object_unref(GST_OBJECT(camSrc)); - } - - return m_cameraSrc; -} - -void CameraBinSession::captureImage(int requestId, const QString &fileName) -{ - const QString actualFileName = m_mediaStorageLocation.generateFileName(fileName, - QMediaStorageLocation::Pictures, - QLatin1String("IMG_"), - QLatin1String("jpg")); - - m_requestId = requestId; - -#if CAMERABIN_DEBUG - qDebug() << Q_FUNC_INFO << m_requestId << fileName << "actual file name:" << actualFileName; -#endif - - g_object_set(G_OBJECT(m_camerabin), FILENAME_PROPERTY, actualFileName.toLocal8Bit().constData(), NULL); - - g_signal_emit_by_name(G_OBJECT(m_camerabin), CAPTURE_START, NULL); - - m_imageFileName = actualFileName; -} - -void CameraBinSession::setCaptureMode(QCamera::CaptureModes mode) -{ - m_captureMode = mode; - - switch (m_captureMode) { - case QCamera::CaptureStillImage: - g_object_set(m_camerabin, MODE_PROPERTY, CAMERABIN_IMAGE_MODE, NULL); - break; - case QCamera::CaptureVideo: - g_object_set(m_camerabin, MODE_PROPERTY, CAMERABIN_VIDEO_MODE, NULL); - break; - } - - m_recorderControl->updateStatus(); -} - -QUrl CameraBinSession::outputLocation() const -{ - //return the location service wrote data to, not one set by user, it can be empty. - return m_actualSink; -} - -bool CameraBinSession::setOutputLocation(const QUrl& sink) -{ - if (!sink.isRelative() && !sink.isLocalFile()) { - qWarning("Output location must be a local file"); - return false; - } - - m_sink = m_actualSink = sink; - return true; -} - -void CameraBinSession::setDevice(const QString &device) -{ - if (m_inputDevice != device) { - m_inputDevice = device; - m_inputDeviceHasChanged = true; - } -} - -void CameraBinSession::setAudioInput(QGstreamerElementFactory *audioInput) -{ - m_audioInputFactory = audioInput; -} - -void CameraBinSession::setVideoInput(QGstreamerElementFactory *videoInput) -{ - m_videoInputFactory = videoInput; - m_inputDeviceHasChanged = true; -} - -bool CameraBinSession::isReady() const -{ - //it's possible to use QCamera without any viewfinder attached - return !m_viewfinderInterface || m_viewfinderInterface->isReady(); -} - -void CameraBinSession::setViewfinder(QObject *viewfinder) -{ - if (m_viewfinderInterface) - m_viewfinderInterface->stopRenderer(); - - m_viewfinderInterface = qobject_cast<QGstreamerVideoRendererInterface*>(viewfinder); - if (!m_viewfinderInterface) - viewfinder = 0; - - if (m_viewfinder != viewfinder) { - bool oldReady = isReady(); - - if (m_viewfinder) { - disconnect(m_viewfinder, SIGNAL(sinkChanged()), - this, SLOT(handleViewfinderChange())); - disconnect(m_viewfinder, SIGNAL(readyChanged(bool)), - this, SIGNAL(readyChanged(bool))); - - m_busHelper->removeMessageFilter(m_viewfinder); - } - - m_viewfinder = viewfinder; - m_viewfinderHasChanged = true; - - if (m_viewfinder) { - connect(m_viewfinder, SIGNAL(sinkChanged()), - this, SLOT(handleViewfinderChange())); - connect(m_viewfinder, SIGNAL(readyChanged(bool)), - this, SIGNAL(readyChanged(bool))); - - m_busHelper->installMessageFilter(m_viewfinder); - } - - emit viewfinderChanged(); - if (oldReady != isReady()) - emit readyChanged(isReady()); - } -} - -static QList<QCameraViewfinderSettings> capsToViewfinderSettings(GstCaps *supportedCaps) -{ - QList<QCameraViewfinderSettings> settings; - - if (!supportedCaps) - return settings; - - supportedCaps = qt_gst_caps_normalize(supportedCaps); - - // Convert caps to QCameraViewfinderSettings - for (uint i = 0; i < gst_caps_get_size(supportedCaps); ++i) { - const GstStructure *structure = gst_caps_get_structure(supportedCaps, i); - - QCameraViewfinderSettings s; - s.setResolution(QGstUtils::structureResolution(structure)); - s.setPixelFormat(QGstUtils::structurePixelFormat(structure)); - s.setPixelAspectRatio(QGstUtils::structurePixelAspectRatio(structure)); - - QPair<qreal, qreal> frameRateRange = QGstUtils::structureFrameRateRange(structure); - s.setMinimumFrameRate(frameRateRange.first); - s.setMaximumFrameRate(frameRateRange.second); - - if (!s.resolution().isEmpty() - && s.pixelFormat() != QVideoFrame::Format_Invalid - && !settings.contains(s)) { - settings.append(s); - } - } - - gst_caps_unref(supportedCaps); - return settings; -} - -QList<QCameraViewfinderSettings> CameraBinSession::supportedViewfinderSettings() const -{ - if (m_status >= QCamera::LoadedStatus && m_supportedViewfinderSettings.isEmpty()) { - m_supportedViewfinderSettings = - capsToViewfinderSettings(supportedCaps(QCamera::CaptureViewfinder)); - } - - return m_supportedViewfinderSettings; -} - -QCameraViewfinderSettings CameraBinSession::viewfinderSettings() const -{ - return m_status == QCamera::ActiveStatus ? m_actualViewfinderSettings : m_viewfinderSettings; -} - -void CameraBinSession::ViewfinderProbe::probeCaps(GstCaps *caps) -{ - QGstreamerVideoProbeControl::probeCaps(caps); - - // Update actual viewfinder settings on viewfinder caps change - const GstStructure *s = gst_caps_get_structure(caps, 0); - const QPair<qreal, qreal> frameRate = QGstUtils::structureFrameRateRange(s); - session->m_actualViewfinderSettings.setResolution(QGstUtils::structureResolution(s)); - session->m_actualViewfinderSettings.setMinimumFrameRate(frameRate.first); - session->m_actualViewfinderSettings.setMaximumFrameRate(frameRate.second); - session->m_actualViewfinderSettings.setPixelFormat(QGstUtils::structurePixelFormat(s)); - session->m_actualViewfinderSettings.setPixelAspectRatio(QGstUtils::structurePixelAspectRatio(s)); -} - -void CameraBinSession::handleViewfinderChange() -{ - //the viewfinder will be reloaded - //shortly when the pipeline is started - m_viewfinderHasChanged = true; - emit viewfinderChanged(); -} - -void CameraBinSession::setStatus(QCamera::Status status) -{ - if (m_status == status) - return; - - m_status = status; - emit statusChanged(m_status); - - setStateHelper(m_pendingState); -} - -QCamera::Status CameraBinSession::status() const -{ - return m_status; -} - -QCamera::State CameraBinSession::pendingState() const -{ - return m_pendingState; -} - -void CameraBinSession::setState(QCamera::State newState) -{ - if (newState == m_pendingState) - return; - - m_pendingState = newState; - emit pendingStateChanged(m_pendingState); - -#if CAMERABIN_DEBUG - qDebug() << Q_FUNC_INFO << newState; -#endif - - setStateHelper(newState); -} - -void CameraBinSession::setStateHelper(QCamera::State state) -{ - switch (state) { - case QCamera::UnloadedState: - unload(); - break; - case QCamera::LoadedState: - if (m_status == QCamera::ActiveStatus) - stop(); - else if (m_status == QCamera::UnloadedStatus) - load(); - break; - case QCamera::ActiveState: - // If the viewfinder changed while in the loaded state, we need to reload the pipeline - if (m_status == QCamera::LoadedStatus && !m_viewfinderHasChanged) - start(); - else if (m_status == QCamera::UnloadedStatus || m_viewfinderHasChanged) - load(); - } -} - -void CameraBinSession::setError(int err, const QString &errorString) -{ - // Emit only first error - if (m_pendingState == QCamera::UnloadedState) - return; - - setState(QCamera::UnloadedState); - emit error(err, errorString); - setStatus(QCamera::UnloadedStatus); -} - -void CameraBinSession::load() -{ - if (m_status != QCamera::UnloadedStatus && !m_viewfinderHasChanged) - return; - - setStatus(QCamera::LoadingStatus); - - gst_element_set_state(m_camerabin, GST_STATE_NULL); - - if (!setupCameraBin()) { - setError(QCamera::CameraError, QStringLiteral("No camera source available")); - return; - } - - m_recorderControl->applySettings(); - -#if QT_CONFIG(gstreamer_encodingprofiles) - GstEncodingContainerProfile *profile = m_recorderControl->videoProfile(); - if (profile) { - g_object_set (G_OBJECT(m_camerabin), - "video-profile", - profile, - NULL); - gst_encoding_profile_unref(profile); - } -#endif - - gst_element_set_state(m_camerabin, GST_STATE_READY); -} - -void CameraBinSession::unload() -{ - if (m_status == QCamera::UnloadedStatus || m_status == QCamera::UnloadingStatus) - return; - - setStatus(QCamera::UnloadingStatus); - - if (m_recordingActive) - stopVideoRecording(); - - if (m_viewfinderInterface) - m_viewfinderInterface->stopRenderer(); - - gst_element_set_state(m_camerabin, GST_STATE_NULL); - - if (m_busy) - emit busyChanged(m_busy = false); - - m_supportedViewfinderSettings.clear(); - - setStatus(QCamera::UnloadedStatus); -} - -void CameraBinSession::start() -{ - if (m_status != QCamera::LoadedStatus) - return; - - setStatus(QCamera::StartingStatus); - - setAudioCaptureCaps(); - - setupCaptureResolution(); - - gst_element_set_state(m_camerabin, GST_STATE_PLAYING); -} - -void CameraBinSession::stop() -{ - if (m_status != QCamera::ActiveStatus) - return; - - setStatus(QCamera::StoppingStatus); - - if (m_recordingActive) - stopVideoRecording(); - - if (m_viewfinderInterface) - m_viewfinderInterface->stopRenderer(); - - gst_element_set_state(m_camerabin, GST_STATE_READY); -} - -bool CameraBinSession::isBusy() const -{ - return m_busy; -} - -void CameraBinSession::updateBusyStatus(GObject *o, GParamSpec *p, gpointer d) -{ - Q_UNUSED(p); - CameraBinSession *session = reinterpret_cast<CameraBinSession *>(d); - - gboolean idle = false; - g_object_get(o, "idle", &idle, NULL); - bool busy = !idle; - - if (session->m_busy != busy) { - session->m_busy = busy; - QMetaObject::invokeMethod(session, "busyChanged", - Qt::QueuedConnection, - Q_ARG(bool, busy)); - } -} - -qint64 CameraBinSession::duration() const -{ - if (m_camerabin) { - GstElement *fileSink = gst_bin_get_by_name(GST_BIN(m_camerabin), FILESINK_BIN_NAME); - if (fileSink) { - GstFormat format = GST_FORMAT_TIME; - gint64 duration = 0; - bool ret = qt_gst_element_query_position(fileSink, format, &duration); - gst_object_unref(GST_OBJECT(fileSink)); - if (ret) - return duration / 1000000; - } - } - - return 0; -} - -bool CameraBinSession::isMuted() const -{ - return m_muted; -} - -void CameraBinSession::setMuted(bool muted) -{ - if (m_muted != muted) { - m_muted = muted; - - if (m_camerabin) - g_object_set(G_OBJECT(m_camerabin), MUTE_PROPERTY, m_muted, NULL); - emit mutedChanged(m_muted); - } -} - -void CameraBinSession::setCaptureDevice(const QString &deviceName) -{ - m_captureDevice = deviceName; -} - -void CameraBinSession::setMetaData(const QMap<QByteArray, QVariant> &data) -{ - m_metaData = data; - - if (m_camerabin) - QGstUtils::setMetaData(m_camerabin, data); -} - -bool CameraBinSession::processSyncMessage(const QGstreamerMessage &message) -{ - GstMessage* gm = message.rawMessage(); - - if (gm && GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT) { - const GstStructure *st = gst_message_get_structure(gm); - const GValue *sampleValue = 0; - if (m_captureMode == QCamera::CaptureStillImage - && gst_structure_has_name(st, "preview-image") -#if GST_CHECK_VERSION(1,0,0) - && gst_structure_has_field_typed(st, "sample", GST_TYPE_SAMPLE) - && (sampleValue = gst_structure_get_value(st, "sample"))) { - GstSample * const sample = gst_value_get_sample(sampleValue); - GstCaps * const previewCaps = gst_sample_get_caps(sample); - GstBuffer * const buffer = gst_sample_get_buffer(sample); -#else - && gst_structure_has_field_typed(st, "buffer", GST_TYPE_BUFFER) - && (sampleValue = gst_structure_get_value(st, "buffer"))) { - GstBuffer * const buffer = gst_value_get_buffer(sampleValue); -#endif - - QImage image; -#if GST_CHECK_VERSION(1,0,0) - GstVideoInfo previewInfo; - if (gst_video_info_from_caps(&previewInfo, previewCaps)) - image = QGstUtils::bufferToImage(buffer, previewInfo); -#else - image = QGstUtils::bufferToImage(buffer); - gst_buffer_unref(buffer); -#endif - if (!image.isNull()) { - static QMetaMethod exposedSignal = QMetaMethod::fromSignal(&CameraBinSession::imageExposed); - exposedSignal.invoke(this, - Qt::QueuedConnection, - Q_ARG(int,m_requestId)); - - static QMetaMethod capturedSignal = QMetaMethod::fromSignal(&CameraBinSession::imageCaptured); - capturedSignal.invoke(this, - Qt::QueuedConnection, - Q_ARG(int,m_requestId), - Q_ARG(QImage,image)); - } - return true; - } -#if QT_CONFIG(gstreamer_photography) - if (gst_structure_has_name(st, GST_PHOTOGRAPHY_AUTOFOCUS_DONE)) - m_cameraFocusControl->handleFocusMessage(gm); -#endif - } - - return false; -} - -bool CameraBinSession::processBusMessage(const QGstreamerMessage &message) -{ - GstMessage* gm = message.rawMessage(); - - if (gm) { - if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ERROR) { - GError *err; - gchar *debug; - gst_message_parse_error (gm, &err, &debug); - - QString message; - - if (err && err->message) { - message = QString::fromUtf8(err->message); - qWarning() << "CameraBin error:" << message; -#if CAMERABIN_DEBUG - qWarning() << QString::fromUtf8(debug); -#endif - } - - // Only report error messages from camerabin or video source - if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_camerabin) - || GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_videoSrc)) { - if (message.isEmpty()) - message = tr("Camera error"); - - setError(int(QMediaRecorder::ResourceError), message); - } - -#ifdef CAMERABIN_DEBUG_DUMP_BIN - _gst_debug_bin_to_dot_file_with_ts(GST_BIN(m_camerabin), - GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /* GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES*/), - "camerabin_error"); -#endif - - - if (err) - g_error_free (err); - - if (debug) - g_free (debug); - } - - if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_WARNING) { - GError *err; - gchar *debug; - gst_message_parse_warning (gm, &err, &debug); - - if (err && err->message) - qWarning() << "CameraBin warning:" << QString::fromUtf8(err->message); - - if (err) - g_error_free (err); - if (debug) - g_free (debug); - } - - if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_camerabin)) { - switch (GST_MESSAGE_TYPE(gm)) { - case GST_MESSAGE_DURATION: - break; - - case GST_MESSAGE_STATE_CHANGED: - { - - GstState oldState; - GstState newState; - GstState pending; - - gst_message_parse_state_changed(gm, &oldState, &newState, &pending); - - -#if CAMERABIN_DEBUG - QStringList states; - states << "GST_STATE_VOID_PENDING" << "GST_STATE_NULL" << "GST_STATE_READY" << "GST_STATE_PAUSED" << "GST_STATE_PLAYING"; - - - qDebug() << QString("state changed: old: %1 new: %2 pending: %3") \ - .arg(states[oldState]) \ - .arg(states[newState]) \ - .arg(states[pending]); -#endif - -#ifdef CAMERABIN_DEBUG_DUMP_BIN - _gst_debug_bin_to_dot_file_with_ts(GST_BIN(m_camerabin), - GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /*GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES*/), - "camerabin"); -#endif - - switch (newState) { - case GST_STATE_VOID_PENDING: - case GST_STATE_NULL: - setStatus(QCamera::UnloadedStatus); - break; - case GST_STATE_READY: - if (oldState == GST_STATE_NULL) - m_supportedViewfinderSettings.clear(); - - setMetaData(m_metaData); - setStatus(QCamera::LoadedStatus); - break; - case GST_STATE_PLAYING: - setStatus(QCamera::ActiveStatus); - break; - case GST_STATE_PAUSED: - default: - break; - } - } - break; - default: - break; - } - } - } - - return false; -} - -QGstreamerVideoProbeControl *CameraBinSession::videoProbe() -{ - return &m_viewfinderProbe; -} - -QString CameraBinSession::currentContainerFormat() const -{ - if (!m_muxer) - return QString(); - - QString format; - - if (GstPad *srcPad = gst_element_get_static_pad(m_muxer, "src")) { - if (GstCaps *caps = qt_gst_pad_get_caps(srcPad)) { - gchar *capsString = gst_caps_to_string(caps); - format = QString::fromLatin1(capsString); - if (capsString) - g_free(capsString); - gst_caps_unref(caps); - } - gst_object_unref(GST_OBJECT(srcPad)); - } - - return format; -} - -void CameraBinSession::recordVideo() -{ - QString format = currentContainerFormat(); - if (format.isEmpty()) - format = m_mediaContainerControl->actualContainerFormat(); - - const QString fileName = m_sink.isLocalFile() ? m_sink.toLocalFile() : m_sink.toString(); - const QFileInfo fileInfo(fileName); - const QString extension = fileInfo.suffix().isEmpty() - ? QGstUtils::fileExtensionForMimeType(format) - : fileInfo.suffix(); - - const QString actualFileName = m_mediaStorageLocation.generateFileName(fileName, - QMediaStorageLocation::Movies, - QLatin1String("clip_"), - extension); - - m_recordingActive = true; - m_actualSink = QUrl::fromLocalFile(actualFileName); - - g_object_set(G_OBJECT(m_camerabin), FILENAME_PROPERTY, QFile::encodeName(actualFileName).constData(), NULL); - - g_signal_emit_by_name(G_OBJECT(m_camerabin), CAPTURE_START, NULL); -} - -void CameraBinSession::stopVideoRecording() -{ - m_recordingActive = false; - g_signal_emit_by_name(G_OBJECT(m_camerabin), CAPTURE_STOP, NULL); -} - -//internal, only used by CameraBinSession::supportedFrameRates. -//recursively fills the list of framerates res from value data. -static void readValue(const GValue *value, QList< QPair<int,int> > *res, bool *continuous) -{ - if (GST_VALUE_HOLDS_FRACTION(value)) { - int num = gst_value_get_fraction_numerator(value); - int denum = gst_value_get_fraction_denominator(value); - - *res << QPair<int,int>(num, denum); - } else if (GST_VALUE_HOLDS_FRACTION_RANGE(value)) { - const GValue *rateValueMin = gst_value_get_fraction_range_min(value); - const GValue *rateValueMax = gst_value_get_fraction_range_max(value); - - if (continuous) - *continuous = true; - - readValue(rateValueMin, res, continuous); - readValue(rateValueMax, res, continuous); - } else if (GST_VALUE_HOLDS_LIST(value)) { - for (uint i=0; i<gst_value_list_get_size(value); i++) { - readValue(gst_value_list_get_value(value, i), res, continuous); - } - } -} - -static bool rateLessThan(const QPair<int,int> &r1, const QPair<int,int> &r2) -{ - return r1.first*r2.second < r2.first*r1.second; -} - -GstCaps *CameraBinSession::supportedCaps(QCamera::CaptureModes mode) const -{ - GstCaps *supportedCaps = 0; - - // When using wrappercamerabinsrc, get the supported caps directly from the video source element. - // This makes sure we only get the caps actually supported by the video source element. - if (m_videoSrc) { - GstPad *pad = gst_element_get_static_pad(m_videoSrc, "src"); - if (pad) { - supportedCaps = qt_gst_pad_get_caps(pad); - gst_object_unref(GST_OBJECT(pad)); - } - } - - // Otherwise, let the camerabin handle this. - if (!supportedCaps) { - const gchar *prop; - switch (mode) { - case QCamera::CaptureStillImage: - prop = SUPPORTED_IMAGE_CAPTURE_CAPS_PROPERTY; - break; - case QCamera::CaptureVideo: - prop = SUPPORTED_VIDEO_CAPTURE_CAPS_PROPERTY; - break; - case QCamera::CaptureViewfinder: - default: - prop = SUPPORTED_VIEWFINDER_CAPS_PROPERTY; - break; - } - - g_object_get(G_OBJECT(m_camerabin), prop, &supportedCaps, NULL); - } - - return supportedCaps; -} - -QList< QPair<int,int> > CameraBinSession::supportedFrameRates(const QSize &frameSize, bool *continuous) const -{ - QList< QPair<int,int> > res; - - GstCaps *supportedCaps = this->supportedCaps(QCamera::CaptureVideo); - - if (!supportedCaps) - return res; - - GstCaps *caps = 0; - - if (frameSize.isEmpty()) { - caps = gst_caps_copy(supportedCaps); - } else { - GstCaps *filter = QGstUtils::videoFilterCaps(); - gst_caps_set_simple( - filter, - "width", G_TYPE_INT, frameSize.width(), - "height", G_TYPE_INT, frameSize.height(), - NULL); - - caps = gst_caps_intersect(supportedCaps, filter); - gst_caps_unref(filter); - } - gst_caps_unref(supportedCaps); - - //simplify to the list of rates only: - caps = gst_caps_make_writable(caps); - for (uint i=0; i<gst_caps_get_size(caps); i++) { - GstStructure *structure = gst_caps_get_structure(caps, i); - gst_structure_set_name(structure, "video/x-raw"); -#if GST_CHECK_VERSION(1,2,0) - gst_caps_set_features(caps, i, NULL); -#endif - const GValue *oldRate = gst_structure_get_value(structure, "framerate"); - if (!oldRate) - continue; - - GValue rate; - memset(&rate, 0, sizeof(rate)); - g_value_init(&rate, G_VALUE_TYPE(oldRate)); - g_value_copy(oldRate, &rate); - gst_structure_remove_all_fields(structure); - gst_structure_set_value(structure, "framerate", &rate); - g_value_unset(&rate); - } -#if GST_CHECK_VERSION(1,0,0) - caps = gst_caps_simplify(caps); -#else - gst_caps_do_simplify(caps); -#endif - - for (uint i=0; i<gst_caps_get_size(caps); i++) { - GstStructure *structure = gst_caps_get_structure(caps, i); - const GValue *rateValue = gst_structure_get_value(structure, "framerate"); - if (!rateValue) - continue; - - readValue(rateValue, &res, continuous); - } - - std::sort(res.begin(), res.end(), rateLessThan); - -#if CAMERABIN_DEBUG - qDebug() << "Supported rates:" << caps; - qDebug() << res; -#endif - - gst_caps_unref(caps); - - return res; -} - -//internal, only used by CameraBinSession::supportedResolutions -//recursively find the supported resolutions range. -static QPair<int,int> valueRange(const GValue *value, bool *continuous) -{ - int minValue = 0; - int maxValue = 0; - - if (g_value_type_compatible(G_VALUE_TYPE(value), G_TYPE_INT)) { - minValue = maxValue = g_value_get_int(value); - } else if (GST_VALUE_HOLDS_INT_RANGE(value)) { - minValue = gst_value_get_int_range_min(value); - maxValue = gst_value_get_int_range_max(value); - *continuous = true; - } else if (GST_VALUE_HOLDS_LIST(value)) { - for (uint i=0; i<gst_value_list_get_size(value); i++) { - QPair<int,int> res = valueRange(gst_value_list_get_value(value, i), continuous); - - if (res.first > 0 && minValue > 0) - minValue = qMin(minValue, res.first); - else //select non 0 valid value - minValue = qMax(minValue, res.first); - - maxValue = qMax(maxValue, res.second); - } - } - - return QPair<int,int>(minValue, maxValue); -} - -static bool resolutionLessThan(const QSize &r1, const QSize &r2) -{ - return qlonglong(r1.width()) * r1.height() < qlonglong(r2.width()) * r2.height(); -} - - -QList<QSize> CameraBinSession::supportedResolutions(QPair<int,int> rate, - bool *continuous, - QCamera::CaptureModes mode) const -{ - QList<QSize> res; - - if (continuous) - *continuous = false; - - GstCaps *supportedCaps = this->supportedCaps(mode); - -#if CAMERABIN_DEBUG - qDebug() << "Source caps:" << supportedCaps; -#endif - - if (!supportedCaps) - return res; - - GstCaps *caps = 0; - bool isContinuous = false; - - if (rate.first <= 0 || rate.second <= 0) { - caps = gst_caps_copy(supportedCaps); - } else { - GstCaps *filter = QGstUtils::videoFilterCaps(); - gst_caps_set_simple( - filter, - "framerate" , GST_TYPE_FRACTION , rate.first, rate.second, - NULL); - caps = gst_caps_intersect(supportedCaps, filter); - gst_caps_unref(filter); - } - gst_caps_unref(supportedCaps); - - //simplify to the list of resolutions only: - caps = gst_caps_make_writable(caps); - for (uint i=0; i<gst_caps_get_size(caps); i++) { - GstStructure *structure = gst_caps_get_structure(caps, i); - gst_structure_set_name(structure, "video/x-raw"); -#if GST_CHECK_VERSION(1,2,0) - gst_caps_set_features(caps, i, NULL); -#endif - const GValue *oldW = gst_structure_get_value(structure, "width"); - const GValue *oldH = gst_structure_get_value(structure, "height"); - if (!oldW || !oldH) - continue; - - GValue w; - memset(&w, 0, sizeof(GValue)); - GValue h; - memset(&h, 0, sizeof(GValue)); - g_value_init(&w, G_VALUE_TYPE(oldW)); - g_value_init(&h, G_VALUE_TYPE(oldH)); - g_value_copy(oldW, &w); - g_value_copy(oldH, &h); - gst_structure_remove_all_fields(structure); - gst_structure_set_value(structure, "width", &w); - gst_structure_set_value(structure, "height", &h); - g_value_unset(&w); - g_value_unset(&h); - } - -#if GST_CHECK_VERSION(1,0,0) - caps = gst_caps_simplify(caps); -#else - gst_caps_do_simplify(caps); -#endif - - - for (uint i=0; i<gst_caps_get_size(caps); i++) { - GstStructure *structure = gst_caps_get_structure(caps, i); - const GValue *wValue = gst_structure_get_value(structure, "width"); - const GValue *hValue = gst_structure_get_value(structure, "height"); - if (!wValue || !hValue) - continue; - - QPair<int,int> wRange = valueRange(wValue, &isContinuous); - QPair<int,int> hRange = valueRange(hValue, &isContinuous); - - QSize minSize(wRange.first, hRange.first); - QSize maxSize(wRange.second, hRange.second); - - if (!minSize.isEmpty()) - res << minSize; - - if (minSize != maxSize && !maxSize.isEmpty()) - res << maxSize; - } - - - std::sort(res.begin(), res.end(), resolutionLessThan); - - //if the range is continuos, populate is with the common rates - if (isContinuous && res.size() >= 2) { - //fill the ragne with common value - static const QList<QSize> commonSizes = - QList<QSize>() << QSize(128, 96) - << QSize(160,120) - << QSize(176, 144) - << QSize(320, 240) - << QSize(352, 288) - << QSize(640, 480) - << QSize(848, 480) - << QSize(854, 480) - << QSize(1024, 768) - << QSize(1280, 720) // HD 720 - << QSize(1280, 1024) - << QSize(1600, 1200) - << QSize(1920, 1080) // HD - << QSize(1920, 1200) - << QSize(2048, 1536) - << QSize(2560, 1600) - << QSize(2580, 1936); - QSize minSize = res.first(); - QSize maxSize = res.last(); - res.clear(); - - for (const QSize &candidate : commonSizes) { - int w = candidate.width(); - int h = candidate.height(); - - if (w > maxSize.width() && h > maxSize.height()) - break; - - if (w >= minSize.width() && h >= minSize.height() && - w <= maxSize.width() && h <= maxSize.height()) - res << candidate; - } - - if (res.isEmpty() || res.first() != minSize) - res.prepend(minSize); - - if (res.last() != maxSize) - res.append(maxSize); - } - -#if CAMERABIN_DEBUG - qDebug() << "Supported resolutions:" << gst_caps_to_string(caps); - qDebug() << res; -#endif - - gst_caps_unref(caps); - - if (continuous) - *continuous = isContinuous; - - return res; -} - -void CameraBinSession::elementAdded(GstBin *, GstElement *element, CameraBinSession *session) -{ - GstElementFactory *factory = gst_element_get_factory(element); - - if (GST_IS_BIN(element)) { - g_signal_connect(G_OBJECT(element), "element-added", G_CALLBACK(elementAdded), session); - g_signal_connect(G_OBJECT(element), "element-removed", G_CALLBACK(elementRemoved), session); - } else if (!factory) { - // no-op -#if GST_CHECK_VERSION(0,10,31) - } else if (gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_AUDIO_ENCODER)) { -#else - } else if (strstr(gst_element_factory_get_klass(factory), "Encoder/Audio") != NULL) { -#endif - session->m_audioEncoder = element; - - session->m_audioEncodeControl->applySettings(element); -#if GST_CHECK_VERSION(0,10,31) - } else if (gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_VIDEO_ENCODER)) { -#else - } else if (strstr(gst_element_factory_get_klass(factory), "Encoder/Video") != NULL) { -#endif - session->m_videoEncoder = element; - - session->m_videoEncodeControl->applySettings(element); -#if GST_CHECK_VERSION(0,10,31) - } else if (gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_MUXER)) { -#else - } else if (strstr(gst_element_factory_get_klass(factory), "Muxer") != NULL) { -#endif - session->m_muxer = element; - } -} - -void CameraBinSession::elementRemoved(GstBin *, GstElement *element, CameraBinSession *session) -{ - if (element == session->m_audioEncoder) - session->m_audioEncoder = 0; - else if (element == session->m_videoEncoder) - session->m_videoEncoder = 0; - else if (element == session->m_muxer) - session->m_muxer = 0; -} - -QT_END_NAMESPACE |