2 #include "qtcammode_p.h"
3 #include "qtcamdevice_p.h"
4 #include "qtcamdevice.h"
6 #include "qtcamgstreamermessagehandler.h"
7 #include "qtcamgstreamermessagelistener.h"
8 #include <gst/video/video.h>
11 #define PREVIEW_CAPS "video/x-raw-rgb, width = (int) %1, height = (int) %2, bpp = (int) 32, depth = (int) 24, red_mask = (int) 65280, green_mask = (int) 16711680, blue_mask = (int) -16777216"
13 #define CAPS "video/x-raw-yuv, width = (int) %1, height = (int) %2, framerate = (fraction) %3/%4"
15 class PreviewImageHandler : public QtCamGStreamerMessageHandler {
17 PreviewImageHandler(QtCamMode *m, QObject *parent = 0) :
18 QtCamGStreamerMessageHandler("preview-image", parent) {
22 virtual void handleMessage(GstMessage *message) {
23 const GstStructure *s = gst_message_get_structure(message);
28 const char *file = gst_structure_get_string(s, "location");
33 const GValue *val = gst_structure_get_value(s, "buffer");
38 GstBuffer *buffer = gst_value_get_buffer(val);
45 if (!gst_video_format_parse_caps(buffer->caps, &fmt, &width, &height)) {
49 if (fmt != GST_VIDEO_FORMAT_BGRx || width <= 0 || height <= 0) {
53 QImage image(buffer->data, width, height, QImage::Format_RGB32);
55 // We need to copy because GStreamer will free the buffer after we return
56 // and since QImage doesn't copythe data by default we will end up with garbage.
57 // TODO: consider a QImage subclass that takes a GstBuffer reference
58 QImage cp = image.copy();
60 QString fileName = QString::fromUtf8(file);
62 QMetaObject::invokeMethod(mode, "previewAvailable",
63 Q_ARG(QImage, cp), Q_ARG(QString, fileName));
69 class DoneHandler : public QtCamGStreamerMessageHandler {
71 DoneHandler(QtCamMode *m, const char *done, QObject *parent = 0) :
72 QtCamGStreamerMessageHandler(done, parent) {
76 virtual void handleMessage(GstMessage *message) {
77 const GstStructure *s = gst_message_get_structure(message);
78 if (gst_structure_has_field(s, "filename")) {
79 const char *str = gst_structure_get_string(s, "filename");
81 fileName = QString::fromUtf8(str);
85 QMetaObject::invokeMethod(mode, "saved", Q_ARG(QString, fileName));
92 QtCamMode::QtCamMode(QtCamModePrivate *d, const char *mode, const char *done, QObject *parent) :
93 QObject(parent), d_ptr(d) {
95 d_ptr->id = d_ptr->modeId(mode);
96 d_ptr->previewImageHandler = new PreviewImageHandler(this, this);
97 d_ptr->doneHandler = new DoneHandler(this, done, this);
100 QtCamMode::~QtCamMode() {
101 delete d_ptr; d_ptr = 0;
104 void QtCamMode::activate() {
105 if (!d_ptr->dev->cameraBin) {
109 if (d_ptr->dev->active == this) {
113 if (d_ptr->dev->active) {
114 d_ptr->dev->active->deactivate();
117 d_ptr->dev->active = this;
119 // TODO: check that we can actually do it. Perhaps the pipeline is busy.
121 g_object_set(d_ptr->dev->cameraBin, "mode", d_ptr->id, NULL);
123 d_ptr->dev->listener->addHandler(d_ptr->previewImageHandler);
124 d_ptr->dev->listener->addHandler(d_ptr->doneHandler);
130 QMetaObject::invokeMethod(d_ptr->dev->q_ptr, "modeChanged");
132 emit activeChanged();
135 void QtCamMode::deactivate() {
136 if (d_ptr->dev->active != this) {
140 d_ptr->dev->listener->removeHandler(d_ptr->previewImageHandler);
141 d_ptr->dev->listener->removeHandler(d_ptr->doneHandler);
143 d_ptr->previewImageHandler->setParent(this);
144 d_ptr->doneHandler->setParent(this);
148 d_ptr->dev->active = 0;
150 QMetaObject::invokeMethod(d_ptr->dev->q_ptr, "modeChanged");
152 emit activeChanged();
155 bool QtCamMode::canCapture() {
156 return d_ptr->dev->cameraBin && isActive() && d_ptr->dev->q_ptr->isRunning();
159 bool QtCamMode::isActive() {
160 return d_ptr->dev->active == this;
163 void QtCamMode::setCaps(const char *property, const QSize& resolution,
164 const QPair<int, int> frameRate) {
166 if (!d_ptr->dev->cameraBin) {
170 // TODO: allow proceeding without specifying a frame rate (maybe we can calculate it ?)
171 if (frameRate.first <= 0 || frameRate.second <= 0) {
175 if (resolution.width() <= 0 || resolution.height() <= 0) {
179 QString capsString = QString(CAPS)
180 .arg(resolution.width()).arg(resolution.height())
181 .arg(frameRate.first).arg(frameRate.second);
183 GstCaps *caps = gst_caps_from_string(capsString.toAscii());
185 g_object_set(d_ptr->dev->cameraBin, property, caps, NULL);
187 gst_caps_unref(caps);
190 void QtCamMode::setPreviewSize(const QSize& size) {
191 if (!d_ptr->dev->cameraBin) {
195 if (size.width() <= 0 && size.height() <= 0) {
196 g_object_set(d_ptr->dev->cameraBin, "preview-caps", NULL, "post-previews", FALSE, NULL);
199 QString preview = QString(PREVIEW_CAPS).arg(size.width()).arg(size.height());
201 GstCaps *caps = gst_caps_from_string(preview.toAscii());
203 g_object_set(d_ptr->dev->cameraBin, "preview-caps", caps, "post-previews", TRUE, NULL);
205 gst_caps_unref(caps);
209 void QtCamMode::setFileName(const QString& fileName) {
210 d_ptr->doneHandler->fileName = fileName;