2 Copyright (C) 2010 by Juan Carlos Torres <jucato@kdemail.net>
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of
7 the License or (at your option) version 3 or any later version
8 accepted by the membership of KDE e.V. (or its successor appro-
9 ved by the membership of KDE e.V.), which shall act as a proxy
10 defined in Section 14 of version 3 of the license.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see http://www.gnu.org/licenses/.
24 #include <QDBusConnection>
25 #include <QDBusMetaType>
26 #include <QDBusInterface>
34 #include <sys/ioctl.h>
35 #include <linux/videodev2.h>
38 * This section sets up the necessary types and methods
39 * to create a D-Bus connection using Qt.
42 #define HAL_CAM_SHUTTER_UDI "/org/freedesktop/Hal/devices/platform_cam_shutter"
43 #define HAL_CAM_SHUTTER_STATE "button.state.value"
45 Q_DECLARE_METATYPE(Property)
46 Q_DECLARE_METATYPE(QList<Property>)
48 const QDBusArgument & operator<<(QDBusArgument &arg, const Property &change)
51 arg << change.name << change.added << change.removed;
55 const QDBusArgument & operator>>(const QDBusArgument &arg, Property &change)
58 arg >> change.name >> change.added >> change.removed;
65 * Camera class definition
69 char Camera::m_deviceName[15] = "";
71 Camera::Camera(QObject* parent) : QObject(parent)
86 * Open and acquire a file descriptor for a file connected to
87 * the character device representing the camera, usually /dev/video0
89 int Camera::open(char* device)
95 qDebug() << "Device name not specified";
96 return Camera::GenericError;
99 memcpy(m_deviceName, device, sizeof(m_deviceName));
101 if (stat(m_deviceName, &st) == -1)
103 qDebug() << "Cannot identify device:" << m_deviceName;
104 return Camera::GenericError;
107 if (!S_ISCHR(st.st_mode))
109 qDebug() << "No such device: " << m_deviceName;
110 return Camera::GenericError;
113 m_fd = ::open(m_deviceName, O_RDWR | O_NONBLOCK, 0);
117 qDebug() << "Cannot open device: " << m_deviceName;
118 return Camera::GenericError;
128 if (::close(m_fd) == -1)
130 qDebug() << "Cannot close device: " << m_deviceName;
131 return Camera::GenericError;
137 return Camera::NoError;
141 * Initializes the camera by setting up the
142 * cropping rectangle, data format and memory buffers
144 * Based on @ref http://v4l2spec.bytesex.org/spec/capture-example.html
148 struct v4l2_cropcap cropcap;
149 struct v4l2_crop crop;
150 struct v4l2_format fmt;
151 struct v4l2_requestbuffers req;
153 // Set cropping rectangle
154 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
155 if (ioctl(m_fd, VIDIOC_CROPCAP, &cropcap) != -1)
157 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
158 crop.c = cropcap.defrect; // reset to default
160 if (ioctl(m_fd, VIDIOC_S_CROP, &crop) == -1)
162 qDebug() << "Unable to set cropping rectangle";
163 return Camera::GenericError;
168 qDebug() << "Unable to get crop capabilities";
169 return Camera::GenericError;
173 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
174 fmt.fmt.pix.width = 640;
175 fmt.fmt.pix.height = 480;
176 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
177 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
179 if (ioctl(m_fd, VIDIOC_S_FMT, &fmt) == -1)
181 qDebug() << "Unable to set data format";
182 return Camera::GenericError;
185 // Set up memory mapped buffers
187 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
188 req.memory = V4L2_MEMORY_MMAP;
190 if (ioctl(m_fd, VIDIOC_REQBUFS, &req) == -1)
192 qDebug() << "No memory mapping support";
193 return Camera::GenericError;
198 qDebug() << "Insufficient buffer memory on device: " << m_deviceName;
199 return Camera::GenericError;
202 m_buffers = static_cast<buffer*>(calloc(req.count, sizeof(*m_buffers)));
206 qDebug() << "Out of memory";
207 return Camera::GenericError;
210 for (m_numBuffers = 0; m_numBuffers < req.count; ++m_numBuffers)
212 struct v4l2_buffer buf;
214 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
215 buf.memory = V4L2_MEMORY_MMAP;
216 buf.index = m_numBuffers;
218 if (ioctl(m_fd, VIDIOC_QUERYBUF, &buf) == -1)
220 qDebug() << "Unable to query the status of buffer number: " << m_numBuffers;
221 return Camera::GenericError;
224 m_buffers[m_numBuffers].length = buf.length;
225 m_buffers[m_numBuffers].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
226 MAP_SHARED, m_fd, buf.m.offset);
228 if (m_buffers[m_numBuffers].start == MAP_FAILED)
230 qDebug() << "Unable to map memmory";
231 return Camera::GenericError;
235 return Camera::NoError;
242 // Unmap memory mapped buffers
243 if (m_numBuffers > 0)
245 for (i = 0; i < m_numBuffers; ++i)
247 if (munmap(m_buffers[i].start, m_buffers[i].length) == -1)
249 qDebug() << "Unable to unmap memory";
250 return Camera::GenericError;
257 // Free allocated memory
265 return Camera::NoError;
268 int Camera::stream(bool stream)
270 enum v4l2_buf_type type;
272 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
274 // Start or stop streaming
277 if (ioctl(m_fd, VIDIOC_STREAMON, &type) == -1)
279 qDebug() << "Camera::stream: Unable to start streaming";
280 return Camera::GenericError;
285 if (ioctl(m_fd, VIDIOC_STREAMOFF, &type) == -1)
287 qDebug() << "Camera::stream: Unable to stop streaming";
288 return Camera::GenericError;
292 return Camera::NoError;
296 * Strobes the camera flash ONCE only
300 struct v4l2_control ctrl;
302 ctrl.id = V4L2_CID_FLASH_STROBE;
304 if (ioctl(m_fd, VIDIOC_S_CTRL, &ctrl) == -1)
306 qDebug() << "Cannot set flash";
307 return Camera::GenericError;
310 return Camera::NoError;
314 * Sets the LED intensity for strobe (flash) mode only.
317 * code = (intensity - 35)/15
318 * intensity = (code * 15) + 35
320 * Range: 215mA to 500mA
322 * @param intensity Intensity in mA
324 int Camera::setFlashIntensity(int intensity)
326 struct v4l2_control ctrl;
327 int intensityCode = (intensity - 35)/15;
329 // Set intensity to safe limits
330 if (intensityCode > 31)
334 else if (intensityCode < 0)
339 // Set flash intensity
340 ctrl.id = V4L2_CID_FLASH_INTENSITY;
341 ctrl.value = intensityCode;
342 if (ioctl(m_fd, VIDIOC_S_CTRL, &ctrl) == -1)
344 qDebug() << "Cannot set intensity";
345 return Camera::GenericError;
357 return Camera::NoError;
360 int Camera::flashIntensity() const
362 struct v4l2_control ctrl;
364 ctrl.id = V4L2_CID_FLASH_INTENSITY;
366 if (ioctl(m_fd, VIDIOC_G_CTRL, &ctrl) == -1) {
367 qDebug() << "Cannot get intensity";
368 return Camera::GenericError;
371 return 35 + (ctrl.value * 15);
375 * Sets the flash timeout. Works only in strobe (flash) mode.
377 * 1 sec = 1,000 ms = 1,000,000 us (microseconds)
379 * Range: 54,600us to 820,000us (54.6ms to 820ms)
381 * @param timeout Timeout in microseconds
383 int Camera::setTimeout(quint32 timeout)
385 struct v4l2_control ctrl;
387 // Set timeout to safe limits
392 else if (timeout > 820000)
398 ctrl.id = V4L2_CID_FLASH_TIMEOUT;
399 ctrl.value = timeout;
401 if (ioctl(m_fd, VIDIOC_S_CTRL, &ctrl) == -1)
403 qDebug() << "Cannot set timeout";
404 return Camera::GenericError;
407 return Camera::NoError;
410 quint32 Camera::timeout() const
412 struct v4l2_control ctrl;
414 ctrl.id = V4L2_CID_FLASH_TIMEOUT;
416 if (ioctl(m_fd, VIDIOC_G_CTRL, &ctrl) == -1) {
417 qDebug() << "Cannot get timeout";
418 return Camera::GenericError;
425 * Sets up a D-Bus connection to listen for camera shutter
426 * state changes and calls the slot @ref shutterPropertyModified()
428 void Camera::registerDbusWatcher()
430 qDBusRegisterMetaType< Property >();
431 qDBusRegisterMetaType< QList<Property> >();
433 QDBusConnection::systemBus().connect(
436 "org.freedesktop.Hal.Device",
439 SLOT(shutterPropertyModified(int, QList<Property>)));
443 * Checks for the status of the camera shutter using D-Bus and HAL
445 bool Camera::isShutterOpen() const
447 QDBusInterface propertyInterface("org.freedesktop.Hal",
449 "org.freedesktop.Hal.Device",
450 QDBusConnection::systemBus());
452 bool isOpen = propertyInterface.call("GetProperty",
453 HAL_CAM_SHUTTER_STATE).arguments().at(0).toBool();
459 * Called when camera shutter state changes. Checks for the
460 * actual state using @ref isShutterOpen() and emits the
461 * @ref shutterStateChanged() signal
463 void Camera::shutterPropertyModified(int /*numUpdates*/, QList< Property > /*updates*/)
465 bool isOpen = isShutterOpen();
467 emit shutterStateChanged(isOpen);