transcode sucks too much (often a green image instead of a proper thumbnail), replace...
authorgc <gc>
Thu, 7 Feb 2008 23:31:58 +0000 (23:31 +0000)
committergc <gc>
Thu, 7 Feb 2008 23:31:58 +0000 (23:31 +0000)
INTERNALS
bin/booh
bin/booh-backend
bin/booh-classifier
lib/booh/booh-lib.rb

index 0219bf4..5c948cd 100644 (file)
--- a/INTERNALS
+++ b/INTERNALS
@@ -5,7 +5,7 @@ Booh uses
 - XML documents to save config files
 
 - convert/identify from ImageMagick for thumbnails,
-  transcode/mencoder for videos manipulation
+  mplayer for videos manipulation
 
 - ruby-gettext for i18n
 
index c644cb1..d48d600 100755 (executable)
--- a/bin/booh
+++ b/bin/booh
@@ -142,7 +142,7 @@ It is generally available with the 'ImageMagick' software package.")), { :pos_ce
     if !system("which exif >/dev/null 2>/dev/null")
         show_popup($main_window, utf8(_("The program 'exif' is needed to view EXIF data. Please install it.")), { :pos_centered => true })
     end
-    missing = %w(transcode mencoder).delete_if { |prg| system("which #{prg} >/dev/null 2>/dev/null") }
+    missing = %w(mplayer).delete_if { |prg| system("which #{prg} >/dev/null 2>/dev/null") }
     if missing != []
         show_popup($main_window, utf8(_("The following program(s) are needed to handle videos: '%s'. Videos will be ignored.") % missing.join(', ')), { :pos_centered => true })
     end
@@ -516,19 +516,19 @@ def enhance(xmldir, attributes_prefix)
     end
 end
 
-def change_frame_offset(xmldir, attributes_prefix, value)
+def change_seektime(xmldir, attributes_prefix, value)
     $modified = true
-    xmldir.add_attribute("#{attributes_prefix}frame-offset", value)
+    xmldir.add_attribute("#{attributes_prefix}seektime", value)
 end
 
-def ask_new_frame_offset(xmldir, attributes_prefix)
+def ask_new_seektime(xmldir, attributes_prefix)
     if xmldir
-        value = xmldir.attributes["#{attributes_prefix}frame-offset"]
+        value = xmldir.attributes["#{attributes_prefix}seektime"]
     else
         value = ''
     end
 
-    dialog = Gtk::Dialog.new(utf8(_("Change frame offset")),
+    dialog = Gtk::Dialog.new(utf8(_("Change seek time")),
                              $main_window,
                              Gtk::Dialog::MODAL | Gtk::Dialog::DESTROY_WITH_PARENT,
                              [Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK],
@@ -536,8 +536,8 @@ def ask_new_frame_offset(xmldir, attributes_prefix)
 
     lbl = Gtk::Label.new
     lbl.markup = utf8(
-_("Please specify the <b>frame offset</b> of the video, to take the thumbnail
-from. There are approximately 25 frames per second in a video.
+_("Please specify the <b>seek time</b> of the video, to take the thumbnail
+from, in seconds.
 "))
     dialog.vbox.add(lbl)
     dialog.vbox.add(entry = Gtk::Entry.new.set_text(value))
@@ -561,7 +561,7 @@ from. There are approximately 25 frames per second in a video.
         dialog.destroy
         if response == Gtk::Dialog::RESPONSE_OK
             $modified = true
-            msg 3, "changing frame offset to #{newval}"
+            msg 3, "changing seektime to #{newval}"
             return { :old => value, :new => newval }
         else
             return nil
@@ -936,21 +936,21 @@ def popup_thumbnail_menu(event, optionals, fullpath, type, xmldir, attributes_pr
     if type == 'video'
         if !possible_actions[:can_multiple] || $selected_elements.length == 0 || $selected_elements.reject { |k,v| $name2widgets[k][:type] == 'video' }.empty?
             menu.append(Gtk::SeparatorMenuItem.new)
-            menu.append(color_swap = Gtk::ImageMenuItem.new(utf8(_("Red/blue color swap"))))
-            color_swap.image = Gtk::Image.new("#{$FPATH}/images/stock-color-triangle-16.png")
-            color_swap.signal_connect('activate') { distribute_multiple_call.call(:color_swap) }
+#            menu.append(color_swap = Gtk::ImageMenuItem.new(utf8(_("Red/blue color swap"))))
+#            color_swap.image = Gtk::Image.new("#{$FPATH}/images/stock-color-triangle-16.png")
+#            color_swap.signal_connect('activate') { distribute_multiple_call.call(:color_swap) }
             menu.append(flip = Gtk::ImageMenuItem.new(utf8(_("Flip upside-down"))))
             flip.image = Gtk::Image.new("#{$FPATH}/images/stock-rotate-180-16.png")
             flip.signal_connect('activate') { distribute_multiple_call.call(:rotate, 180) }
-            menu.append(frame_offset = Gtk::ImageMenuItem.new(utf8(_("Specify frame offset"))))
-            frame_offset.image = Gtk::Image.new("#{$FPATH}/images/stock-video-16.png")
-            frame_offset.signal_connect('activate') {
+            menu.append(seektime = Gtk::ImageMenuItem.new(utf8(_("Specify seek time"))))
+            seektime.image = Gtk::Image.new("#{$FPATH}/images/stock-video-16.png")
+            seektime.signal_connect('activate') {
                 if possible_actions[:can_multiple] && $selected_elements.length > 0
-                    if values = ask_new_frame_offset(nil, '')
-                        distribute_multiple_call.call(:frame_offset, values)
+                    if values = ask_new_seektime(nil, '')
+                        distribute_multiple_call.call(:seektime, values)
                     end
                 else
-                    closures[:frame_offset].call
+                    closures[:seektime].call
                 end
             }
         end
@@ -1199,22 +1199,22 @@ def add_thumbnail(autotable, filename, type, thumbnail_img, caption)
                   })
     }
 
-    change_frame_offset_and_cleanup_real = proc { |values|
-        perform_change_frame_offset_and_cleanup = proc { |val|
+    change_seektime_and_cleanup_real = proc { |values|
+        perform_change_seektime_and_cleanup = proc { |val|
             cleanup_all_thumbnails.call
-            change_frame_offset($xmldir.elements["*[@filename='#{filename}']"], '', val)
+            change_seektime($xmldir.elements["*[@filename='#{filename}']"], '', val)
             my_gen_real_thumbnail.call
         }
-        perform_change_frame_offset_and_cleanup.call(values[:new])
+        perform_change_seektime_and_cleanup.call(values[:new])
         
-        save_undo(_("specify frame offset"),
+        save_undo(_("specify seektime"),
                   proc {
-                      perform_change_frame_offset_and_cleanup.call(values[:old])
+                      perform_change_seektime_and_cleanup.call(values[:old])
                       textview.grab_focus
                       autoscroll_if_needed($autotable_sw, img, textview)
                       $notebook.set_page(1)
                       proc {
-                          perform_change_frame_offset_and_cleanup.call(values[:new])
+                          perform_change_seektime_and_cleanup.call(values[:new])
                           textview.grab_focus
                           autoscroll_if_needed($autotable_sw, img, textview)
                           $notebook.set_page(1)
@@ -1222,9 +1222,9 @@ def add_thumbnail(autotable, filename, type, thumbnail_img, caption)
                   })
     }
 
-    change_frame_offset_and_cleanup = proc {
-        if values = ask_new_frame_offset($xmldir.elements["*[@filename='#{filename}']"], '')
-            change_frame_offset_and_cleanup_real.call(values)
+    change_seektime_and_cleanup = proc {
+        if values = ask_new_seektime($xmldir.elements["*[@filename='#{filename}']"], '')
+            change_seektime_and_cleanup_real.call(values)
         end
     }
 
@@ -1418,7 +1418,7 @@ def add_thumbnail(autotable, filename, type, thumbnail_img, caption)
     }
 
     $name2closures[filename] = { :rotate => rotate_and_cleanup, :enhance => enhance_and_cleanup, :delete => delete, :cut => cut,
-                                 :color_swap => color_swap_and_cleanup, :frame_offset => change_frame_offset_and_cleanup_real,
+                                 :color_swap => color_swap_and_cleanup, :seektime => change_seektime_and_cleanup_real,
                                  :whitebalance => whitebalance_and_cleanup_real, :gammacorrect => gammacorrect_and_cleanup_real,
                                  :pano => change_pano_amount_and_cleanup_real, :refresh => refresh }
 
@@ -1537,7 +1537,7 @@ def add_thumbnail(autotable, filename, type, thumbnail_img, caption)
                                      { :can_left => x > 0, :can_right => next_ && autotable.get_current_pos(next_)[0] > x,
                                        :can_up => y > 0, :can_down => y < autotable.get_max_y, :can_multiple => true, :can_panorama => true },
                                      { :rotate => rotate_and_cleanup, :move => move, :color_swap => color_swap_and_cleanup, :enhance => enhance_and_cleanup,
-                                       :frame_offset => change_frame_offset_and_cleanup, :delete => delete, :whitebalance => whitebalance_and_cleanup,
+                                       :seektime => change_seektime_and_cleanup, :delete => delete, :whitebalance => whitebalance_and_cleanup,
                                        :cut => cut, :paste => paste, :view => proc { view_element(filename, { :delete => delete }) },
                                        :pano => change_pano_amount_and_cleanup, :refresh => refresh, :gammacorrect => gammacorrect_and_cleanup })
             end
@@ -2333,7 +2333,7 @@ def change_dir
                 old_rotate = xmldir.attributes["#{infotype}-rotate"]
                 old_color_swap = xmldir.attributes["#{infotype}-color-swap"]
                 old_enhance = xmldir.attributes["#{infotype}-enhance"]
-                old_frame_offset = xmldir.attributes["#{infotype}-frame-offset"]
+                old_seektime = xmldir.attributes["#{infotype}-seektime"]
 
                 new_file = fc.filename
                 msg 3, "new captionfile is: #{fc.filename}"
@@ -2343,7 +2343,7 @@ def change_dir
                     xmldir.delete_attribute("#{infotype}-rotate")
                     xmldir.delete_attribute("#{infotype}-color-swap")
                     xmldir.delete_attribute("#{infotype}-enhance")
-                    xmldir.delete_attribute("#{infotype}-frame-offset")
+                    xmldir.delete_attribute("#{infotype}-seektime")
                     my_gen_real_thumbnail.call
                 }
                 perform_changefile.call
@@ -2354,7 +2354,7 @@ def change_dir
                               xmldir.add_attribute("#{infotype}-rotate", old_rotate)
                               xmldir.add_attribute("#{infotype}-color-swap", old_color_swap)
                               xmldir.add_attribute("#{infotype}-enhance", old_enhance)
-                              xmldir.add_attribute("#{infotype}-frame-offset", old_frame_offset)
+                              xmldir.add_attribute("#{infotype}-seektime", old_seektime)
                               my_gen_real_thumbnail.call
                               $notebook.set_page(0)
                               proc {
@@ -2439,20 +2439,20 @@ def change_dir
                       })
         }
 
-        change_frame_offset_and_cleanup = proc {
-            if values = ask_new_frame_offset(xmldir, "#{infotype}-")
-                perform_change_frame_offset_and_cleanup = proc { |val|
-                    change_frame_offset(xmldir, "#{infotype}-", val)
+        change_seektime_and_cleanup = proc {
+            if values = ask_new_seektime(xmldir, "#{infotype}-")
+                perform_change_seektime_and_cleanup = proc { |val|
+                    change_seektime(xmldir, "#{infotype}-", val)
                     my_gen_real_thumbnail.call
                 }
-                perform_change_frame_offset_and_cleanup.call(values[:new])
+                perform_change_seektime_and_cleanup.call(values[:new])
 
-                save_undo(_("specify frame offset"),
+                save_undo(_("specify seektime"),
                           proc {
-                              perform_change_frame_offset_and_cleanup.call(values[:old])
+                              perform_change_seektime_and_cleanup.call(values[:old])
                               $notebook.set_page(0)
                               proc {
-                                  perform_change_frame_offset_and_cleanup.call(values[:new])
+                                  perform_change_seektime_and_cleanup.call(values[:new])
                                   $notebook.set_page(0)
                               }
                           })
@@ -2540,7 +2540,7 @@ def change_dir
                                        :can_up => counter > 1, :can_down => counter > 0 && counter < subalbums_counter,
                                        :can_top => counter > 1, :can_bottom => counter > 0 && counter < subalbums_counter },
                                      { :change => change_image, :move => move, :rotate => rotate_and_cleanup, :enhance => enhance_and_cleanup,
-                                       :color_swap => color_swap_and_cleanup, :frame_offset => change_frame_offset_and_cleanup, :whitebalance => whitebalance_and_cleanup,
+                                       :color_swap => color_swap_and_cleanup, :seektime => change_seektime_and_cleanup, :whitebalance => whitebalance_and_cleanup,
                                        :gammacorrect => gammacorrect_and_cleanup, :refresh => refresh })
             end
             if event.event_type == Gdk::Event::BUTTON2_PRESS && event.button == 1
index 9e2f6e2..14bdb9f 100755 (executable)
@@ -364,7 +364,7 @@ It is generally available with the 'ImageMagick' software package.")
 It is generally available with the 'ImageMagick' software package.")
         $no_identify = true
     end
-    missing = %w(transcode mencoder).delete_if { |prg| system("which #{prg} >/dev/null 2>/dev/null") }
+    missing = %w(mplayer).delete_if { |prg| system("which #{prg} >/dev/null 2>/dev/null") }
     if missing != []
         msg 1, _("the following program(s) are needed to handle videos: '%s'. Videos will be ignored.") % missing.join(', ')
         $ignore_videos = true
index 64a789b..b0bde2f 100644 (file)
@@ -133,7 +133,7 @@ def read_config
 end
 
 def check_config
-    missing = %w(transcode mencoder).delete_if { |prg| system("which #{prg} >/dev/null 2>/dev/null") }
+    missing = %w(mplayer).delete_if { |prg| system("which #{prg} >/dev/null 2>/dev/null") }
     if missing != []
         show_popup($main_window, utf8(_("The following program(s) are needed to handle videos: '%s'. Videos will be ignored.") % missing.join(', ')), { :pos_centered => true })
     end
index 45bbb8b..c370a8f 100644 (file)
@@ -19,6 +19,7 @@
 
 require 'iconv'
 require 'timeout'
+require 'tempfile'
 
 require 'rexml/document'
 
@@ -208,19 +209,6 @@ module Booh
         end
     end
 
-    #- grab the results of a command but don't sleep forever on a runaway process
-    def subproc_runaway_aware(command)
-        begin
-            timeout(10) {
-                return `#{command}`
-            }
-        rescue Timeout::Error    
-            msg 1, _("forgetting runaway process (transcode sucks again?)")
-            #- todo should slay transcode but dunno how to do that
-            return nil
-        end
-    end
-
     def get_image_size(fullpath)
         if !$no_identify
             if $sizes_cache.nil?
@@ -311,31 +299,28 @@ module Booh
         gen_thumbnails(orig, allow_background, dests, xmldirorelem, type + '-')
     end
 
-    def gen_video_thumbnail(orig, dest_dir, orig_base, colorswap, frame_offset)
-        transcode_options = ''
+    def gen_video_thumbnail(orig, colorswap, seektime)
         if colorswap
-            transcode_options += '-k '
+            #- ignored for the moment. is mplayer subject to blue faces problem?
+        end
+        #- it's not possible to specify a basename for the output jpeg file with mplayer (file will be named 00000001.jpg); as this can
+        #- be called from multiple threads, we must come up with a unique directory where to put the file
+        tmpfile = Tempfile.new("boohvideotmp")
+        tmpfile.close!
+        begin
+            Dir.mkdir(tmpdirname = tmpfile.path)
+        rescue Errno::EEXIST
+            raise "Tmp directory #{tmpfile.path} already exists"
         end
-        cmd = "mencoder '#{orig}' -nosound -ovc lavc -lavcopts vcodec=mjpeg -o '#{dest_dir}/#{orig_base}.avi' -frames #{frame_offset+26} -fps 25 >/dev/null 2>/dev/null"
+        cmd = "mplayer '#{orig}' -nosound -vo jpeg:outdir='#{tmpdirname}' -frames 1 -ss #{seektime} >/dev/null 2>/dev/null"
         msg 2, cmd
         system cmd
-        if File.exists?("#{dest_dir}/#{orig_base}.avi")
-            cmd = "transcode -a 0 -c #{frame_offset}-#{frame_offset+1} -i '#{dest_dir}/#{orig_base}.avi' -y jpg -o '#{dest_dir}/#{orig_base}.jpg' #{transcode_options} 2>&1"
-            msg 2, cmd
-            results = subproc_runaway_aware(cmd)
-            File.delete(File.join(dest_dir, "#{orig_base}.avi"))
-            if results =~ /skipping frames/ && results =~ /encoded 0 frames/
-                msg 0, _("specified frame-offset too large? max frame was: %s. that may also be another probleme. try another value.") % results.scan(/skipping frames \[000000-(\d+)\]/)[-1]
-                return false
-            elsif results =~ /V: import format.*unknown/ || !File.exists?("#{dest_dir}/#{orig_base}.jpg000000.jpg")
-                msg 0, _("could not extract first image of video %s encoded by mencoder") % "#{dest_dir}/#{orig_base}.avi"
-                return false
-            end
-        else
-            msg 0, _("could not make mencoder to encode %s to mjpeg") % orig
-            return false
+        if ! File.exists?("#{tmpdirname}/00000001.jpg")
+            msg 0, _("specified seektime too large? that may also be another probleme. try another value.")
+            Dir.rmdir(tmpdirname)
+            return nil
         end
-        return true
+        return tmpdirname
     end
 
     def gen_thumbnails(orig, allow_background, dests, felem, attributes_prefix)
@@ -394,12 +379,12 @@ module Booh
 
         elsif entry2type(orig) == 'video'
             if felem
-                #- frame-offset is an attribute that allows to specify which frame to use for the thumbnail
-                frame_offset = felem.attributes["#{attributes_prefix}frame-offset"]
-                if !frame_offset
-                    felem.add_attribute("#{attributes_prefix}frame-offset", frame_offset = "0")
+                #- seektime is an attribute that allows to specify where the frame to use for the thumbnail must be taken
+                seektime = felem.attributes["#{attributes_prefix}seektime"]
+                if ! seektime
+                    felem.add_attribute("#{attributes_prefix}seektime", seektime = "0")
                 end
-                frame_offset = frame_offset.to_i
+                seektime = seektime.to_f
                 if rotate = felem.attributes["#{attributes_prefix}rotate"]
                     convert_options += "-rotate #{rotate} "
                 end
@@ -407,43 +392,40 @@ module Booh
                     convert_options += ($config['convert-enhance'] || $convert_enhance) + " "
                 end
             end
-            orig_base = File.basename(dests[0]['filename']) + File.basename(orig)
-            orig_image = "#{dest_dir}/#{orig_base}.jpg000000.jpg"
-            if File.exists?(orig_image)
-                File.delete(orig_image)
-            end
             for dest in dests
-                if ! File.exists?(orig_image)
-                    if ! gen_video_thumbnail(orig, dest_dir, orig_base, felem && felem.attributes["#{attributes_prefix}color-swap"], frame_offset)
+                if ! File.exists?(dest['filename'])
+                    tmpdir = gen_video_thumbnail(orig, felem && felem.attributes["#{attributes_prefix}color-swap"], seektime)
+                    if tmpdir.nil?
                         return false
                     end
+                    tmpfile = "#{tmpdir}/00000001.jpg"
+                    alltmpfiles = [ tmpfile ]
                     if felem && whitebalance = felem.attributes["#{attributes_prefix}white-balance"]
                         if whitebalance.to_f != 0
-                            neworig = "#{dest_dir}/#{orig_base}-whitebalance#{whitebalance}.jpg"
-                            cmd = "booh-fix-whitebalance '#{orig_image}' '#{neworig}' #{whitebalance}"
+                            neworig = "#{tmpdir}/whitebalance#{whitebalance}.jpg"
+                            cmd = "booh-fix-whitebalance '#{tmpfile}' '#{neworig}' #{whitebalance}"
                             sys(cmd)
                             if File.exists?(neworig)
-                                orig_image = neworig
+                                tmpfile = neworig
+                                alltmpfiles << neworig
                             end
                         end
                     end
                     if felem && gammacorrect = felem.attributes["#{attributes_prefix}gamma-correction"]
                         if gammacorrect.to_f != 0
-                            neworig = "#{dest_dir}/#{orig_base}-gammacorrect#{gammacorrect}.jpg"
-                            cmd = "booh-gamma-correction '#{orig_image}' '#{neworig}' #{gammacorrect}"
+                            neworig = "#{tmpdir}/gammacorrect#{gammacorrect}.jpg"
+                            cmd = "booh-gamma-correction '#{tmpfile}' '#{neworig}' #{gammacorrect}"
                             sys(cmd)
                             if File.exists?(neworig)
-                                orig_image = neworig
+                                tmpfile = neworig
+                                alltmpfiles << neworig
                             end
                         end
                     end
+                    sys("#{$convert} #{convert_options}-size #{dest['size']} -resize #{dest['size']} '#{tmpfile}' '#{dest['filename']}'")
+                    alltmpfiles.each { |file| File.delete(file) }
+                    Dir.rmdir(tmpdir)
                 end
-                if !File.exists?(dest['filename'])
-                    sys("#{$convert} #{convert_options}-size #{dest['size']} -resize #{dest['size']} '#{orig_image}' '#{dest['filename']}'")
-                end
-            end
-            if neworig
-                File.delete(neworig)
             end
             return true
         end