MeeGo 1.2 Harmattan Developer Documentation Develop for the Nokia N9

cameraexample.cpp Example File

demos/mobile/qcamera/cameraexample.cpp
 /****************************************************************************
 **
 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
 ** This file is part of the demonstration applications of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:BSD$
 ** You may use this file under the terms of the BSD license as follows:
 **
 ** "Redistribution and use in source and binary forms, with or without
 ** modification, are permitted provided that the following conditions are
 ** met:
 **   * Redistributions of source code must retain the above copyright
 **     notice, this list of conditions and the following disclaimer.
 **   * Redistributions in binary form must reproduce the above copyright
 **     notice, this list of conditions and the following disclaimer in
 **     the documentation and/or other materials provided with the
 **     distribution.
 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
 **     the names of its contributors may be used to endorse or promote
 **     products derived from this software without specific prior written
 **     permission.
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/

 #include "cameraexample.h"
 #include "messagehandling.h"
 #include "contactsdlg.h"
 #include "button.h"
 #include "businesscardhandling.h"
 #include <QDebug>

 /*****************************************************************************
 * MyVideoSurface
 */
 MyVideoSurface::MyVideoSurface(QWidget* widget, VideoIF* target, QObject* parent)
     : QAbstractVideoSurface(parent)
 {
     m_targetWidget = widget;
     m_target = target;
     m_imageFormat = QImage::Format_Invalid;
 }

 MyVideoSurface::~MyVideoSurface()
 {
 }

 bool MyVideoSurface::start(const QVideoSurfaceFormat &format)
 {
     m_videoFormat = format;
     const QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat());
     const QSize size = format.frameSize();

     if (imageFormat != QImage::Format_Invalid && !size.isEmpty()) {
         m_imageFormat = imageFormat;
         QAbstractVideoSurface::start(format);
         return true;
     } else {
         return false;
     }
 }

 bool MyVideoSurface::present(const QVideoFrame &frame)
 {
     m_frame = frame;
     if (surfaceFormat().pixelFormat() != m_frame.pixelFormat() ||
             surfaceFormat().frameSize() != m_frame.size()) {
         stop();
         return false;
     } else {
         m_target->updateVideo();
         return true;
     }
 }

 void MyVideoSurface::paint(QPainter *painter)
  {
      if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) {
          QImage image(
                  m_frame.bits(),
                  m_frame.width(),
                  m_frame.height(),
                  m_frame.bytesPerLine(),
                  m_imageFormat);

          QRect r = m_targetWidget->rect();
          QPoint centerPic((qAbs(r.size().width() - image.size().width())) / 2, (qAbs(
              r.size().height() - image.size().height())) / 2);

          if (!image.isNull()) {
             painter->drawImage(centerPic,image);
          }

          m_frame.unmap();
      }
  }

 QList<QVideoFrame::PixelFormat> MyVideoSurface::supportedPixelFormats(
             QAbstractVideoBuffer::HandleType handleType) const
 {
     if (handleType == QAbstractVideoBuffer::NoHandle) {
         return QList<QVideoFrame::PixelFormat>()
                 << QVideoFrame::Format_RGB32
                 << QVideoFrame::Format_ARGB32
                 << QVideoFrame::Format_ARGB32_Premultiplied
                 << QVideoFrame::Format_RGB565
                 << QVideoFrame::Format_RGB555;
     } else {
         return QList<QVideoFrame::PixelFormat>();
     }
 }

 /*****************************************************************************
 * CameraExample
 */
 CameraExample::CameraExample(QWidget *parent) :
     QMainWindow(parent)
 {
     setWindowTitle("QCameraExample");

     // Opitimizations for screen update and drawing qwidget
     setAutoFillBackground(false);

     // Prevent to screensaver to activate
     m_systemScreenSaver = new QSystemScreenSaver(this);
     m_systemScreenSaver->setScreenSaverInhibit();

     m_myVideoSurface = 0;
     pictureCaptured = false;
     showViewFinder = false;
     m_focusing = false;

     // MMS handling
     m_message = new Message(this);
     QObject::connect(m_message, SIGNAL(messageStateChanged(int)), this, SLOT(messageStateChanged(int)));
     QObject::connect(m_message, SIGNAL(messageReceived(QString,QString,QPixmap)), this, SLOT(messageReceived(QString,QString,QPixmap)));

     // Business card handling (Contact's avatar picture)
     m_businessCardHandling = new BusinessCardHandling(this);

     // Black background
     QPalette palette = this->palette();
     palette.setColor(QPalette::Background, Qt::black);
     setPalette(palette);

     // Main widget & layout
     QWidget* mainWidget = new QWidget(this);
     mainWidget->setPalette(palette);

     QHBoxLayout* hboxl = new QHBoxLayout;
     hboxl->setSpacing(0);
     hboxl->setMargin(0);

     // UI stack
     m_stackedWidget = new QStackedWidget();
     m_stackedWidget->setPalette(palette);

     // First widget to stack
     m_videoWidget = new QWidget();
     m_videoWidget->setPalette(palette);
     m_stackedWidget->addWidget(m_videoWidget);

     // Second widget to stack
     QWidget* secondWidget = new QWidget(this);
     secondWidget->setPalette(palette);
     m_stackedWidget->addWidget(secondWidget);
     m_stackedWidget->setCurrentIndex(0);

     hboxl->addWidget(m_stackedWidget);

     // Buttons
     QSize iconSize(80, 80);
     QVBoxLayout* vboxl = new QVBoxLayout;
     vboxl->setSpacing(0);
     vboxl->setMargin(0);

     // Exit button
     m_exit = new Button(this);
     QObject::connect(m_exit, SIGNAL(pressed()), qApp, SLOT(quit()));
     QPixmap p = QPixmap(":/icons/exit.png");
     m_exit->setPixmap(p.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
     vboxl->addWidget(m_exit);
     vboxl->setAlignment(m_exit, Qt::AlignHCenter | Qt::AlignTop);

     // Camera button
     m_cameraBtn = new Button(this);
     QObject::connect(m_cameraBtn, SIGNAL(pressed()), this, SLOT(searchAndLock()));
     p = QPixmap(":/icons/camera.png");
     m_cameraBtn->setPixmap(p.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
     vboxl->addWidget(m_cameraBtn);
     vboxl->setAlignment(m_cameraBtn, Qt::AlignCenter);

     // Send MMS button
     m_mms = new Button(this);
     QObject::connect(m_mms, SIGNAL(pressed()), this, SLOT(openContactsDlg()));
     p = QPixmap(":/icons/mms.png");
     m_mms->setPixmap(p.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
     vboxl->addWidget(m_mms);
     vboxl->setAlignment(m_mms, Qt::AlignHCenter | Qt::AlignBottom);
 #ifndef MESSAGING_ENABLED
     m_mms->disableBtn(true);
     m_mms->setEnabled(false);
 #endif

     hboxl->addLayout(vboxl);
     mainWidget->setLayout(hboxl);

     setCentralWidget(mainWidget);

     // Enable camera after 1s, so that the application is started
     // and widget is created to landscape orientation
     QTimer::singleShot(1000,this,SLOT(enableCamera()));
 }

 CameraExample::~CameraExample()
 {
 if (m_myVideoSurface)
     m_myVideoSurface->stop();
     m_camera->stop();
     delete m_stackedWidget;
     delete m_stillImageCapture;
     delete m_camera;
 }

 void CameraExample::enableCamera()
 {
     m_camera = new QCamera();
     m_camera->setCaptureMode(QCamera::CaptureStillImage);
     connect(m_camera, SIGNAL(error(QCamera::Error)), this, SLOT(error(QCamera::Error)));
     connect(m_camera, SIGNAL(lockStatusChanged(QCamera::LockStatus,QCamera::LockChangeReason)), this, SLOT(lockStatusChanged(QCamera::LockStatus,QCamera::LockChangeReason)));

     // Own video output drawing that shows camera view finder pictures
     QMediaService* ms = m_camera->service();
     QVideoRendererControl* vrc = ms->requestControl<QVideoRendererControl*>();
     m_myVideoSurface = new MyVideoSurface(this,this,this);
     vrc->setSurface(m_myVideoSurface);
     // Image capturer
     m_stillImageCapture = new QCameraImageCapture(m_camera);
     connect(m_stillImageCapture, SIGNAL(imageCaptured(int,QImage)), this, SLOT(imageCaptured(int,QImage)));

     // Start camera
     if (m_camera->state() == QCamera::ActiveState) {
         m_camera->stop();
     }
     m_videoWidget->show();
     m_camera->start();
     showViewFinder = true;
 }

 void CameraExample::mousePressEvent(QMouseEvent *event)
 {
     QMainWindow::mousePressEvent(event);

     if (pictureCaptured) {
         // Starting view finder
         pictureCaptured = false;
         m_stackedWidget->setCurrentIndex(0);
         if (m_myVideoSurface) {
             showViewFinder = true;
         }
     }
 }

 void CameraExample::searchAndLock()
 {
     m_focusing = false;
     m_focusMessage.clear();

     if (pictureCaptured) {
         // Starting view finder again
         pictureCaptured = false;
         m_stackedWidget->setCurrentIndex(0);
         if (m_myVideoSurface) {
             showViewFinder = true;
         }
     }
     else {
         // Search and lock picture (=focus)
         if (m_camera->supportedLocks() & QCamera::LockFocus) {
             m_focusing = true;
             m_focusMessage = "Focusing...";
             m_camera->searchAndLock(QCamera::LockFocus);
         } else {
         // No focus functionality, take picture right away
             captureImage();
         }
     }
 }

 void CameraExample::lockStatusChanged(QCamera::LockStatus status, QCamera::LockChangeReason reason)
 {
     if (status == QCamera::Locked) {
         if (reason == QCamera::LockAcquired) {
             // Focus locked
             m_focusMessage.clear();
             m_focusing = false;
             // Capture new image
             captureImage();
             // Unlock camera
             m_camera->unlock();
         } else {
             if (m_focusing)
                 m_focusMessage = "No focus, try again";
         }
     } else if (status == QCamera::Unlocked && m_focusing) {
         m_focusMessage = "No focus, try again";
     }
 }

 void CameraExample::captureImage()
 {
     if (pictureCaptured) {
         // Starting view finder again
         pictureCaptured = false;
         m_stackedWidget->setCurrentIndex(0);
         showViewFinder = true;
     }
     else {
         // Capturing image
         showViewFinder = false;
         // Get picture location where to store captured images
         QString path(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
         QDir dir(path);

         // Get next filename
         QStringList files = dir.entryList(QStringList() << "camera_*.jpg");
         int lastImage = 0;
         foreach ( QString fileName, files ) {
                 int imgNumber = fileName.mid(7, fileName.size() - 11).toInt();
                 lastImage = qMax(lastImage, imgNumber);
             }
         // Capture image
         if (m_stillImageCapture->isReadyForCapture()) {
             m_imageName = QString("camera_%1.jpg").arg(lastImage+1);
             m_stillImageCapture->capture(m_imageName);
         }
     }
 }

 void CameraExample::imageCaptured(int id, const QImage &preview)
 {
     showViewFinder = false;
     m_focusing = false;

     // Image captured, show it to the user
     m_stackedWidget->setCurrentIndex(1);

     // Get picture location
     QString path(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
     m_imageName.prepend(path + "/");

     m_capturedImage = preview;

     // Set suitable size to the image
     QSize s = m_videoWidget->size();
     s = s - QSize(20, 20);
     m_capturedImage = m_capturedImage.scaled(s, Qt::KeepAspectRatio, Qt::SmoothTransformation);

     pictureCaptured = true;
     update();
 }

 void CameraExample::error(QCamera::Error e)
 {
     switch (e) {
     case QCamera::NoError:
     {
         break;
     }
     case QCamera::CameraError:
     {
         QMessageBox::warning(this, "QCameraExample", "General Camera error");
         break;
     }
     case QCamera::InvalidRequestError:
     {
         QMessageBox::warning(this, "QCameraExample", "Camera invalid request error");
         break;
     }
     case QCamera::ServiceMissingError:
     {
         QMessageBox::warning(this, "QCameraExample", "Camera service missing error");
         break;
     }
     case QCamera::NotSupportedFeatureError :
     {
         QMessageBox::warning(this, "QCameraExample", "Camera not supported error");
         break;
     }
     };
 }

 void CameraExample::openContactsDlg()
 {
     // Open dialog for showing contacts
     if (!m_contactsDialog) {

         if (m_capturedImage.isNull()) {
             QMessageBox::information(this, "QCameraExample", "Take picture first");
             return;
         }

         // Show dialog
         m_contactsDialog = new ContactsDialog(this);
         QObject::connect(m_contactsDialog, SIGNAL(contactSelected(QString)),
         this, SLOT(contactSelected(QString)));
         m_contactsDialog->exec();
         QObject::disconnect(m_contactsDialog, SIGNAL(contactSelected(QString)),
         this, SLOT(contactSelected(QString)));

         delete m_contactsDialog;
         m_contactsDialog = 0;
     }
 }

 void CameraExample::contactSelected(QString phoneNumber)
 {
     m_phoneNumber = phoneNumber;
     QTimer::singleShot(1000,this,SLOT(sendMMS()));
 }

 void CameraExample::sendMMS()
 {
 #ifdef MESSAGING_ENABLED
     m_message->sendMMS(m_imageName, m_phoneNumber);
 #endif
 }

 void CameraExample::messageStateChanged(int /*error*/)
 {
 }

 void CameraExample::updateVideo()
 {
     if (showViewFinder) {
         repaint();
     }
 }

 void CameraExample::paintEvent(QPaintEvent *event)
 {
     //QMainWindow::paintEvent(event);

     QPainter painter(this);
     QRect r = this->rect();

     QFont font = painter.font();
     font.setPixelSize(20);
     painter.setFont(font);
     painter.setPen(Qt::white);

     if (showViewFinder && m_myVideoSurface && m_myVideoSurface->isActive()) {
         // Show view finder
         m_myVideoSurface->paint(&painter);

         // Paint focus message
         if (!m_focusMessage.isEmpty())
             painter.drawText(r, Qt::AlignCenter, m_focusMessage);

     } else {
         // Draw black
         painter.fillRect(event->rect(), palette().background());
         // Show captured image
         if (pictureCaptured) {
             // Paint captured image
             QPoint centerPic((qAbs(r.size().width() - m_capturedImage.size().width())) / 2, (qAbs(
                 r.size().height() - m_capturedImage.size().height())) / 2);

             painter.drawImage(centerPic, m_capturedImage);

             // Paint filename
             painter.drawText(r, Qt::AlignBottom | Qt::AlignCenter, m_imageName);
         }
     }

 }

 void CameraExample::messageReceived(QString phoneNumber, QString filename, QPixmap pixmap)
 {
 #ifdef MESSAGING_ENABLED
     // MMS message received
     // Check that is came from some of our contact
     QContact contact;
     if (m_businessCardHandling->findContact(phoneNumber, contact)) {
         // Ask from user to store it as sender avatar picture into contacts
         if (QMessageBox::question(
             this,
             "QCameraExample",
             QString(
                 "MMS picture message received from %1. Do you want to store it as sender avatar picture?").arg(
                 contact.displayLabel()), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {

             m_businessCardHandling->storeAvatarToContact(phoneNumber, filename, pixmap);
         }
     }
 #endif
 }