From 724bb4ef15cd02a360e49de9c67847a19d5ca832 Mon Sep 17 00:00:00 2001 From: mickeyl Date: Sat, 19 Apr 2003 00:40:00 +0000 Subject: - fix shutter handling - include manually overriding xflip and yflip - prepare video capturing mode - use caption to indicate current settings --- diff --git a/noncore/multimedia/camera/camera.pro b/noncore/multimedia/camera/camera.pro index ffd5f37..8aedcea 100644 --- a/noncore/multimedia/camera/camera.pro +++ b/noncore/multimedia/camera/camera.pro @@ -4,11 +4,13 @@ DESTDIR = $(OPIEDIR)/bin TEMPLATE = app CONFIG = qt warn_on debug -HEADERS = zcameraio.h \ +HEADERS = imageio.h \ + zcameraio.h \ previewwidget.h \ mainwindow.h -SOURCES = zcameraio.cpp \ +SOURCES = imageio.cpp \ + zcameraio.cpp \ previewwidget.cpp \ mainwindow.cpp \ main.cpp diff --git a/noncore/multimedia/camera/imageio.cpp b/noncore/multimedia/camera/imageio.cpp new file mode 100644 index 0000000..f8f5dd0 --- a/dev/null +++ b/noncore/multimedia/camera/imageio.cpp @@ -0,0 +1,55 @@ +/********************************************************************** +** Copyright (C) 2002 Michael 'Mickey' Lauer. All rights reserved. +** +** This file is part of Opie Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "imageio.h" + +#include +#include + + +void bufferToImage( int _width, int _height, unsigned char* bp, QImage* image ) +{ + unsigned char* p; + + image->create( _width, _height, 16 ); + for ( int i = 0; i < _height; ++i ) + { + p = image->scanLine( i ); + for ( int j = 0; j < _width; j++ ) + { + *p = *bp; + p++; + bp++; + *p = *bp; + p++; + bp++; + } + } +} + + +void imageToFile( QImage* i, const QString& name, const QString& format, int quality ) +{ + QImage im = i->convertDepth( 32 ); + bool result = im.save( name, format, quality ); + if ( !result ) + { + oerr << "imageio-Problem while writing." << oendl; + } + else + { + odebug << format << "-image has been successfully captured" << oendl; + } +} \ No newline at end of file diff --git a/noncore/multimedia/camera/imageio.h b/noncore/multimedia/camera/imageio.h new file mode 100644 index 0000000..8dba2ed --- a/dev/null +++ b/noncore/multimedia/camera/imageio.h @@ -0,0 +1,26 @@ +/********************************************************************** +** Copyright (C) 2003 Michael 'Mickey' Lauer. All rights reserved. +** +** This file is part of Opie Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef IMAGEIO_H +#define IMAGEIO_H + +#include + +class QImage; + +void bufferToImage( int _width, int height, unsigned char* bp, QImage* image ); +void imageToFile( QImage* i, const QString& name, const QString& format, int quality ); + +#endif diff --git a/noncore/multimedia/camera/mainwindow.cpp b/noncore/multimedia/camera/mainwindow.cpp index 8e89039..6141fd1 100644 --- a/noncore/multimedia/camera/mainwindow.cpp +++ b/noncore/multimedia/camera/mainwindow.cpp @@ -16,6 +16,7 @@ #include "mainwindow.h" #include "previewwidget.h" #include "zcameraio.h" +#include "imageio.h" #include #include @@ -27,8 +28,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -36,13 +39,20 @@ #include #include using namespace Opie; - #include #include +#include +#include +#include +#include +#include +#include + +#define CAPTUREFILE "/tmp/capture.dat" CameraMainWindow::CameraMainWindow( QWidget * parent, const char * name, WFlags f ) - :QMainWindow( parent, name, f ), _pics( 0 ) + :QMainWindow( parent, name, f ), _capturing( false ), _pics( 0 ) { #ifdef QT_NO_DEBUG if ( !ZCameraIO::instance()->isOpen() ) @@ -78,6 +88,9 @@ CameraMainWindow::CameraMainWindow( QWidget * parent, const char * name, WFlags connect( preview, SIGNAL( contextMenuRequested() ), this, SLOT( showContextMenu() ) ); connect( ZCameraIO::instance(), SIGNAL( shutterClicked() ), this, SLOT( shutterClicked() ) ); + + updateCaption(); + }; @@ -89,6 +102,7 @@ CameraMainWindow::~CameraMainWindow() void CameraMainWindow::init() { // TODO: Save this stuff in config + flip = 'A'; // auto quality = 50; zoom = 1; captureX = 640; @@ -121,16 +135,27 @@ void CameraMainWindow::init() ( new QAction( "x 1", 0, 0, zoomg, 0, true ) )->setOn( true ); new QAction( "x 2", 0, 0, zoomg, 0, true ); + flipg = new QActionGroup( 0, "flip", true ); + flipg->setToggleAction( true ); + ( new QAction( "Auto (recommended)", 0, 0, flipg, 0, true ) )->setOn( true ); + new QAction( "0 (always off)", 0, 0, flipg, 0, true ); + new QAction( "X (always horizontal)", 0, 0, flipg, 0, true ); + new QAction( "Y (always vertical)", 0, 0, flipg, 0, true ); + new QAction( "* (always both)", 0, 0, flipg, 0, true ); + outputg = new QActionGroup( 0, "output", true ); outputg->setToggleAction( true ); ( new QAction( "JPEG", 0, 0, outputg, 0, true ) )->setOn( true ); new QAction( "PNG", 0, 0, outputg, 0, true ); new QAction( "BMP", 0, 0, outputg, 0, true ); + new QAction( "AVI", 0, 0, outputg, 0, true ); connect( resog, SIGNAL( selected(QAction*) ), this, SLOT( resoMenuItemClicked(QAction*) ) ); connect( qualityg, SIGNAL( selected(QAction*) ), this, SLOT( qualityMenuItemClicked(QAction*) ) ); connect( zoomg, SIGNAL( selected(QAction*) ), this, SLOT( zoomMenuItemClicked(QAction*) ) ); + connect( flipg, SIGNAL( selected(QAction*) ), this, SLOT( flipMenuItemClicked(QAction*) ) ); connect( outputg, SIGNAL( selected(QAction*) ), this, SLOT( outputMenuItemClicked(QAction*) ) ); + } @@ -169,6 +194,7 @@ void CameraMainWindow::changeZoom( int zoom ) ZCameraIO::instance()->setCaptureFrame( 240, 160, z ); } + void CameraMainWindow::showContextMenu() { QPopupMenu reso; @@ -179,6 +205,10 @@ void CameraMainWindow::showContextMenu() quality.setCheckable( true ); qualityg->addTo( &quality ); + QPopupMenu flip; + flip.setCheckable( true ); + flipg->addTo( &flip ); + QPopupMenu zoom; zoom.setCheckable( true ); zoomg->addTo( &zoom ); @@ -190,6 +220,7 @@ void CameraMainWindow::showContextMenu() QPopupMenu m( this ); m.insertItem( "&Resolution", &reso ); m.insertItem( "&Zoom", &zoom ); + m.insertItem( "&Flip", &flip ); m.insertItem( "&Quality", &quality ); m.insertItem( "&Output As", &output ); m.exec( QCursor::pos() ); @@ -201,6 +232,7 @@ void CameraMainWindow::resoMenuItemClicked( QAction* a ) captureX = a->text().left(3).toInt(); captureY = a->text().right(3).toInt(); odebug << "Capture Resolution now: " << captureX << ", " << captureY << oendl; + updateCaption(); } @@ -208,14 +240,35 @@ void CameraMainWindow::qualityMenuItemClicked( QAction* a ) { quality = a->text().left(3).toInt(); odebug << "Quality now: " << quality << oendl; + updateCaption(); } void CameraMainWindow::zoomMenuItemClicked( QAction* a ) { - zoom = QString( a->text()[2] ).toInt(); + zoom = QString( a->text().at(2) ).toInt(); odebug << "Zoom now: " << zoom << oendl; ZCameraIO::instance()->setZoom( zoom ); + updateCaption(); +} + + +void CameraMainWindow::flipMenuItemClicked( QAction* a ) +{ + flip = QString( a->text().at(0) ); + odebug << "Flip now: " << flip << oendl; + if ( flip == "A" ) + ZCameraIO::instance()->setFlip( ZCameraIO::AUTOMATICFLIP ); + else if ( flip == "0" ) + ZCameraIO::instance()->setFlip( ZCameraIO::XNOFLIP | ZCameraIO::YNOFLIP ); + else if ( flip == "X" ) + ZCameraIO::instance()->setFlip( ZCameraIO::XFLIP ); + else if ( flip == "Y" ) + ZCameraIO::instance()->setFlip( ZCameraIO::YFLIP ); + else if ( flip == "*" ) + ZCameraIO::instance()->setFlip( ZCameraIO::XFLIP | ZCameraIO::YFLIP ); + + updateCaption(); } @@ -223,22 +276,37 @@ void CameraMainWindow::outputMenuItemClicked( QAction* a ) { captureFormat = a->text(); odebug << "Output format now: " << captureFormat << oendl; + updateCaption(); } void CameraMainWindow::shutterClicked() { - Global::statusMessage( "CAPTURING..." ); - qApp->processEvents(); + if ( captureFormat != "AVI" ) // capture one photo per shutterClick + { + Global::statusMessage( "CAPTURING..." ); + qApp->processEvents(); - odebug << "Shutter has been pressed" << oendl; - ODevice::inst()->touchSound(); + odebug << "Shutter has been pressed" << oendl; + ODevice::inst()->touchSound(); + + performCapture( captureFormat ); + } + else // capture video! start with one shutter click and stop with the next + { + !_capturing ? startVideoCapture() : stopVideoCapture(); + } +} + + +void CameraMainWindow::performCapture( const QString& format ) +{ QString name; name.sprintf( "/tmp/image-%d_%d_%d_q%d.%s", _pics++, captureX, captureY, quality, (const char*) captureFormat.lower() ); QImage i; ZCameraIO::instance()->captureFrame( captureX, captureY, zoom, &i ); QImage im = i.convertDepth( 32 ); - bool result = im.save( name, captureFormat, quality ); + bool result = im.save( name, format, quality ); if ( !result ) { oerr << "imageio-Problem while writing." << oendl; @@ -251,3 +319,117 @@ void CameraMainWindow::shutterClicked() } } + +void CameraMainWindow::startVideoCapture() +{ + //ODevice::inst()->touchSound(); + ODevice::inst()->setLedState( Led_Mail, Led_BlinkSlow ); + + _capturefd = ::open( CAPTUREFILE, O_WRONLY | O_CREAT ); + if ( _capturefd == -1 ) + { + owarn << "can't open capture file: " << strerror(errno) << oendl; + return; + } + + _capturebuf = new unsigned char[captureX*captureY*2]; + _capturing = true; + _videopics = 0; + updateCaption(); + _time.start(); + preview->setRefreshingRate( 1000 ); + startTimer( 100 ); // too fast but that is ok +} + + +void CameraMainWindow::timerEvent( QTimerEvent* ) +{ + if ( !_capturing ) + { + owarn << "timer event in CameraMainWindow without capturing video ?" << oendl; + return; + } + + ZCameraIO::instance()->captureFrame( captureX, captureY, zoom, _capturebuf ); + _videopics++; + ::write( _capturefd, _capturebuf, captureX*captureY*2 ); + setCaption( QString().sprintf( "Capturing %dx%d @ %.2f fps %d", + captureX, captureY, 1000.0 / (_time.elapsed()/_videopics), _videopics ) ); +} + + +void CameraMainWindow::stopVideoCapture() +{ + killTimers(); + //ODevice::inst()->touchSound(); + ODevice::inst()->setLedState( Led_Mail, Led_Off ); + _capturing = false; + updateCaption(); + ::close( _capturefd ); + + //postProcessVideo(); + + #ifndef QT_NO_DEBUG + preview->setRefreshingRate( 1500 ); + #else + preview->setRefreshingRate( 200 ); + #endif + + //delete[] _capturebuf; //FIXME: close memory leak +} + +void CameraMainWindow::postProcessVideo() +{ + preview->setRefreshingRate( 0 ); + + /* + + QDialog* fr = new QDialog( this, "splash" ); //, false, QWidget::WStyle_NoBorder | QWidget::WStyle_Customize ); + fr->setCaption( "Please wait..." ); + QVBoxLayout* box = new QVBoxLayout( fr, 2, 2 ); + QProgressBar* bar = new QProgressBar( fr ); + bar->setCenterIndicator( true ); + bar->setTotalSteps( _videopics-1 ); + QLabel* label = new QLabel( "Post processing frame bla/bla", fr ); + box->addWidget( bar ); + box->addWidget( label ); + fr->show(); + qApp->processEvents(); + + for ( int i = 0; i < _videopics; ++i ) + { + label->setText( QString().sprintf( "Post processing frame %d / %d", i+1, _videopics ) ); + bar->setProgress( i ); + qApp->processEvents(); + } + + */ + + int infd = ::open( CAPTUREFILE, O_RDONLY ); + if ( infd == -1 ) + { + owarn << "couldn't open capture file: " << strerror(errno) << oendl; + return; + } + + int outfd = ::open( "/tmp/output.avi", O_WRONLY ); + if ( outfd == -1 ) + { + owarn << "couldn't open output file: " << strerror(errno) << oendl; + return; + } + + + + +} + +void CameraMainWindow::updateCaption() +{ + if ( !_capturing ) + setCaption( QString().sprintf( "Opie-Camera: %dx%d %s q%d z%d (%s)", captureX, captureY, (const char*) captureFormat.lower(), quality, zoom, (const char*) flip ) ); + else + setCaption( "Opie-Camera: => CAPTURING <=" ); +} + + diff --git a/noncore/multimedia/camera/mainwindow.h b/noncore/multimedia/camera/mainwindow.h index 7a12452..ad8d1b1 100644 --- a/noncore/multimedia/camera/mainwindow.h +++ b/noncore/multimedia/camera/mainwindow.h @@ -20,10 +20,12 @@ #include #include #include +#include class QAction; class QActionGroup; class QIconSet; +class QTimerEvent; class QToolButton; class QLabel; class MainWindowBase; @@ -45,11 +47,20 @@ class CameraMainWindow: public QMainWindow void resoMenuItemClicked( QAction* ); void qualityMenuItemClicked( QAction* ); void zoomMenuItemClicked( QAction* ); + void flipMenuItemClicked( QAction* ); void outputMenuItemClicked( QAction* ); void shutterClicked(); + void updateCaption(); + protected: void init(); + void startVideoCapture(); + void stopVideoCapture(); + void postProcessVideo(); + void performCapture( const QString& ); + + virtual void timerEvent( QTimerEvent* ); private: PreviewWidget* preview; @@ -59,15 +70,23 @@ class CameraMainWindow: public QMainWindow QActionGroup* resog; QActionGroup* qualityg; QActionGroup* zoomg; + QActionGroup* flipg; QActionGroup* outputg; + QString flip; int quality; int zoom; int captureX; int captureY; QString captureFormat; + bool _capturing; int _pics; + + QTime _time; + int _videopics; + int _capturefd; + unsigned char* _capturebuf; }; #endif diff --git a/noncore/multimedia/camera/previewwidget.cpp b/noncore/multimedia/camera/previewwidget.cpp index f87dcc9..08330d0 100644 --- a/noncore/multimedia/camera/previewwidget.cpp +++ b/noncore/multimedia/camera/previewwidget.cpp @@ -72,3 +72,17 @@ void PreviewWidget::mousePressEvent( QMouseEvent* ) emit contextMenuRequested(); } + +void PreviewWidget::setRefreshingRate( int ms ) +{ + killTimers(); + if ( ms ) + startTimer( ms ); +} + + +void PreviewWidget::refresh() +{ + QTimerEvent t( 10 ); // event id is meaningless in this case + timerEvent( &t ); +} diff --git a/noncore/multimedia/camera/previewwidget.h b/noncore/multimedia/camera/previewwidget.h index dada301..d37f80f 100644 --- a/noncore/multimedia/camera/previewwidget.h +++ b/noncore/multimedia/camera/previewwidget.h @@ -31,6 +31,9 @@ class PreviewWidget: public QLabel PreviewWidget( QWidget * parent = 0, const char * name = 0, WFlags f = 0 ); virtual ~PreviewWidget(); + void setRefreshingRate( int ms ); + void refresh(); + protected: virtual void timerEvent( QTimerEvent* ); virtual void resizeEvent( QResizeEvent* ); diff --git a/noncore/multimedia/camera/zcameraio.cpp b/noncore/multimedia/camera/zcameraio.cpp index 9af0c25..1c449e7 100644 --- a/noncore/multimedia/camera/zcameraio.cpp +++ b/noncore/multimedia/camera/zcameraio.cpp @@ -44,7 +44,9 @@ ZCameraIO* ZCameraIO::instance() ZCameraIO::ZCameraIO() - :_height( 0 ), _width( 0 ), _zoom( 0 ), _rot( 0 ), _readlen( 0 ) + : _pressed( false ), _height( 0 ), _width( 0 ), _zoom( 0 ), + _flip( -1 ), _rot( 0 ), _readlen( 0 ) + { _driver = ::open( SHARPZDC, O_RDWR ); if ( _driver == -1 ) @@ -84,18 +86,24 @@ bool ZCameraIO::isOpen() const bool ZCameraIO::isShutterPressed() { - if ( _timer->elapsed() < 1000 ) //TODO: make this customizable? - { - clearShutterLatch(); - return false; - } if ( _status[0] == 'S' ) { - _timer->restart(); - clearShutterLatch(); - return true; + if ( !_pressed ) // wasn't pressed before, but is now! + { + _pressed = true; + _timer->start(); + return true; + } + + if ( _timer->elapsed() > 2000 ) // the press is pretty old now + { + clearShutterLatch(); + _status[0] = 's'; + _pressed = false; + } } - else return false; + + return false; } @@ -149,11 +157,20 @@ void ZCameraIO::setReadMode( int mode ) if ( mode & STATUS ) // STATUS bit is set { read( _status, 4 ); - if ( isShutterPressed() ) emit shutterClicked(); + if ( isShutterPressed() ) + { + emit shutterClicked(); + } } } +void ZCameraIO::setFlip( int flip ) +{ + _flip = flip; +} + + void ZCameraIO::clearShutterLatch() { write( "B", 1 ); @@ -198,15 +215,25 @@ bool ZCameraIO::snapshot( QImage* image ) odebug << "finder reversed = " << isFinderReversed() << oendl; odebug << "rotation = " << _rot << oendl; - if ( _rot ) // Portrait + int readmode; + if ( _flip == -1 ) // AUTO { - setReadMode( IMAGE | isFinderReversed() ? XFLIP | YFLIP : 0 ); + if ( _rot ) // Portrait + { + readmode = IMAGE | isFinderReversed() ? XFLIP | YFLIP : 0; + } + else // Landscape + { + readmode = IMAGE | XFLIP | YFLIP; + } } - else // Landscape + else // OVERRIDE { - setReadMode( IMAGE | XFLIP | YFLIP ); //isFinderReversed() ? 0 : XFLIP ); + readmode = IMAGE | _flip; } + setReadMode( readmode ); + char buf[_readlen]; char* bp = buf; unsigned char* p; @@ -234,18 +261,31 @@ bool ZCameraIO::snapshot( QImage* image ) bool ZCameraIO::snapshot( unsigned char* buf ) { - setReadMode( IMAGE | XFLIP | YFLIP ); + setReadMode( STATUS ); - read( (char*) buf, _readlen ); + odebug << "finder reversed = " << isFinderReversed() << oendl; + odebug << "rotation = " << _rot << oendl; - /* //TESTCODE - int fd = open( "/tmp/cam", O_RDONLY ); - if ( ::read( fd, (char*) buf, 76800 ) != 76800 ) - owarn << "Couldn't read image from /dev/sharp_zdc" << oendl; - // TESTCODE */ + int readmode; + if ( _flip == -1 ) // AUTO + { + if ( _rot ) // Portrait + { + readmode = IMAGE | isFinderReversed() ? XFLIP | YFLIP : 0; + } + else // Landscape + { + readmode = IMAGE | XFLIP | YFLIP; + } + } + else // OVERRIDE + { + readmode = IMAGE | _flip; + } + setReadMode( readmode ); + read( (char*) buf, _readlen ); - return true; } @@ -262,3 +302,17 @@ void ZCameraIO::captureFrame( int w, int h, int zoom, QImage* image ) } +void ZCameraIO::captureFrame( int w, int h, int zoom, unsigned char* buf ) +{ + //FIXME: this is too slow + int pw = _width; + int ph = _height; + if ( _rot ) + setCaptureFrame( h, w, zoom*256, true ); + else + setCaptureFrame( w, h, zoom*256, false ); + + snapshot( buf ); + setCaptureFrame( pw, ph, _zoom, _rot ); +} + diff --git a/noncore/multimedia/camera/zcameraio.h b/noncore/multimedia/camera/zcameraio.h index edce143..3352a5e 100644 --- a/noncore/multimedia/camera/zcameraio.h +++ b/noncore/multimedia/camera/zcameraio.h @@ -33,7 +33,8 @@ class ZCameraIO : public QObject IMAGE = 0, STATUS = 1, FASTER = 0, BETTER = 2, XNOFLIP = 0, XFLIP = 4, - YNOFLIP = 0, YFLIP = 8 + YNOFLIP = 0, YFLIP = 8, + AUTOMATICFLIP = -1 }; // low level interface @@ -41,19 +42,21 @@ class ZCameraIO : public QObject bool setCaptureFrame( int w, int h, int zoom = 256, bool rot = true ); bool setZoom( int zoom = 0 ); void setReadMode( int = IMAGE | XFLIP | YFLIP ); + void setFlip( int flip ); bool isShutterPressed(); // not const, because it calls clearShutterLatch bool isAvailable() const; bool isCapturing() const; bool isFinderReversed() const; - bool snapshot( unsigned char* ); - bool snapshot( QImage* ); + bool snapshot( QImage* image ); + bool snapshot( unsigned char* buf ); // high level interface bool isOpen() const; static ZCameraIO* instance(); void captureFrame( int w, int h, int zoom, QImage* image ); + void captureFrame( int w, int h, int zoom, unsigned char* buf ); protected: ZCameraIO(); @@ -68,10 +71,12 @@ class ZCameraIO : public QObject private: int _driver; char _status[4]; + bool _pressed; static ZCameraIO* _instance; int _height; int _width; int _zoom; + int _flip; bool _rot; int _readlen; -- cgit v0.9.0.2