qtmobility/plugins/multimedia/gstreamer/mediacapture/qgstreamercameracontrol.cpp
changeset 4 90517678cc4f
parent 1 2b40d63a9c3d
child 5 453da2cfceef
equal deleted inserted replaced
1:2b40d63a9c3d 4:90517678cc4f
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qgstreamercameracontrol.h"
       
    43 
       
    44 #include <QtCore/qdebug.h>
       
    45 #include <QtCore/qfile.h>
       
    46 
       
    47 #include <linux/types.h>
       
    48 #include <sys/time.h>
       
    49 #include <sys/ioctl.h>
       
    50 #include <sys/poll.h>
       
    51 #include <unistd.h>
       
    52 #include <fcntl.h>
       
    53 #include <errno.h>
       
    54 #include <string.h>
       
    55 #include <stdlib.h>
       
    56 #include <sys/mman.h>
       
    57 #include <linux/videodev2.h>
       
    58 
       
    59 QT_BEGIN_NAMESPACE
       
    60 static inline uint qHash(const QSize& key) { return uint(key.width()*256+key.height()); }
       
    61 
       
    62 static bool operator<(const QSize &s1, const QSize s2)
       
    63 {
       
    64     return s1.width()*s1.height() < s2.width()*s2.height();
       
    65 }
       
    66 QT_END_NAMESPACE
       
    67 
       
    68 QGstreamerCameraControl::QGstreamerCameraControl(QGstreamerCaptureSession *session)
       
    69     :QCameraControl(session), m_captureMode(QCamera::CaptureStillImage), m_session(session), m_state(QCamera::StoppedState)
       
    70 {
       
    71     connect(m_session, SIGNAL(stateChanged(QGstreamerCaptureSession::State)),
       
    72             this, SLOT(updateState()));
       
    73 }
       
    74 
       
    75 QGstreamerCameraControl::~QGstreamerCameraControl()
       
    76 {
       
    77 }
       
    78 
       
    79 GstElement *QGstreamerCameraControl::buildElement()
       
    80 {
       
    81     GstElement *camera = gst_element_factory_make("v4l2src", "camera_source");
       
    82 
       
    83     if (camera && !m_device.isEmpty() )
       
    84         g_object_set(G_OBJECT(camera), "device", m_device.constData(), NULL);
       
    85 
       
    86     return camera;
       
    87 }
       
    88 
       
    89 void QGstreamerCameraControl::start()
       
    90 {
       
    91     if (m_session->state() == QGstreamerCaptureSession::StoppedState)
       
    92         m_session->setState(QGstreamerCaptureSession::PreviewState);
       
    93 }
       
    94 
       
    95 void QGstreamerCameraControl::stop()
       
    96 {
       
    97     m_session->setState(QGstreamerCaptureSession::StoppedState);
       
    98 }
       
    99 
       
   100 void QGstreamerCameraControl::setDevice(const QString &device)
       
   101 {
       
   102     QByteArray newDevice = device.toLocal8Bit();
       
   103 
       
   104     if (m_device != newDevice) {
       
   105         m_device = newDevice;
       
   106         updateSupportedResolutions(device);
       
   107     }
       
   108 }
       
   109 
       
   110 QCamera::State QGstreamerCameraControl::state() const
       
   111 {
       
   112     if (m_session->state() == QGstreamerCaptureSession::StoppedState)
       
   113         return QCamera::StoppedState;
       
   114     else
       
   115         return QCamera::ActiveState;
       
   116 }
       
   117 
       
   118 void QGstreamerCameraControl::updateState()
       
   119 {
       
   120     QCamera::State newState = state();
       
   121     if (m_state != newState) {
       
   122         m_state = newState;
       
   123         emit stateChanged(m_state);
       
   124     }
       
   125 }
       
   126 
       
   127 
       
   128 void QGstreamerCameraControl::updateSupportedResolutions(const QString &device)
       
   129 {
       
   130     m_frameRates.clear();
       
   131     m_resolutions.clear();
       
   132     m_ratesByResolution.clear();
       
   133 
       
   134     QSet<QSize> allResolutions;
       
   135     QSet<int> allFrameRates;
       
   136 
       
   137     QFile f(device);
       
   138 
       
   139     if (!f.open(QFile::ReadOnly))
       
   140         return;
       
   141 
       
   142     int fd = f.handle();
       
   143 
       
   144     //get the list of formats:
       
   145     QList<quint32> supportedFormats;
       
   146 
       
   147     {
       
   148         v4l2_fmtdesc fmt;
       
   149         memset(&fmt, 0, sizeof(v4l2_fmtdesc));
       
   150 
       
   151         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
       
   152         int sanity = 0;
       
   153 
       
   154         for (fmt.index = 0;; fmt.index++) {
       
   155             if (sanity++ > 8)
       
   156                 break;
       
   157             if(  ::ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == -1) {
       
   158                 if(errno == EINVAL)
       
   159                     break;
       
   160             }
       
   161             supportedFormats.append(fmt.pixelformat);
       
   162         }
       
   163     }
       
   164 
       
   165     QList<QSize> commonSizes;
       
   166     commonSizes << QSize(128, 96)
       
   167             <<QSize(160,120)
       
   168             <<QSize(176, 144)
       
   169             <<QSize(320, 240)
       
   170             <<QSize(352, 288)
       
   171             <<QSize(640, 480)
       
   172             <<QSize(1024, 768)
       
   173             <<QSize(1280, 1024)
       
   174             <<QSize(1600, 1200)
       
   175             <<QSize(1920, 1200)
       
   176             <<QSize(2048, 1536)
       
   177             <<QSize(2560, 1600)
       
   178             <<QSize(2580, 1936);
       
   179 
       
   180     QList<int> commonRates;
       
   181     commonRates << 05*1000 << 75*1000  << 10*1000 << 15*1000 << 20*1000
       
   182             << 24*1000 << 25*1000 << 30*1000 << 50*1000 << 60*1000;
       
   183 
       
   184 
       
   185     //get the list of resolutions:
       
   186 
       
   187     foreach (quint32 format, supportedFormats) {
       
   188         struct v4l2_frmsizeenum formatSize;
       
   189         memset(&formatSize, 0, sizeof(formatSize));
       
   190         formatSize.pixel_format = format;
       
   191 
       
   192         QList<QSize> sizeList;
       
   193 
       
   194         if (0) {
       
   195             char formatStr[5];
       
   196             memcpy(formatStr, &format, 4);
       
   197             formatStr[4] = 0;
       
   198             //qDebug() << "trying format" << formatStr;
       
   199         }
       
   200 
       
   201         for (int i=0;;i++) {
       
   202             formatSize.index = i;
       
   203             if (ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &formatSize) < 0)
       
   204                 break;
       
   205 
       
   206             if (formatSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
       
   207                 sizeList.append(QSize(formatSize.discrete.width, formatSize.discrete.height));
       
   208             } else {
       
   209 
       
   210                 foreach (const QSize& candidate, commonSizes) {
       
   211                     if (candidate.width() <= (int)formatSize.stepwise.max_width &&
       
   212                         candidate.height() >= (int)formatSize.stepwise.min_width &&
       
   213                         candidate.width() % formatSize.stepwise.step_width == 0 &&
       
   214                         candidate.height() <= (int)formatSize.stepwise.max_height &&
       
   215                         candidate.height() >= (int)formatSize.stepwise.min_height &&
       
   216                         candidate.height() % formatSize.stepwise.step_height == 0) {
       
   217                         sizeList.append(candidate);
       
   218                     }
       
   219                 }
       
   220 
       
   221                 if (!sizeList.contains(QSize(formatSize.stepwise.min_width, formatSize.stepwise.min_height)))
       
   222                     sizeList.prepend(QSize(formatSize.stepwise.min_width, formatSize.stepwise.min_height));
       
   223 
       
   224                 if (!sizeList.contains(QSize(formatSize.stepwise.max_width, formatSize.stepwise.max_height)))
       
   225                     sizeList.append(QSize(formatSize.stepwise.max_width, formatSize.stepwise.max_height));
       
   226 
       
   227                 break; //stepwise values are returned only for index 0
       
   228             }
       
   229 
       
   230         }
       
   231 
       
   232         //and frameRates for each resolution.
       
   233 
       
   234         foreach (const QSize &s, sizeList) {
       
   235             allResolutions.insert(s);
       
   236 
       
   237             struct v4l2_frmivalenum formatInterval;
       
   238             memset(&formatInterval, 0, sizeof(formatInterval));
       
   239             formatInterval.pixel_format = format;
       
   240             formatInterval.width = s.width();
       
   241             formatInterval.height = s.height();
       
   242 
       
   243             QList<int> frameRates; //in 1/1000 of fps
       
   244 
       
   245             for (int i=0; ; i++) {
       
   246                 formatInterval.index = i;
       
   247 
       
   248                 if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &formatInterval) < 0)
       
   249                     break;
       
   250 
       
   251                 if (formatInterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
       
   252                     //converts seconds to fps*1000
       
   253                     if (formatInterval.discrete.numerator)
       
   254                         frameRates.append(qRound(formatInterval.discrete.denominator*1000.0 / formatInterval.discrete.numerator));
       
   255                 } else {
       
   256                     if (formatInterval.stepwise.min.numerator == 0 ||
       
   257                         formatInterval.stepwise.max.numerator == 0) {
       
   258                         qWarning() << "received invalid frame interval";
       
   259                         break;
       
   260                     }
       
   261 
       
   262 
       
   263                     int minRate = qRound(formatInterval.stepwise.min.denominator*1000.0 /
       
   264                                          formatInterval.stepwise.min.numerator);
       
   265 
       
   266                     int maxRate = qRound(formatInterval.stepwise.max.denominator*1000.0 /
       
   267                                          formatInterval.stepwise.max.numerator);
       
   268 
       
   269 
       
   270                     foreach (int candidate, commonRates) {
       
   271                         if (candidate >= minRate && candidate <= maxRate)
       
   272                             frameRates.append(candidate);
       
   273                     }
       
   274 
       
   275                     if (!frameRates.contains(minRate))
       
   276                         frameRates.prepend(minRate);
       
   277 
       
   278                     if (!frameRates.contains(maxRate))
       
   279                         frameRates.append(maxRate);
       
   280 
       
   281                     break; //stepwise values are returned only for index 0
       
   282                 }
       
   283             }
       
   284             allFrameRates.unite(frameRates.toSet());
       
   285             m_ratesByResolution[s].unite(frameRates.toSet());
       
   286         }
       
   287     }
       
   288 
       
   289     f.close();
       
   290 
       
   291     foreach(int rate, allFrameRates) {
       
   292         m_frameRates.append(rate/1000.0);
       
   293     }
       
   294 
       
   295     qSort(m_frameRates);
       
   296 
       
   297     m_resolutions = allResolutions.toList();
       
   298     qSort(m_resolutions);
       
   299 
       
   300     //qDebug() << "frame rates:" << m_frameRates;
       
   301     //qDebug() << "resolutions:" << m_resolutions;
       
   302 }
       
   303 
       
   304 
       
   305 QList<qreal> QGstreamerCameraControl::supportedFrameRates(const QSize &frameSize) const
       
   306 {
       
   307     if (frameSize.isEmpty())
       
   308         return m_frameRates;
       
   309     else {
       
   310         QList<qreal> res;
       
   311         foreach(int rate, m_ratesByResolution[frameSize]) {
       
   312             res.append(rate/1000.0);
       
   313         }
       
   314         return res;
       
   315     }
       
   316 }
       
   317 
       
   318 QList<QSize> QGstreamerCameraControl::supportedResolutions(qreal frameRate) const
       
   319 {
       
   320     Q_UNUSED(frameRate);
       
   321     return m_resolutions;
       
   322 }