diff options
Diffstat (limited to 'src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp')
-rw-r--r-- | src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp | 285 |
1 files changed, 85 insertions, 200 deletions
diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp index a2bd80de8..af5b339e5 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp +++ b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp @@ -45,6 +45,7 @@ #include <gst/gsttagsetter.h> #include <gst/gstversion.h> +#include <gst/video/video.h> #include <QtCore/qdebug.h> #include <QtCore/qurl.h> @@ -52,7 +53,6 @@ #include <QCoreApplication> #include <QtCore/qmetaobject.h> #include <QtCore/qfile.h> - #include <QtGui/qimage.h> QT_BEGIN_NAMESPACE @@ -64,7 +64,7 @@ QGstreamerCaptureSession::QGstreamerCaptureSession(QGstreamerCaptureSession::Cap m_waitingForEos(false), m_pipelineMode(EmptyPipeline), m_captureMode(captureMode), - m_audioBufferProbeId(-1), + m_audioProbe(0), m_audioInputFactory(0), m_audioPreviewFactory(0), m_videoInputFactory(0), @@ -169,7 +169,7 @@ GstElement *QGstreamerCaptureSession::buildEncodeBin() if (m_captureMode & Video) { GstElement *videoQueue = gst_element_factory_make("queue", "video-encode-queue"); - GstElement *colorspace = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace-encoder"); + GstElement *colorspace = gst_element_factory_make(QT_GSTREAMER_COLORCONVERSION_ELEMENT_NAME, "videoconvert-encoder"); GstElement *videoscale = gst_element_factory_make("videoscale","videoscale-encoder"); gst_bin_add_many(GST_BIN(encodeBin), videoQueue, colorspace, videoscale, NULL); @@ -280,7 +280,7 @@ GstElement *QGstreamerCaptureSession::buildVideoPreview() if (m_viewfinderInterface) { GstElement *bin = gst_bin_new("video-preview-bin"); - GstElement *colorspace = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace-preview"); + GstElement *colorspace = gst_element_factory_make(QT_GSTREAMER_COLORCONVERSION_ELEMENT_NAME, "videoconvert-preview"); GstElement *capsFilter = gst_element_factory_make("capsfilter", "capsfilter-video-preview"); GstElement *preview = m_viewfinderInterface->videoSink(); @@ -299,36 +299,25 @@ GstElement *QGstreamerCaptureSession::buildVideoPreview() resolution = m_imageEncodeControl->imageSettings().resolution(); } - if (!resolution.isEmpty() || frameRate > 0.001) { - GstCaps *caps = gst_caps_new_empty(); - QStringList structureTypes; - structureTypes << "video/x-raw-yuv" << "video/x-raw-rgb"; - - foreach(const QString &structureType, structureTypes) { - GstStructure *structure = gst_structure_new(structureType.toLatin1().constData(), NULL); - - if (!resolution.isEmpty()) { - gst_structure_set(structure, "width", G_TYPE_INT, resolution.width(), NULL); - gst_structure_set(structure, "height", G_TYPE_INT, resolution.height(), NULL); - } - - if (frameRate > 0.001) { - QPair<int,int> rate = m_videoEncodeControl->rateAsRational(); + GstCaps *caps = QGstUtils::videoFilterCaps(); - //qDebug() << "frame rate:" << num << denum; + if (!resolution.isEmpty()) { + gst_caps_set_simple(caps, "width", G_TYPE_INT, resolution.width(), NULL); + gst_caps_set_simple(caps, "height", G_TYPE_INT, resolution.height(), NULL); + } + if (frameRate > 0.001) { + QPair<int,int> rate = m_videoEncodeControl->rateAsRational(); - gst_structure_set(structure, "framerate", GST_TYPE_FRACTION, rate.first, rate.second, NULL); - } + //qDebug() << "frame rate:" << num << denum; - gst_caps_append_structure(caps,structure); - } + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, rate.first, rate.second, NULL); + } - //qDebug() << "set video preview caps filter:" << gst_caps_to_string(caps); + //qDebug() << "set video preview caps filter:" << gst_caps_to_string(caps); - g_object_set(G_OBJECT(capsFilter), "caps", caps, NULL); + g_object_set(G_OBJECT(capsFilter), "caps", caps, NULL); - gst_caps_unref(caps); - } + gst_caps_unref(caps); // add ghostpads GstPad *pad = gst_element_get_static_pad(colorspace, "sink"); @@ -342,7 +331,7 @@ GstElement *QGstreamerCaptureSession::buildVideoPreview() previewElement = gst_element_factory_make("fakesink", "video-preview"); #else GstElement *bin = gst_bin_new("video-preview-bin"); - GstElement *colorspace = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace-preview"); + GstElement *colorspace = gst_element_factory_make(QT_GSTREAMER_COLORCONVERSION_ELEMENT_NAME, "videoconvert-preview"); GstElement *preview = gst_element_factory_make("ximagesink", "video-preview"); gst_bin_add_many(GST_BIN(bin), colorspace, preview, NULL); gst_element_link(colorspace,preview); @@ -360,101 +349,49 @@ GstElement *QGstreamerCaptureSession::buildVideoPreview() return previewElement; } - -static gboolean passImageFilter(GstElement *element, - GstBuffer *buffer, - void *appdata) +void QGstreamerCaptureSession::probeCaps(GstCaps *caps) { - Q_UNUSED(element); - Q_UNUSED(buffer); - - QGstreamerCaptureSession *session = (QGstreamerCaptureSession *)appdata; - if (session->m_passImage || session->m_passPrerollImage) { - session->m_passImage = false; - - if (session->m_passPrerollImage) { - session->m_passPrerollImage = false; - return TRUE; - } - session->m_passPrerollImage = false; - - QImage img; - - GstCaps *caps = gst_buffer_get_caps(buffer); - if (caps) { - GstStructure *structure = gst_caps_get_structure (caps, 0); - gint width = 0; - gint height = 0; - - if (structure && - gst_structure_get_int(structure, "width", &width) && - gst_structure_get_int(structure, "height", &height) && - width > 0 && height > 0) { - if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-yuv") == 0) { - guint32 fourcc = 0; - gst_structure_get_fourcc(structure, "format", &fourcc); - - if (fourcc == GST_MAKE_FOURCC('I','4','2','0')) { - img = QImage(width/2, height/2, QImage::Format_RGB32); - - const uchar *data = (const uchar *)buffer->data; +#if GST_CHECK_VERSION(1,0,0) + gst_video_info_from_caps(&m_previewInfo, caps); +#else + Q_UNUSED(caps); +#endif +} - for (int y=0; y<height; y+=2) { - const uchar *yLine = data + y*width; - const uchar *uLine = data + width*height + y*width/4; - const uchar *vLine = data + width*height*5/4 + y*width/4; +bool QGstreamerCaptureSession::probeBuffer(GstBuffer *buffer) +{ + if (m_passPrerollImage) { + m_passImage = false; + m_passPrerollImage = false; - for (int x=0; x<width; x+=2) { - const qreal Y = 1.164*(yLine[x]-16); - const int U = uLine[x/2]-128; - const int V = vLine[x/2]-128; + return true; + } else if (!m_passImage) { + return false; + } - int b = qBound(0, int(Y + 2.018*U), 255); - int g = qBound(0, int(Y - 0.813*V - 0.391*U), 255); - int r = qBound(0, int(Y + 1.596*V), 255); + m_passImage = false; - img.setPixel(x/2,y/2,qRgb(r,g,b)); - } - } - } +#if GST_CHECK_VERSION(1,0,0) + QImage img = QGstUtils::bufferToImage(buffer, m_previewInfo); +#else + QImage img = QGstUtils::bufferToImage(buffer); +#endif - } else if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-rgb") == 0) { - QImage::Format format = QImage::Format_Invalid; - int bpp = 0; - gst_structure_get_int(structure, "bpp", &bpp); - - if (bpp == 24) - format = QImage::Format_RGB888; - else if (bpp == 32) - format = QImage::Format_RGB32; - - if (format != QImage::Format_Invalid) { - img = QImage((const uchar *)buffer->data, - width, - height, - format); - img.bits(); //detach - } - } - } - gst_caps_unref(caps); - } + if (img.isNull()) + return true; - static QMetaMethod exposedSignal = QMetaMethod::fromSignal(&QGstreamerCaptureSession::imageExposed); - exposedSignal.invoke(session, - Qt::QueuedConnection, - Q_ARG(int,session->m_imageRequestId)); + static QMetaMethod exposedSignal = QMetaMethod::fromSignal(&QGstreamerCaptureSession::imageExposed); + exposedSignal.invoke(this, + Qt::QueuedConnection, + Q_ARG(int,m_imageRequestId)); - static QMetaMethod capturedSignal = QMetaMethod::fromSignal(&QGstreamerCaptureSession::imageCaptured); - capturedSignal.invoke(session, - Qt::QueuedConnection, - Q_ARG(int,session->m_imageRequestId), - Q_ARG(QImage,img)); + static QMetaMethod capturedSignal = QMetaMethod::fromSignal(&QGstreamerCaptureSession::imageCaptured); + capturedSignal.invoke(this, + Qt::QueuedConnection, + Q_ARG(int,m_imageRequestId), + Q_ARG(QImage,img)); - return TRUE; - } else { - return FALSE; - } + return true; } static gboolean saveImageFilter(GstElement *element, @@ -471,7 +408,15 @@ static gboolean saveImageFilter(GstElement *element, if (!fileName.isEmpty()) { QFile f(fileName); if (f.open(QFile::WriteOnly)) { - f.write((const char *)buffer->data, buffer->size); +#if GST_CHECK_VERSION(1,0,0) + GstMapInfo info; + if (gst_buffer_map(buffer, &info, GST_MAP_READ)) { + f.write(reinterpret_cast<const char *>(info.data), info.size); + gst_buffer_unmap(buffer, &info); + } +#else + f.write(reinterpret_cast<const char *>(buffer->data), buffer->size); +#endif f.close(); static QMetaMethod savedSignal = QMetaMethod::fromSignal(&QGstreamerCaptureSession::imageSaved); @@ -489,18 +434,19 @@ GstElement *QGstreamerCaptureSession::buildImageCapture() { GstElement *bin = gst_bin_new("image-capture-bin"); GstElement *queue = gst_element_factory_make("queue", "queue-image-capture"); - GstElement *colorspace = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace-image-capture"); + GstElement *colorspace = gst_element_factory_make(QT_GSTREAMER_COLORCONVERSION_ELEMENT_NAME, "videoconvert-image-capture"); GstElement *encoder = gst_element_factory_make("jpegenc", "image-encoder"); GstElement *sink = gst_element_factory_make("fakesink","sink-image-capture"); GstPad *pad = gst_element_get_static_pad(queue, "src"); Q_ASSERT(pad); - gst_pad_add_buffer_probe(pad, G_CALLBACK(passImageFilter), this); + + addProbeToPad(pad, false); + gst_object_unref(GST_OBJECT(pad)); g_object_set(G_OBJECT(sink), "signal-handoffs", TRUE, NULL); - g_signal_connect(G_OBJECT(sink), "handoff", - G_CALLBACK(saveImageFilter), this); + g_signal_connect(G_OBJECT(sink), "handoff", G_CALLBACK(saveImageFilter), this); gst_bin_add_many(GST_BIN(bin), queue, colorspace, encoder, sink, NULL); gst_element_link_many(queue, colorspace, encoder, sink, NULL); @@ -715,6 +661,8 @@ void QGstreamerCaptureSession::dumpGraph(const QString &fileName) _gst_debug_bin_to_dot_file(GST_BIN(m_pipeline), GstDebugGraphDetails(/*GST_DEBUG_GRAPH_SHOW_ALL |*/ GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES), fileName.toLatin1()); +#else + Q_UNUSED(fileName); #endif } @@ -877,10 +825,8 @@ void QGstreamerCaptureSession::setState(QGstreamerCaptureSession::State newState qint64 QGstreamerCaptureSession::duration() const { - GstFormat format = GST_FORMAT_TIME; - gint64 duration = 0; - - if ( m_encodeBin && gst_element_query_position(m_encodeBin, &format, &duration)) + gint64 duration = 0; + if (m_encodeBin && qt_gst_element_query_position(m_encodeBin, GST_FORMAT_TIME, &duration)) return duration / 1000000; else return 0; @@ -896,50 +842,8 @@ void QGstreamerCaptureSession::setMetaData(const QMap<QByteArray, QVariant> &dat //qDebug() << "QGstreamerCaptureSession::setMetaData" << data; m_metaData = data; - if (m_encodeBin) { - GstIterator *elements = gst_bin_iterate_all_by_interface(GST_BIN(m_encodeBin), GST_TYPE_TAG_SETTER); - GstElement *element = 0; - while (gst_iterator_next(elements, (void**)&element) == GST_ITERATOR_OK) { - //qDebug() << "found element with tag setter interface:" << gst_element_get_name(element); - QMapIterator<QByteArray, QVariant> it(data); - while (it.hasNext()) { - it.next(); - const QString tagName = it.key(); - const QVariant tagValue = it.value(); - - - switch(tagValue.type()) { - case QVariant::String: - gst_tag_setter_add_tags(GST_TAG_SETTER(element), - GST_TAG_MERGE_REPLACE_ALL, - tagName.toUtf8().constData(), - tagValue.toString().toUtf8().constData(), - NULL); - break; - case QVariant::Int: - case QVariant::LongLong: - gst_tag_setter_add_tags(GST_TAG_SETTER(element), - GST_TAG_MERGE_REPLACE_ALL, - tagName.toUtf8().constData(), - tagValue.toInt(), - NULL); - break; - case QVariant::Double: - gst_tag_setter_add_tags(GST_TAG_SETTER(element), - GST_TAG_MERGE_REPLACE_ALL, - tagName.toUtf8().constData(), - tagValue.toDouble(), - NULL); - break; - default: - break; - } - - } - - } - gst_iterator_free(elements); - } + if (m_encodeBin) + QGstUtils::setMetaData(GST_BIN(m_encodeBin), data); } bool QGstreamerCaptureSession::processBusMessage(const QGstreamerMessage &message) @@ -1058,34 +962,16 @@ void QGstreamerCaptureSession::setVolume(qreal volume) void QGstreamerCaptureSession::addProbe(QGstreamerAudioProbeControl* probe) { - QMutexLocker locker(&m_audioProbeMutex); - - if (m_audioProbes.contains(probe)) - return; - - m_audioProbes.append(probe); + Q_ASSERT(!m_audioProbe); + m_audioProbe = probe; + addAudioBufferProbe(); } void QGstreamerCaptureSession::removeProbe(QGstreamerAudioProbeControl* probe) { - QMutexLocker locker(&m_audioProbeMutex); - m_audioProbes.removeOne(probe); -} - -gboolean QGstreamerCaptureSession::padAudioBufferProbe(GstPad *pad, GstBuffer *buffer, gpointer user_data) -{ - Q_UNUSED(pad); - - QGstreamerCaptureSession *session = reinterpret_cast<QGstreamerCaptureSession*>(user_data); - QMutexLocker locker(&session->m_audioProbeMutex); - - if (session->m_audioProbes.isEmpty()) - return TRUE; - - foreach (QGstreamerAudioProbeControl* probe, session->m_audioProbes) - probe->bufferProbed(buffer); - - return TRUE; + Q_ASSERT(m_audioProbe == probe); + removeAudioBufferProbe(); + m_audioProbe = 0; } GstPad *QGstreamerCaptureSession::getAudioProbePad() @@ -1114,26 +1000,25 @@ GstPad *QGstreamerCaptureSession::getAudioProbePad() void QGstreamerCaptureSession::removeAudioBufferProbe() { - if (m_audioBufferProbeId == -1) + if (!m_audioProbe) return; GstPad *pad = getAudioProbePad(); if (pad) { - gst_pad_remove_buffer_probe(pad, m_audioBufferProbeId); - gst_object_unref(G_OBJECT(pad)); + m_audioProbe->removeProbeFromPad(pad); + gst_object_unref(GST_OBJECT(pad)); } - - m_audioBufferProbeId = -1; } void QGstreamerCaptureSession::addAudioBufferProbe() { - Q_ASSERT(m_audioBufferProbeId == -1); + if (!m_audioProbe) + return; GstPad *pad = getAudioProbePad(); if (pad) { - m_audioBufferProbeId = gst_pad_add_buffer_probe(pad, G_CALLBACK(padAudioBufferProbe), this); - gst_object_unref(G_OBJECT(pad)); + m_audioProbe->addProbeToPad(pad); + gst_object_unref(GST_OBJECT(pad)); } } |