[niepce] Basic video thumbnailing Rudimentary caching for thumbnails.



commit f9c6d4760b4905a0e96b3bf29595daf8e2ddefa1
Author: Hub Figuiere <hub figuiere net>
Date:   Sun Nov 6 16:52:52 2011 -0800

    Basic video thumbnailing
    Rudimentary caching for thumbnails.

 src/engine/library/thumbnailcache.cpp |  230 ++++++++++++++++++++-------------
 src/engine/library/thumbnailcache.hpp |   79 +++++++-----
 src/fwk/toolkit/Makefile.am           |    1 +
 src/fwk/toolkit/movieutils.cpp        |   47 +++++++
 src/fwk/toolkit/movieutils.hpp        |   43 ++++++
 5 files changed, 278 insertions(+), 122 deletions(-)
---
diff --git a/src/engine/library/thumbnailcache.cpp b/src/engine/library/thumbnailcache.cpp
index 7503482..cb0be65 100644
--- a/src/engine/library/thumbnailcache.cpp
+++ b/src/engine/library/thumbnailcache.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - library/thumbnailcache.cpp
  *
- * Copyright (C) 2007-2008 Hubert Figuiere
+ * Copyright (C) 2007-2008,2011 Hubert Figuiere
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,111 +22,163 @@
 #include <functional>
 #include <boost/bind.hpp>
 #include <boost/any.hpp>
+#include <boost/lexical_cast.hpp>
 
 #include <gdkmm/pixbuf.h>
 #include <libopenraw-gnome/gdkpixbuf.h>
 
 #include "niepce/notifications.hpp"
 #include "fwk/base/debug.hpp"
+#include "fwk/utils/pathutils.hpp"
 #include "fwk/toolkit/mimetype.hpp"
 #include "fwk/toolkit/gdkutils.hpp"
+#include "fwk/toolkit/movieutils.hpp"
 #include "thumbnailcache.hpp"
 #include "thumbnailnotification.hpp"
 
 namespace eng {
 
-	ThumbnailCache::ThumbnailCache(const std::string & dir,
-								   const fwk::NotificationCenter::Ptr & nc)
-		: m_cacheDir(dir),
-		  m_notif_center(nc)
-	{
-	}
-
-	ThumbnailCache::~ThumbnailCache()
-	{
-	}
-
-	void ThumbnailCache::request(const LibFile::ListPtr & fl)
-	{
-		clear();
-		std::for_each(fl->begin(), fl->end(),
-					 boost::bind(&ThumbnailCache::requestForFile, this, 
-								 _1));
-	}
-
-	void ThumbnailCache::requestForFile(const LibFile::Ptr & f)
-	{
-		ThumbnailTask::Ptr task(new ThumbnailTask(f, 160, 160));
-		schedule( task );
-	}
-
-
-	void ThumbnailCache::execute(const  ThumbnailTask::Ptr & task)
-	{
-    const std::string & filename = task->file()->path();
-		DBG_OUT("creating thumbnail for %s",filename.c_str());
+ThumbnailCache::ThumbnailCache(const std::string & dir,
+                               const fwk::NotificationCenter::Ptr & nc)
+    : m_cacheDir(dir),
+      m_notif_center(nc)
+{
+}
+
+ThumbnailCache::~ThumbnailCache()
+{
+}
+
+void ThumbnailCache::request(const LibFile::ListPtr & fl)
+{
+    clear();
+    std::for_each(fl->begin(), fl->end(),
+                  boost::bind(&ThumbnailCache::requestForFile, this, 
+                              _1));
+}
+
+void ThumbnailCache::requestForFile(const LibFile::Ptr & f)
+{
+    ThumbnailTask::Ptr task(new ThumbnailTask(f, 160, 160));
+    schedule( task );
+}
+
+namespace {
+
+// TODO see about 1. moving this out 2. abstracting the type away from Gdk::Pixbuf
+// Gdk does not belong to eng.
+Glib::RefPtr<Gdk::Pixbuf> getThumbnail(const LibFile::Ptr & f, int w, int h, const std::string & cached)
+{
+    if(ThumbnailCache::is_thumbnail_cached(f->path(), cached)) {
+        DBG_OUT("cached!");
+        return Gdk::Pixbuf::create_from_file(cached);
+    }
+    const std::string & filename = f->path();
+    DBG_OUT("creating thumbnail for %s",filename.c_str());
+
+    fwk::MimeType mime_type(filename);
+
+
+    DBG_OUT("MIME type %s", mime_type.string().c_str());
+	
+    Glib::RefPtr<Gdk::Pixbuf> pix;
+
+    if(mime_type.isUnknown()) {
+        DBG_OUT("unknown file type %s", filename.c_str());
+    }
+    // TODO: what about videos?
+    else if(mime_type.isMovie()) {
+        if(fwk::thumbnail_movie(filename, w, h, cached)) {
+            pix = Gdk::Pixbuf::create_from_file(cached, w, h, true);
+        }
+    }
+    else if(!mime_type.isImage()) {
+        DBG_OUT("not an image type");
+    }
+    else if(!mime_type.isDigicamRaw()) {
+        DBG_OUT("not a raw type, trying GdkPixbuf loaders");
+        try {
+            pix = Gdk::Pixbuf::create_from_file(filename, w, h, true);
+            if(pix) {
+                pix = fwk::gdkpixbuf_exif_rotate(pix, f->orientation());
+            }
+        }
+        catch(const Glib::Error & e) {
+            ERR_OUT("exception %s", e.what().c_str());
+        }
+    }	
+    else {	
+        GdkPixbuf *pixbuf = or_gdkpixbuf_extract_rotated_thumbnail(filename.c_str(), 
+                                                                   std::min(w, h));
+        if(pixbuf) {
+            pix = Glib::wrap(pixbuf, true); // take ownership
+        }
+        if((w < pix->get_width()) || (h < pix->get_height())) {
+            pix = fwk::gdkpixbuf_scale_to_fit(pix, std::min(w,h));
+        }
+    }
+    if(pix)
+    {
+        pix->save(cached, "png");
+    }
+    else {
+        DBG_OUT("couldn't get the thumbnail for %s", filename.c_str());
+    }
+    return pix;
+}
+
+}
+
+void ThumbnailCache::execute(const  ThumbnailTask::Ptr & task)
+{
     int w, h;
     w = task->width();
     h = task->height();
 
-		fwk::MimeType mime_type(filename);
-
-
-		DBG_OUT("MIME type %s", mime_type.string().c_str());
-
-		if(mime_type.isUnknown()) {
-			DBG_OUT("unknown file type %s", filename.c_str());
-			return;
-		}
-		if(!mime_type.isImage()) {
-			DBG_OUT("not an image type");
-			return;
-		}
-		
-		Glib::RefPtr<Gdk::Pixbuf> pix;
-		if(!mime_type.isDigicamRaw()) {
-			DBG_OUT("not a raw type, trying GdkPixbuf loaders");
-      try {
-        pix = Gdk::Pixbuf::create_from_file(filename, w, h, true);
-        if(pix) {
-          pix = fwk::gdkpixbuf_exif_rotate(pix, task->file()->orientation());
+    Glib::RefPtr<Gdk::Pixbuf> pix;
+
+    std::string dest = path_for_thumbnail(task->file()->path(), std::max(w,h));
+    DBG_OUT("cached thumbnail %s", dest.c_str());
+
+    pix = getThumbnail(task->file(), w, h, dest);
+
+    if(pix) {
+        fwk::NotificationCenter::Ptr nc(m_notif_center);
+        if(nc) {
+            // pass the notification
+            fwk::Notification::Ptr n(new fwk::Notification(niepce::NOTIFICATION_THUMBNAIL));
+            ThumbnailNotification tn;
+            tn.id = task->file()->id();
+            tn.width = pix->get_width();
+            tn.height = pix->get_height();
+            tn.pixmap = pix;
+            n->setData(boost::any(tn));
+            DBG_OUT("notify thumbnail for id=%d", tn.id);
+            nc->post(n);
         }
-      }
-      catch(const Glib::Error & e) 
-      {
-        ERR_OUT("exception %s", e.what().c_str());
-      }
-		}	
-		else {	
-			GdkPixbuf *pixbuf = or_gdkpixbuf_extract_rotated_thumbnail(filename.c_str(), 
-																	   std::min(w, h));
-			if(pixbuf) {
-				 pix = Glib::wrap(pixbuf, true); // take ownership
-			}
-		}
-		if(pix)
-		{
-            if((w < pix->get_width()) || (h < pix->get_height())) {
-                pix = fwk::gdkpixbuf_scale_to_fit(pix, std::min(w,h));
-            }
-			fwk::NotificationCenter::Ptr nc(m_notif_center);
-			if(nc) {
-				// pass the notification
-				fwk::Notification::Ptr n(new fwk::Notification(niepce::NOTIFICATION_THUMBNAIL));
-				ThumbnailNotification tn;
-				tn.id = task->file()->id();
-				tn.width = pix->get_width();
-				tn.height = pix->get_height();
-				tn.pixmap = pix;
-				n->setData(boost::any(tn));
-				DBG_OUT("notify thumbnail for id=%d", tn.id);
-				nc->post(n);
-			}
-		}
-		else 
-		{
-			DBG_OUT("couldn't get the thumbnail for %s", filename.c_str());
-		}
-	}
+    }
+}
 
+std::string ThumbnailCache::path_for_thumbnail(const std::string & filename, int size) const
+{
+    std::string subdir = size ? boost::lexical_cast<std::string>(size) : "full";
+    // todo compute a hash
+    return m_cacheDir + "/" + subdir + "/" + fwk::path_basename(filename) + ".png";
 }
+
+bool ThumbnailCache::is_thumbnail_cached(const std::string & /*file*/, const std::string & thumb)
+{
+    return fwk::path_exists(thumb);
+}
+
+
+}
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  indent-tabs-mode:nil
+  fill-column:80
+  End:
+*/
diff --git a/src/engine/library/thumbnailcache.hpp b/src/engine/library/thumbnailcache.hpp
index c3c2a2a..001cd2e 100644
--- a/src/engine/library/thumbnailcache.hpp
+++ b/src/engine/library/thumbnailcache.hpp
@@ -1,7 +1,7 @@
 /*
  * niepce - library/thumbnailcache.h
  *
- * Copyright (C) 2007 Hubert Figuiere
+ * Copyright (C) 2007,2011 Hubert Figuiere
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,46 +30,59 @@
 namespace eng {
 
 
-	class ThumbnailTask
-	{
-	public:
-		typedef std::tr1::shared_ptr< ThumbnailTask > Ptr;
+class ThumbnailTask
+{
+public:
+    typedef std::tr1::shared_ptr< ThumbnailTask > Ptr;
 		
-		ThumbnailTask(const LibFile::Ptr & f, int w, int h)
-			: m_file(f), m_width(w), m_height(h)
-			{ }
+    ThumbnailTask(const LibFile::Ptr & f, int w, int h)
+        : m_file(f), m_width(w), m_height(h)
+        { }
 		
-		const LibFile::Ptr & file()
-			{ return m_file; }
-		int width() const
-			{ return m_width; }
-		int height() const
-			{ return m_height; }
-	private:
-		const LibFile::Ptr m_file;
-		int m_width;
-		int m_height;
-	};
+    const LibFile::Ptr & file()
+        { return m_file; }
+    int width() const
+        { return m_width; }
+    int height() const
+        { return m_height; }
+private:
+    const LibFile::Ptr m_file;
+    int m_width;
+    int m_height;
+};
 
 
-	class ThumbnailCache
-		: private fwk::Worker< ThumbnailTask::Ptr >
-	{
-	public:
-		ThumbnailCache(const std::string & dir,
-					   const fwk::NotificationCenter::Ptr & nc);
-		~ThumbnailCache();
+class ThumbnailCache
+    : private fwk::Worker< ThumbnailTask::Ptr >
+{
+public:
+    ThumbnailCache(const std::string & dir,
+                   const fwk::NotificationCenter::Ptr & nc);
+    ~ThumbnailCache();
 
-		void request(const LibFile::ListPtr & fl);
-		void requestForFile(const LibFile::Ptr & f);
+    void request(const LibFile::ListPtr & fl);
+    void requestForFile(const LibFile::Ptr & f);
 
-	protected:
-		virtual void execute(const  ThumbnailTask::Ptr & task);
-	private:
+    static bool is_thumbnail_cached(const std::string & file, const std::string & thumb);
+
+protected:
+    virtual void execute(const  ThumbnailTask::Ptr & task);
+private:
     std::string                                 m_cacheDir;
-		std::tr1::weak_ptr<fwk::NotificationCenter> m_notif_center;
-	};
+    std::tr1::weak_ptr<fwk::NotificationCenter> m_notif_center;
+
+    std::string path_for_thumbnail(const std::string & filename, int size) const;
+};
 
 }
 
 #endif
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  indent-tabs-mode:nil
+  fill-column:80
+  End:
+*/
diff --git a/src/fwk/toolkit/Makefile.am b/src/fwk/toolkit/Makefile.am
index 6976c18..10850f5 100644
--- a/src/fwk/toolkit/Makefile.am
+++ b/src/fwk/toolkit/Makefile.am
@@ -22,6 +22,7 @@ libniepceframework_a_SOURCES = configuration.hpp configuration.cpp \
 	uicontroller.hpp uicontroller.cpp \
 	notification.hpp \
 	mimetype.hpp mimetype.cpp \
+	movieutils.hpp movieutils.cpp \
 	imageloader.hpp imageloader.cpp \
 	notificationcenter.hpp notificationcenter.cpp \
 	configdatabinder.hpp configdatabinder.cpp \
diff --git a/src/fwk/toolkit/movieutils.cpp b/src/fwk/toolkit/movieutils.cpp
new file mode 100644
index 0000000..79cd6d5
--- /dev/null
+++ b/src/fwk/toolkit/movieutils.cpp
@@ -0,0 +1,47 @@
+/*
+ * niepce - fwk/movieutils.cpp
+ *
+ * Copyright (C) 2011 Hub Figuiere
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdlib.h>
+
+#include <boost/format.hpp>
+
+
+namespace fwk {
+
+  // TODO don't harcode command
+  // TODO check errors
+  // TODO be smarter
+bool thumbnail_movie(const std::string &src, int w, int h, const std::string &dest)
+{
+  std::string command = str(boost::format("totem-video-thumbnailer -s %1% %2% %3%") 
+			    % std::max(w,h) % src % dest);
+  return system(command.c_str()) != -1;
+}
+
+}
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  indent-tabs-mode:nil
+  fill-column:80
+  End:
+*/
diff --git a/src/fwk/toolkit/movieutils.hpp b/src/fwk/toolkit/movieutils.hpp
new file mode 100644
index 0000000..936030e
--- /dev/null
+++ b/src/fwk/toolkit/movieutils.hpp
@@ -0,0 +1,43 @@
+/*
+ * niepce - fwk/movieutils.hpp
+ *
+ * Copyright (C) 2011 Hub Figuiere
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FWK_MOVIEUTILS_HPP_
+#define __FWK_MOVIEUTILS_HPP_
+
+#include <string>
+
+namespace fwk {
+
+/** Make a thumbnail for a movie. */
+bool thumbnail_movie(const std::string &movie, int w, int h, const std::string &thumbnail);
+
+}
+
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  indent-tabs-mode:nil
+  fill-column:80
+  End:
+*/
+
+#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]