qtmobility/plugins/multimedia/gstreamer/mediacapture/qgstreamerv4l2input.cpp
changeset 4 90517678cc4f
child 11 06b8e2af4411
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 "qgstreamerv4l2input.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 QGstreamerV4L2Input::QGstreamerV4L2Input(QObject *parent)
       
    69     :QObject(parent)
       
    70 {
       
    71 }
       
    72 
       
    73 QGstreamerV4L2Input::~QGstreamerV4L2Input()
       
    74 {
       
    75 }
       
    76 
       
    77 GstElement *QGstreamerV4L2Input::buildElement()
       
    78 {
       
    79 #ifndef Q_WS_MAEMO_5
       
    80     GstElement *camera = gst_element_factory_make("v4l2src", "camera_source");
       
    81 #else
       
    82     GstElement *camera = gst_element_factory_make("v4l2camsrc", "camera_source");
       
    83 #endif
       
    84     if (camera && !m_device.isEmpty() )
       
    85         g_object_set(G_OBJECT(camera), "device", m_device.constData(), NULL);
       
    86 
       
    87     return camera;
       
    88 }
       
    89 
       
    90 void QGstreamerV4L2Input::setDevice(const QByteArray &newDevice)
       
    91 {
       
    92     if (m_device != newDevice) {
       
    93         m_device = newDevice;
       
    94         updateSupportedResolutions(newDevice);
       
    95     }
       
    96 }
       
    97 
       
    98 void QGstreamerV4L2Input::setDevice(const QString &device)
       
    99 {
       
   100     setDevice(QFile::encodeName(device));
       
   101 }
       
   102 
       
   103 void QGstreamerV4L2Input::updateSupportedResolutions(const QByteArray &device)
       
   104 {
       
   105     m_frameRates.clear();
       
   106     m_resolutions.clear();
       
   107     m_ratesByResolution.clear();
       
   108 
       
   109     QSet<QSize> allResolutions;
       
   110     QSet<int> allFrameRates;
       
   111 
       
   112     QFile f(device);
       
   113 
       
   114     if (!f.open(QFile::ReadOnly))
       
   115         return;
       
   116 
       
   117     int fd = f.handle();
       
   118 
       
   119     //get the list of formats:
       
   120     QList<quint32> supportedFormats;
       
   121 
       
   122     {
       
   123         v4l2_fmtdesc fmt;
       
   124         memset(&fmt, 0, sizeof(v4l2_fmtdesc));
       
   125 
       
   126         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
       
   127         int sanity = 0;
       
   128 
       
   129         for (fmt.index = 0;; fmt.index++) {
       
   130             if (sanity++ > 8)
       
   131                 break;
       
   132             if(  ::ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == -1) {
       
   133                 if(errno == EINVAL)
       
   134                     break;
       
   135             }
       
   136             supportedFormats.append(fmt.pixelformat);
       
   137         }
       
   138     }
       
   139 
       
   140     QList<QSize> commonSizes;
       
   141     commonSizes << QSize(128, 96)
       
   142             <<QSize(160,120)
       
   143             <<QSize(176, 144)
       
   144             <<QSize(320, 240)
       
   145             <<QSize(352, 288)
       
   146             <<QSize(640, 480)
       
   147             <<QSize(1024, 768)
       
   148             <<QSize(1280, 1024)
       
   149             <<QSize(1600, 1200)
       
   150             <<QSize(1920, 1200)
       
   151             <<QSize(2048, 1536)
       
   152             <<QSize(2560, 1600)
       
   153             <<QSize(2580, 1936);
       
   154 
       
   155     QList<int> commonRates;
       
   156     commonRates << 05*1000 << 75*1000  << 10*1000 << 15*1000 << 20*1000
       
   157             << 24*1000 << 25*1000 << 30*1000 << 50*1000 << 60*1000;
       
   158 
       
   159 
       
   160     //get the list of resolutions:
       
   161 
       
   162     foreach (quint32 format, supportedFormats) {
       
   163         struct v4l2_frmsizeenum formatSize;
       
   164         memset(&formatSize, 0, sizeof(formatSize));
       
   165         formatSize.pixel_format = format;
       
   166 
       
   167         QList<QSize> sizeList;
       
   168 
       
   169         if (0) {
       
   170             char formatStr[5];
       
   171             memcpy(formatStr, &format, 4);
       
   172             formatStr[4] = 0;
       
   173             //qDebug() << "trying format" << formatStr;
       
   174         }
       
   175 
       
   176         for (int i=0;;i++) {
       
   177             formatSize.index = i;
       
   178             if (ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &formatSize) < 0)
       
   179                 break;
       
   180 
       
   181             if (formatSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
       
   182                 sizeList.append(QSize(formatSize.discrete.width, formatSize.discrete.height));
       
   183             } else {
       
   184 
       
   185                 foreach (const QSize& candidate, commonSizes) {
       
   186                     if (candidate.width() <= (int)formatSize.stepwise.max_width &&
       
   187                         candidate.height() >= (int)formatSize.stepwise.min_width &&
       
   188                         candidate.width() % formatSize.stepwise.step_width == 0 &&
       
   189                         candidate.height() <= (int)formatSize.stepwise.max_height &&
       
   190                         candidate.height() >= (int)formatSize.stepwise.min_height &&
       
   191                         candidate.height() % formatSize.stepwise.step_height == 0) {
       
   192                         sizeList.append(candidate);
       
   193                     }
       
   194                 }
       
   195 
       
   196                 if (!sizeList.contains(QSize(formatSize.stepwise.min_width, formatSize.stepwise.min_height)))
       
   197                     sizeList.prepend(QSize(formatSize.stepwise.min_width, formatSize.stepwise.min_height));
       
   198 
       
   199                 if (!sizeList.contains(QSize(formatSize.stepwise.max_width, formatSize.stepwise.max_height)))
       
   200                     sizeList.append(QSize(formatSize.stepwise.max_width, formatSize.stepwise.max_height));
       
   201 
       
   202                 break; //stepwise values are returned only for index 0
       
   203             }
       
   204 
       
   205         }
       
   206 
       
   207         //and frameRates for each resolution.
       
   208 
       
   209         foreach (const QSize &s, sizeList) {
       
   210             allResolutions.insert(s);
       
   211 
       
   212             struct v4l2_frmivalenum formatInterval;
       
   213             memset(&formatInterval, 0, sizeof(formatInterval));
       
   214             formatInterval.pixel_format = format;
       
   215             formatInterval.width = s.width();
       
   216             formatInterval.height = s.height();
       
   217 
       
   218             QList<int> frameRates; //in 1/1000 of fps
       
   219 
       
   220             for (int i=0; ; i++) {
       
   221                 formatInterval.index = i;
       
   222 
       
   223                 if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &formatInterval) < 0)
       
   224                     break;
       
   225 
       
   226                 if (formatInterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
       
   227                     //converts seconds to fps*1000
       
   228                     if (formatInterval.discrete.numerator)
       
   229                         frameRates.append(qRound(formatInterval.discrete.denominator*1000.0 / formatInterval.discrete.numerator));
       
   230                 } else {
       
   231                     if (formatInterval.stepwise.min.numerator == 0 ||
       
   232                         formatInterval.stepwise.max.numerator == 0) {
       
   233                         qWarning() << "received invalid frame interval";
       
   234                         break;
       
   235                     }
       
   236 
       
   237 
       
   238                     int minRate = qRound(formatInterval.stepwise.min.denominator*1000.0 /
       
   239                                          formatInterval.stepwise.min.numerator);
       
   240 
       
   241                     int maxRate = qRound(formatInterval.stepwise.max.denominator*1000.0 /
       
   242                                          formatInterval.stepwise.max.numerator);
       
   243 
       
   244 
       
   245                     foreach (int candidate, commonRates) {
       
   246                         if (candidate >= minRate && candidate <= maxRate)
       
   247                             frameRates.append(candidate);
       
   248                     }
       
   249 
       
   250                     if (!frameRates.contains(minRate))
       
   251                         frameRates.prepend(minRate);
       
   252 
       
   253                     if (!frameRates.contains(maxRate))
       
   254                         frameRates.append(maxRate);
       
   255 
       
   256                     break; //stepwise values are returned only for index 0
       
   257                 }
       
   258             }
       
   259             allFrameRates.unite(frameRates.toSet());
       
   260             m_ratesByResolution[s].unite(frameRates.toSet());
       
   261         }
       
   262     }
       
   263 
       
   264     f.close();
       
   265 
       
   266     foreach(int rate, allFrameRates) {
       
   267         m_frameRates.append(rate/1000.0);
       
   268     }
       
   269 
       
   270     qSort(m_frameRates);
       
   271 
       
   272     m_resolutions = allResolutions.toList();
       
   273     qSort(m_resolutions);
       
   274 
       
   275     //qDebug() << "frame rates:" << m_frameRates;
       
   276     //qDebug() << "resolutions:" << m_resolutions;
       
   277 }
       
   278 
       
   279 
       
   280 QList<qreal> QGstreamerV4L2Input::supportedFrameRates(const QSize &frameSize) const
       
   281 {
       
   282     if (frameSize.isEmpty())
       
   283         return m_frameRates;
       
   284     else {
       
   285         QList<qreal> res;
       
   286         foreach(int rate, m_ratesByResolution[frameSize]) {
       
   287             res.append(rate/1000.0);
       
   288         }
       
   289         return res;
       
   290     }
       
   291 }
       
   292 
       
   293 QList<QSize> QGstreamerV4L2Input::supportedResolutions(qreal frameRate) const
       
   294 {
       
   295     Q_UNUSED(frameRate);
       
   296     return m_resolutions;
       
   297 }