qnativecamera.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. #include "qnativecamera.h"
  2. #include "videosurface.h"
  3. #include <QPainter>
  4. #include <QTimer>
  5. #include <QDateTime>
  6. #include <QDebug>
  7. QNativeCamera::QNativeCamera(QDeclarativeItem *parent) :
  8. QDeclarativeItem(parent)
  9. ,m_camera(0)
  10. ,m_frontCamera(false)
  11. ,m_cameraImageCapture(0)
  12. ,m_mediaRecorder(0)
  13. ,m_videoSurface(0)
  14. ,m_processedFrameCounter(0)
  15. ,m_incomingFrameCounter(0)
  16. ,m_preview(false)
  17. {
  18. // Important, otherwise the paint method is never called
  19. setFlag(QGraphicsItem::ItemHasNoContents, false);
  20. }
  21. /*!
  22. Destructor.
  23. */
  24. QNativeCamera::~QNativeCamera()
  25. {
  26. destroyResources();
  27. }
  28. /*!
  29. Releases and destroyes all camera resources.
  30. */
  31. void QNativeCamera::destroyResources()
  32. {
  33. if (m_camera) {
  34. m_camera->stop();
  35. }
  36. m_imageFrame = QImage();
  37. if (m_cameraImageCapture) {
  38. delete m_cameraImageCapture;
  39. m_cameraImageCapture = 0;
  40. }
  41. if (m_mediaRecorder) {
  42. delete m_mediaRecorder;
  43. m_mediaRecorder = 0;
  44. }
  45. delete m_camera;
  46. m_camera = 0;
  47. m_incomingFrameCounter = 0;
  48. m_processedFrameCounter = 0;
  49. m_currentDevice = "";
  50. emit currentDeviceChanged();
  51. }
  52. /*!
  53. Returns the list of available devices. Eg. primary camera and front camera.
  54. */
  55. QStringList QNativeCamera::availableDevices() const
  56. {
  57. QStringList list;
  58. foreach (const QByteArray array, QCamera::availableDevices()) {
  59. list << QString(array);
  60. }
  61. return list;
  62. }
  63. /*!
  64. Returns the state camera is currently.
  65. */
  66. QNativeCamera::State QNativeCamera::cameraState() const
  67. {
  68. if (!m_camera) {
  69. return UnloadedState;
  70. }
  71. return State(m_camera->state());
  72. }
  73. /*!
  74. Starts the camera with the given device. The available devices
  75. can be queried with the availableDevices method. Starting will release
  76. and destroy all earlier camera resources before creating new ones.
  77. */
  78. void QNativeCamera::start(const QString &device)
  79. {
  80. qDebug() << "Opening device: " << device;
  81. destroyResources();
  82. m_camera = new QCamera(device.toLatin1(), this);
  83. // Make sure the camera is in loaded state.
  84. //m_camera->load();
  85. m_videoSurface = new VideoSurface(this, m_camera);
  86. m_camera->setViewfinder(m_videoSurface);
  87. // Set the image capturing objects.
  88. m_cameraImageCapture = new QCameraImageCapture(m_camera);
  89. connect(m_cameraImageCapture,SIGNAL(imageAvailable(int,QVideoFrame)), this, SLOT(imageAvailable(int,QVideoFrame)));
  90. connect(m_cameraImageCapture,SIGNAL(imageCaptured(int,QImage)), this, SLOT(imageCaptured(int,QImage)));
  91. connect(m_cameraImageCapture,SIGNAL(imageExposed(int)), this, SLOT(imageExposed(int)));
  92. qDebug() << "QVideoFrame::Format_Jpeg: "<<QString::number(QVideoFrame::Format_Jpeg);
  93. qDebug() << "code buffer format used: "<<QString::number(m_cameraImageCapture->bufferFormat());
  94. //m_cameraImageCapture->setBufferFormat(QVideoFrame::Format_RGB24); // This is equivalent to QImage::Format_RGB888
  95. qDebug() << "code buffer format setted: "<<QString::number(m_cameraImageCapture->bufferFormat());
  96. //m_cameraImageCapture->setCaptureDestination( QCameraImageCapture::CaptureToFile);
  97. if( m_cameraImageCapture->isCaptureDestinationSupported(QCameraImageCapture::CaptureToBuffer) )
  98. qDebug() << "QCameraImageCapture::CaptureToBuffer supported";
  99. else
  100. qDebug() << "QCameraImageCapture::CaptureToBuffer NOT supported";
  101. m_cameraImageCapture->setCaptureDestination( QCameraImageCapture::CaptureToBuffer);
  102. // The following code finds a 16:9 resolution and sets it as capture
  103. // resolution. The view finder image should also change to corresponding
  104. // aspect ratio. On some phones the view finder image does not change
  105. // immediately but after the first image is captured. On some other
  106. // phones the view finder image is correct right a way.
  107. // This code was commented out to prevent sudden change of aspect ratio
  108. // in viewfinder on some phones.
  109. // Find resolution that matches to device's full screen, 16:9
  110. QImageEncoderSettings imageSettings;
  111. imageSettings.setCodec("image/jpeg");
  112. QList<QSize> resolutions = m_cameraImageCapture->supportedResolutions();
  113. //QSize resolution;
  114. qDebug() << "supported resolutions";
  115. foreach (const QSize size, resolutions) {
  116. qDebug() << size.width() << "x" << size.height();
  117. /*float a = size.width() * 1.0f / (size.height() * 1.0f);
  118. float b = 640.0f / 360.0f;
  119. if (qAbs(a - b) <= 0.1f * qMin(qAbs(a), qAbs(b))) {
  120. resolution = size;
  121. break;
  122. }*/
  123. }
  124. QList<QVideoFrame::PixelFormat> bformats = m_cameraImageCapture->supportedBufferFormats();
  125. qDebug() << "QImage::Format_Invalid code: "<<QString::number(QImage::Format_Invalid);
  126. qDebug() << "founded "<<QString::number(bformats.count()) << "buffer formats";
  127. foreach (const QVideoFrame::PixelFormat format, bformats) {
  128. qDebug() << "PixelFormat: " << QString::number(format);
  129. }
  130. if (!m_resolution.isNull()) {
  131. imageSettings.setResolution(m_resolution);
  132. m_cameraImageCapture->setEncodingSettings(imageSettings);
  133. }
  134. // Set the video recording objects.
  135. m_mediaRecorder = new QMediaRecorder(m_camera);
  136. m_camera->load();
  137. // Camera API
  138. connect(m_camera, SIGNAL(locked()), this, SIGNAL(locked()));
  139. connect(m_camera, SIGNAL(lockFailed()), this, SIGNAL(lockFailed()));
  140. //connect(m_camera->focus(), SIGNAL(digitalZoomChanged(qreal)), this, SIGNAL(digitalZoomChanged()));
  141. //connect(m_camera->focus(), SIGNAL(maximumDigitalZoomChanged(qreal)),this, SIGNAL(maximumDigitalZoomChanged()));
  142. connect(m_camera->exposure(), SIGNAL(exposureCompensationChanged(qreal)), this, SIGNAL(exposureCompensationChanged()));
  143. connect(m_camera->exposure(), SIGNAL(isoSensitivityChanged(int)), this, SIGNAL(isoValueChanged()));
  144. connect(m_camera, SIGNAL(stateChanged(QCamera::State)), this, SLOT(cameraStateChanged(QCamera::State)));
  145. connect(m_camera, SIGNAL(stateChanged(QCamera::State)), this, SIGNAL(cameraStateChanged()));
  146. // Image capture API
  147. connect(m_cameraImageCapture, SIGNAL(imageSaved(int, QString)), this, SLOT(handleImageSaved(int, QString)));
  148. // Video recording API
  149. //connect(m_mediaRecorder, SIGNAL(stateChanged(QMediaRecorder::State)), this, SLOT(videoStateChanged(QMediaRecorder::State)));
  150. //connect(m_mediaRecorder, SIGNAL(error(QMediaRecorder::Error)), this, SLOT(handleVideoError(QMediaRecorder::Error)));
  151. // Set the initial capture mode to image capturing.
  152. m_camera->setCaptureMode(QCamera::CaptureStillImage);
  153. // Begin the receiving of view finder frames.
  154. m_camera->start();
  155. m_currentDevice = device;
  156. emit currentDeviceChanged();
  157. if (m_currentDevice == availableDevices()[0]) {
  158. m_frontCamera = false;
  159. }
  160. else {
  161. m_frontCamera = true;
  162. }
  163. emit frontCameraChanged();
  164. }
  165. /*!
  166. Stops the camera and releases all resources.
  167. */
  168. void QNativeCamera::stop()
  169. {
  170. destroyResources();
  171. }
  172. void QNativeCamera::imageAvailable(int id ,QVideoFrame buffer) {
  173. qDebug() << "QNativeCamera captured id:" << QString::number(id);
  174. }
  175. void QNativeCamera::imageCaptured ( int id, const QImage & preview ) {
  176. qDebug() << "QHdrCamera::imageCaptured id:" << QString::number(id);
  177. }
  178. void QNativeCamera::imageExposed(int id){
  179. qDebug() << "QHdrCamera::imageExposed id" << QString::number(id) ;
  180. }
  181. /*!
  182. Returns the current camera in use.
  183. */
  184. QString QNativeCamera::currentDevice() const
  185. {
  186. return m_currentDevice;
  187. }
  188. /*!
  189. Returns true if the secondary camera (front) is in use.
  190. */
  191. bool QNativeCamera::frontCamera() const
  192. {
  193. return m_frontCamera;
  194. }
  195. QSize QNativeCamera::resolution(){
  196. return m_resolution;
  197. }
  198. void QNativeCamera::setResolution(QSize& value){
  199. m_resolution = value;
  200. qDebug() << "Setting resolution to "<<QString::number(value.width())<<"x"<<QString::number(value.height());
  201. }
  202. /*!
  203. Paints the camera view finder frame.
  204. */
  205. void QNativeCamera::paint(QPainter *painter,
  206. const QStyleOptionGraphicsItem *option,
  207. QWidget *widget)
  208. {
  209. Q_UNUSED(option);
  210. Q_UNUSED(widget);
  211. if (!m_imageFrame.isNull()) {
  212. if (m_processedFrameCounter != m_incomingFrameCounter) {
  213. /*if (m_imageAnalyzer) {
  214. m_imageAnalyzer->analyze((unsigned int*)m_imageFrame.bits(),
  215. m_imageFrame.width(),
  216. m_imageFrame.height(),
  217. m_imageFrame.bytesPerLine() / 4,
  218. false);
  219. }*/
  220. m_processedFrameCounter = m_incomingFrameCounter;
  221. }
  222. QPointF upperLeft = boundingRect().center() -
  223. QPointF(m_imageFrame.width() / 2,
  224. m_imageFrame.height() / 2);
  225. // Draw the black borders.
  226. painter->fillRect(0, 0, upperLeft.x(), boundingRect().height(),
  227. Qt::black);
  228. painter->fillRect(upperLeft.x() + m_imageFrame.width(), 0,
  229. boundingRect().right(), boundingRect().bottom(),
  230. Qt::black);
  231. painter->drawImage(QRect(upperLeft.x(), upperLeft.y(),
  232. m_imageFrame.width(),
  233. m_imageFrame.height()), m_imageFrame);
  234. }
  235. else {
  236. painter->fillRect(boundingRect(), Qt::black);
  237. qDebug() << "frame null:" << QString::number(m_incomingFrameCounter);
  238. }
  239. }
  240. /*!
  241. Stores the frame as member to allow it to be processed on paint.
  242. Returns false when there is error, otherwise returns true.
  243. */
  244. bool QNativeCamera::updateFrame(const QVideoFrame &frame)
  245. {
  246. if( m_preview ) {
  247. if (m_processedFrameCounter != m_incomingFrameCounter) {
  248. // Discard frame.
  249. return true;
  250. }
  251. m_incomingFrameCounter++;
  252. m_imageFrame = i_preview.scaled(frame.width(), frame.height()).convertToFormat(QImage::Format_RGB32);
  253. //m_imageFrame = i_preview.convertToFormat(QImage::Format_RGB32);
  254. update();
  255. //qDebug() << "preview:" << QString::number(m_incomingFrameCounter);
  256. } else {
  257. if (!frame.isValid()) {
  258. qDebug() << "CustomCameras::updateFrame: Invalid frame";
  259. return false;
  260. }
  261. if (m_processedFrameCounter != m_incomingFrameCounter) {
  262. // Discard frame.
  263. return true;
  264. }
  265. m_incomingFrameCounter++;
  266. QVideoFrame f = frame;
  267. if (f.map(QAbstractVideoBuffer::ReadOnly)) {
  268. if (m_imageFrame.isNull() || m_imageFrame.width() != f.width() ||
  269. m_imageFrame.height() != f.height()) {
  270. m_imageFrame = QImage(f.width(), f.height(), QImage::Format_RGB32);
  271. }
  272. memcpy(m_imageFrame.bits(), f.bits(), f.mappedBytes());
  273. f.unmap();
  274. update();
  275. }
  276. }
  277. return true;
  278. }
  279. /*!
  280. Capture image with the currently set attributes.
  281. */
  282. void QNativeCamera::captureImage()
  283. {
  284. qDebug() << "QNativeCamera capture";
  285. if (!m_cameraImageCapture) {
  286. return;
  287. }
  288. QString fileName =
  289. QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss.jpg");
  290. m_cameraImageCapture->capture(fileName);
  291. }
  292. /*!
  293. Handles the image saved signal. Emits imageSaved signal delayed, this must be
  294. done in order to be possible to stop the camera from the QML. If
  295. QCameraImageCapture::imageSaved signal was directly connected to the QML and
  296. the camera would be stopped, the applcication would crash as the stop will
  297. destroye the QCameraImageCapture instance.
  298. */
  299. void QNativeCamera::handleImageSaved(int id, const QString &fileName)
  300. {
  301. Q_UNUSED(id);
  302. m_galleryImage = fileName;
  303. i_preview.load(fileName);
  304. QTimer::singleShot(0, this, SLOT(emitImageSavedSignal()));
  305. }
  306. /*!
  307. Emits imageSaved signal.
  308. */
  309. void QNativeCamera::emitImageSavedSignal()
  310. {
  311. emit imageSaved(m_galleryImage);
  312. }
  313. /*!
  314. Gets info about the state change. When the camera is loaded we must emit
  315. the camera API signal in order to QML side to know about the changed camera.
  316. */
  317. void QNativeCamera::cameraStateChanged(QCamera::State state)
  318. {
  319. if (state == QCamera::ActiveState) {
  320. emit digitalZoomChanged();
  321. emit maximumDigitalZoomChanged();
  322. emit exposureCompensationChanged();
  323. emit exposureModeChanged();
  324. emit supportedExposureModesChanged();
  325. emit flashModeChanged();
  326. emit supportedFlashModesChanged();
  327. emit isoValueChanged();
  328. emit supportedIsoValuesChanged();
  329. emit whiteBalanceModeChanged();
  330. emit supportedWhiteBalanceModesChanged();
  331. // emit sharpeningLevelChanged();
  332. // emit contrastChanged();
  333. }
  334. }
  335. qreal QNativeCamera::exposureCompensation(){
  336. return this->m_exposureCompensation;
  337. }
  338. void QNativeCamera::setExposureCompensation(qreal value){
  339. this->m_exposureCompensation=value;
  340. this->m_camera->exposure()->setExposureCompensation(this->m_exposureCompensation);
  341. emit exposureCompensationChanged();
  342. qDebug() << "QNativeCamera: exposure compensation passed:" << QString::number(value);
  343. qDebug() << "QNativeCamera: exposure compensation:" << QString::number(m_camera->exposure()->aperture());
  344. }
  345. bool QNativeCamera::preview(){
  346. return m_preview;
  347. }
  348. void QNativeCamera::setPreview(bool value){
  349. m_preview=value;
  350. }