[Jahshaka-cvs] jah/jahwidgets/src/qt3/wrapper thumbnailer.cpp, NONE, 1.1 thumbnailer.hpp, NONE, 1.1
Status: Beta
Brought to you by:
jahshaka
From: John B. <ok_...@us...> - 2007-04-16 16:01:41
|
Update of /cvsroot/jahshaka/jah/jahwidgets/src/qt3/wrapper In directory sc8-pr-cvs6.sourceforge.net:/tmp/cvs-serv24898/jahwidgets/src/qt3/wrapper Modified Files: wrapper.pro Added Files: thumbnailer.cpp thumbnailer.hpp Log Message: Adding a thumbnailer. Generates thumbnail images for media in a background thread. --- NEW FILE: thumbnailer.hpp --- /* -*- mode: C++; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- */ // jahwidgets - A widget library representation. // Copyright (C) 2006 VM Inc. // Released under the GPL. // For more information, see http://www.jahshaka.org. #ifndef JR_THUMBNAILER_H #define JR_THUMBNAILER_H #include "widgets/mediaPtr.h" // qt #include <qobject.h> #include <qevent.h> #include <qstring.h> #include "config.h" #include <openimagelib/il/openimagelib_plugin.hpp> #include <openpluginlib/pl/string.hpp> namespace jahwidgets { namespace qt3 { namespace il = olib::openimagelib::il; namespace opl = olib::openpluginlib; class ThumbnailerDelegate; class ThumbnailerThread; class WRAPPER_DECLSPEC Thumbnailer : public QObject { Q_OBJECT public: static Thumbnailer* thumbnailer(); virtual ~Thumbnailer(); // Create a thumbnail for the media. Optionally update the media's asset with info such as fps, length etc void push_back( const opl::wstring& id, MediaPtr media, int max_w, int max_h, bool update_asset = false ); il::image_type_ptr pop_result( const opl::wstring& id ); // Empty the thread's queue void empty_queue(); ThumbnailerDelegate* delegate() const { return _delegate; } void setDelegate( ThumbnailerDelegate* delegate ) { _delegate = delegate; } protected: void customEvent( QCustomEvent* ); private: Thumbnailer(); ThumbnailerThread* _thread; ThumbnailerDelegate* _delegate; }; class WRAPPER_DECLSPEC ThumbnailerDelegate { public: virtual ~ThumbnailerDelegate() {} // This will always be sent by the main Qt thread virtual void notify_task_done( const QString& id ) = 0; }; class WRAPPER_DECLSPEC ThumbnailerEvent : public QCustomEvent { public: ThumbnailerEvent( const QString& id ) : QCustomEvent( ThumbnailerEvent::type ), _id(id) {} QString id() const { return _id; } static int type; private: QString _id; }; } } #endif Index: wrapper.pro =================================================================== RCS file: /cvsroot/jahshaka/jah/jahwidgets/src/qt3/wrapper/wrapper.pro,v retrieving revision 1.25 retrieving revision 1.26 diff -u -d -r1.25 -r1.26 --- wrapper.pro 11 Apr 2007 08:46:49 -0000 1.25 +++ wrapper.pro 16 Apr 2007 16:01:36 -0000 1.26 @@ -34,7 +34,8 @@ detail_view.cpp \ splitter.cpp \ action.cpp \ - keys.cpp + keys.cpp \ + thumbnailer.cpp HEADERS += widgetFactory.h \ mem_fn_observer.hpp \ @@ -55,4 +56,5 @@ splitter.hpp \ action.hpp \ keys.hpp \ - dialog_delegate.hpp + dialog_delegate.hpp \ + thumbnailer.hpp --- NEW FILE: thumbnailer.cpp --- /* -*- mode: C++; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- */ // jahwidgets - A widget library representation. // Copyright (C) 2006 VM Inc. // Released under the GPL. // For more information, see http://www.jahshaka.org. #include "thumbnailer.hpp" #include "utils/string_utils.hpp" #include <openassetlib/al/asset.hpp> // qt #include <qthread.h> #include <qmutex.h> #include <qwaitcondition.h> #include <qapplication.h> #include <deque> namespace jahwidgets { namespace qt3 { namespace al = olib::openassetlib::al; int ThumbnailerEvent::type = 10001; template <typename T> struct IdPredicate { IdPredicate( const QString& id ) : targetId(id) {} bool operator()( T obj ) const { return targetId == obj.id; } QString targetId; }; static QWaitCondition input_condition; class ThumbnailerThread : public QThread { public: ThumbnailerThread( QObject* owner ) : _owner(owner) {} void push_back( const QString& id, MediaPtr media, int max_w, int max_h, bool update_asset ) { _mutex.lock(); // Ensure this item isn't already queued in either the input or output queue InputQueue::const_iterator I = std::find_if( _input_queue.begin(), _input_queue.end(), IdPredicate<InputData>( id ) ); OutputQueue::const_iterator O = std::find_if( _output_queue.begin(), _output_queue.end(), IdPredicate<OutputData>( id ) ); if ( I == _input_queue.end() && O == _output_queue.end() ) { // queue it //qDebug( "queue: %s", id.latin1() ); _input_queue.push_back( InputData( id, media, max_w, max_h, update_asset ) ); } _mutex.unlock(); } il::image_type_ptr pop_result( const QString& id ) { il::image_type_ptr image; _mutex.lock(); // if we have the data return it OutputQueue::iterator I = std::find_if( _output_queue.begin(), _output_queue.end(), IdPredicate<OutputData>( id ) ); if ( I != _output_queue.end() ) { //qDebug( "pop_result: %s", id.latin1() ); image = I->image; _output_queue.erase( I ); } _mutex.unlock(); return image; } void empty_queue() { _mutex.lock(); _input_queue.clear(); _mutex.unlock(); } void run() { while( true ) { if ( !_input_queue.empty() ) { // Process one item and pop it off the queue _mutex.lock(); InputData data = _input_queue.front(); _input_queue.pop_front(); _mutex.unlock(); //qDebug( "processing: %s", data.id.latin1() ); il::image_type_ptr image; if ( data.media && data.media->open() && data.media->is_valid() ) { if ( data.update_asset ) { al::asset_ptr asset = data.media->get_asset(); if ( !asset ) { asset = al::asset_factory::instance().create_asset(); data.media->set_asset( asset ); } asset->set( "fps", data.media->fps() ); asset->set( "length", data.media->length() ); } image = data.media->image(); if ( image ) { if ( data.update_asset ) { al::asset_ptr asset = data.media->get_asset(); asset->set( "width", image->width() ); asset->set( "height", image->height() ); } QSize sz = bind_size_to( image->width(), image->height(), data.max_w, data.max_h ); image = il::rescale( image, sz.width(), sz.height() ); } } // Always add to the output queue, even if the thumbnail generation failed _mutex.lock(); _output_queue.push_back( OutputData( data.id, image ) ); _mutex.unlock(); qApp->postEvent( _owner, new ThumbnailerEvent( data.id ) ); } else { input_condition.wait(); } } } private: QSize bind_size_to( int cw, int ch, int mw, int mh ) { if ( cw == 0 || ch == 0 ) { return QSize( cw, ch ); } float ar = float( cw ) / float( ch ); if ( int(mh * ar) <= mw ) { return QSize( int( mh * ar ), mh ); } else { return QSize( mw, int( mw / ar ) ); } } struct InputData { InputData( const QString& id_, MediaPtr media_, int max_w_, int max_h_, bool update_asset_ ) : id(id_), media(media_), max_w(max_w_), max_h(max_h_), update_asset(update_asset_) {} QString id; MediaPtr media; int max_w, max_h; bool update_asset; }; struct OutputData { OutputData( const QString& id_, il::image_type_ptr image_ ) : id(id_), image(image_) {} QString id; il::image_type_ptr image; }; QObject* _owner; QMutex _mutex; typedef std::deque<InputData> InputQueue; typedef std::deque<OutputData> OutputQueue; InputQueue _input_queue; OutputQueue _output_queue; }; Thumbnailer* Thumbnailer::thumbnailer() { static Thumbnailer* _instance; if ( !_instance ) { _instance = new Thumbnailer(); } return _instance; } Thumbnailer::Thumbnailer() : _thread( new ThumbnailerThread(this) ), _delegate(NULL) { } Thumbnailer::~Thumbnailer() { _thread->empty_queue(); _thread->terminate(); _thread->wait(); delete _thread; } void Thumbnailer::push_back( const opl::wstring& id, MediaPtr media, int max_w, int max_h, bool update_asset ) { _thread->push_back( WStringToQString::convert(id), media, max_w, max_h, update_asset ); // Wake up the thread if ( !_thread->running() ) { _thread->start(); } else { input_condition.wakeAll(); } } il::image_type_ptr Thumbnailer::pop_result( const opl::wstring& id ) { return _thread->pop_result( WStringToQString::convert(id) ); } void Thumbnailer::empty_queue() { _thread->empty_queue(); } void Thumbnailer::customEvent( QCustomEvent* e ) { if ( e->type() == ThumbnailerEvent::type ) { ThumbnailerEvent* te = dynamic_cast<ThumbnailerEvent*>(e); if ( te && _delegate ) { _delegate->notify_task_done( te->id() ); } } } } } |