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
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],
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))
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
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
})
}
- 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)
})
}
- 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
}
}
$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 }
{ :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
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}"
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
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 {
})
}
- 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)
}
})
: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
require 'iconv'
require 'timeout'
+require 'tempfile'
require 'rexml/document'
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?
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)
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
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