Projects
Multimedia
tovid
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 6
View file
tovid.changes
Changed
@@ -1,4 +1,11 @@ ------------------------------------------------------------------- +Sat Mar 14 15:34:58 UTC 2015 - aloisio@gmx.com + +- Update to 0.35 + * full changelog at http://tovid.wikia.com/wiki/Tovid_changelog +- Fixed build for 13.2 and newer + +------------------------------------------------------------------- Fri Dec 26 15:40:08 UTC 2014 - obs@botter.cc - Require /usr/bin/mkisofs instead of just mkisofs [PM-118]
View file
tovid.spec
Changed
@@ -10,13 +10,13 @@ Summary: Video conversion and DVD authoring tools Name: tovid -Version: 0.34 +Version: 0.35 Release: 0.pm.1 Group: Productivity/Multimedia/Video/Editors and Convertors -License: GNU General Public License version 2 or later (GPLv2 or later) +License: GPL-2.0+ Url: http://tovid.sourceforge.net/ # http://tovid.googlecode.com/files/tovid-%{version}.tar.gz -Source: tovid-%{version}.tar.bz2 +Source: tovid-%{version}.tar.gz Source90: %{name}-rpmlintrc BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root %if %suse_version > 1110 @@ -46,7 +46,11 @@ %endif Requires: python-cairo Requires: python-imaging -Requires: python-wxGTK +%if 0%{?suse_version} >= 1320 +Requires: python-wxGTK >= 3.0 +%else +Requires: python-wxGTK < 3.0 +%endif Requires: sox Requires: transcode Requires: vcdimager @@ -66,7 +70,11 @@ BuildRequires: normalize BuildRequires: python-cairo BuildRequires: python-imaging -BuildRequires: python-wxGTK +%if 0%{?suse_version} >= 1320 +BuildRequires: python-wxGTK >= 3.0 +%else +BuildRequires: python-wxGTK < 3.0 +%endif BuildRequires: sox BuildRequires: transcode BuildRequires: vcdimager
View file
tovid-0.34.tar.bz2/libtovid/author.py
Deleted
@@ -1,263 +0,0 @@ -"""This module is for authoring a DVD or (S)VCD using dvdauthor or vcdimager. -""" - -__all__ = [ - 'Disc', - 'Menu', - 'Video', - 'Group', - 'Titleset', - 'vcdimager_xml', - 'dvdauthor_xml', -] - -from libtovid import xml - - -### -### Supporting classes -### - -class Video: - """A video title for inclusion on a video disc. - """ - def __init__(self, filename, title=''): - self.filename = filename - self.title = title - self.chapters = [] - - -class Group: - """A group title for inclusion on a video disc. - """ - def __init__(self, filenames, title): - self.filenames = filenames - self.title = title - - -class Menu: - """A menu for navigating the titles on a video disc. - """ - def __init__(self, filename='', videos=None): - """Create a menu linking to the given `Video`\s.""" - self.filename = filename - self.videos = videos or [] - - def add(self, video): - """Add a `Video` to the Menu.""" - self.videos.append(video) - - -class Titleset: - """A group of `Video`\s, with an optional `Menu`. - """ - def __init__(self, menu=None, videos=None): - """Create a Titleset containing the given `Video`\s. - """ - self.menu = menu - self.videos = videos or [] - - def add(self, video): - """Add a `Video` to the Titleset.""" - self.videos.append(video) - - -class Disc: - """A video disc containing one or more `Titleset`\s, and an optional - top `Menu` for navigating to each Titleset. - - """ - def __init__(self, name='Untitled', format='dvd', tvsys='ntsc', - titlesets=None): - """Create a Disc with the given properties. - - format - 'vcd', 'svcd', or 'dvd' - tvsys - 'pal' or 'ntsc' - title - String containing the title of the disc - titlesets - List of `Titleset` objects - """ - self.name = name - self.format = format - self.tvsys = tvsys - self.topmenu = None - self.titlesets = titlesets or [] - - - -### -### Internal functions -### - -def _add_titleset(titleset, ts_id, segment_items, sequence_items, pbc): - """Add titleset content to a vcdimager XML structure. This function is - used internally, mainly to keep `vcdimager_xml` from being too long. - """ - menu = titleset.menu - videos = titleset.videos - # Add menu - if menu: - segment_items.add('segment-item', src=menu.filename, - id='seg-menu-%d' % ts_id) - # Add menu to pbc - selection = pbc.add('selection', id='select-menu-%d' % ts_id) - selection.add('bsn', '1') - # Link back to topmenu (not sure what'll happen if there isn't one...) - selection.add('return', ref='select-topmenu') - selection.add('loop', '0', jump_timing='immediate') - selection.add('play-item', ref='seg-menu-%d' % ts_id) - # Navigational links to titleset videos - for video_id in range(len(videos)): - selection.add('select', - ref='play-title-%d-%d' % (ts_id, video_id)) - # Add videos - for video_id, video in enumerate(videos): - # Add sequence items - sequence_item = sequence_items.add('sequence-item') - sequence_item.set(id='seq-title-%d-%d' % (ts_id, video_id), - src=video.filename) - # Add chapter entries - for chapterid, chapter in enumerate(video.chapters): - sequence_item.add('entry', chapter, id='chapter-%d' % chapterid) - # Add playlists to pbc - playlist = pbc.add('playlist') - playlist.set(id='play-title-%d-%d' % (ts_id, video_id)) - # Add prev/next links if appropriate - if 0 <= video_id < len(videos): - if 0 < video_id: - playlist.add('prev', - ref='play-title-%d-%d' % (ts_id, video_id-1)) - if video_id < len(videos) - 1: - playlist.add('next', - ref='play-title-%d-%d' % (ts_id, video_id+1)) - # Add a return link to the menu, if there is one - if menu: - playlist.add('return', ref='select-menu-%d' % ts_id) - playlist.add('wait', '0') - playlist.add('play-item', ref='seq-title-%d-%d' % (ts_id, video_id)) - - -### -### Exported functions -### - -def vcdimager_xml(disc): - """Return the vcdimager XML string for the given `Disc`. - """ - assert isinstance(disc, Disc) - # XML header (will be added later) - header = '<?xml version="1.0"?>\n' - header += '<!DOCTYPE videocd PUBLIC "-//GNU/DTD VideoCD//EN"\n' - header += ' "http://www.gnu.org/software/vcdimager/videocd.dtd">\n' - # Root videocd element - attributes = { - 'xmlns': 'http://www.gnu.org/software/vcdimager/1.0/', - 'class': disc.format} - if disc.format == 'vcd': - attributes['version'] = '2.0' - else: # SVCD - attributes['version'] = '1.0' - root = xml.Element('videocd') - root.set(**attributes) - # Add info block - info = root.add('info') - info.add('album-id', 'VIDEO_DISC') - info.add('volume-count', '1') - info.add('volume-number', '1') - info.add('restriction', '0') - # Add pvd block - pvd = root.add('pvd') - pvd.add('volume-id', 'VIDEO_DISC') - pvd.add('system-id', 'CD-RTOS CD-BRIDGE') - - # Add segment, sequence, and pbc - segment_items = root.add('segment-items') - sequence_items = root.add('sequence-items') - pbc = root.add('pbc') - # Add topmenu - if disc.topmenu: - segment_items.add('segment-item', src=disc.topmenu.filename, - id='seg-topmenu') - selection = pbc.add('selection', id='select-topmenu') - selection.add('bsn', '1') - selection.add('loop', '0', jump_timing='immediate') - selection.add('play-item', ref='seg-topmenu') - # Add titlesets - for ts_id, titleset in enumerate(disc.titlesets): - _add_titleset(titleset, ts_id, segment_items, sequence_items, pbc) - # If we're doing a topmenu, add a link to the titleset menu - if disc.topmenu: - selection.add('select', ref='select-menu-%d' % ts_id) - - # Return XML with header prepended - return header + str(root) + '\n' - - -def dvdauthor_xml(disc): - """Return the dvdauthor XML string for the given `Disc`. - """ - assert isinstance(disc, Disc) - # Root dvdauthor element - root = xml.Element('dvdauthor', dest=disc.name.replace(' ', '_')) - vmgm = root.add('vmgm') - # Add topmenu if present - if disc.topmenu: - menus = vmgm.add('menus') - menus.add('video') - pgc = menus.add('pgc', entry='title') - vob = pgc.add('vob', file=disc.topmenu.filename) - for index, titleset in enumerate(disc.titlesets): - if titleset.menu: - pgc.add('button', 'jump titleset %d menu;' % (index + 1)) - else: - pgc.add('button', 'jump titleset %d;' % (index + 1)) - # Add each titleset - for titleset in disc.titlesets: - menu = titleset.menu - ts = root.add('titleset') - # Add menu if present - if menu: - menus = ts.add('menus') - menus.add('video') - pgc = menus.add('pgc', entry='root') - vob = pgc.add('vob', file=menu.filename) - for index, video in enumerate(titleset.videos): - pgc.add('button', 'jump title %d;' % (index + 1)) - if disc.topmenu: - pgc.add('button', 'jump vmgm menu;') - titles = ts.add('titles') - # Add a pgc for each video - for video in titleset.videos: - pgc = titles.add('pgc') - vob = pgc.add('vob', file=video.filename) - if video.chapters: - vob.set(chapters=','.join(video.chapters)) - pgc.add('post', 'call menu;') - # Return XML string - return str(root) + '\n' - - -if __name__ == '__main__': - menu1 = Menu('menu1.mpg') - videos1 = [ - Video('video1.mpg'), - Video('video2.mpg'), - Video('video3.mpg')] - menu2 = Menu('menu2.mpg') - videos2 = [ - Video('video4.mpg'), - Video('video5.mpg'), - Video('video6.mpg')] - titlesets = [ - Titleset(menu1, videos1), - Titleset(menu2, videos2)] - disc = Disc('dvd_test', 'dvd', 'ntsc', titlesets) - - print("dvdauthor XML example:") - print(dvdauthor_xml(disc)) - - print("vcdimager XML example:") - print(vcdimager_xml(disc))
View file
tovid-0.34.tar.bz2/libtovid/backend
Deleted
-(directory)
View file
tovid-0.34.tar.bz2/libtovid/backend/__init__.py
Deleted
@@ -1,7 +0,0 @@ -"""Backends, which do some task using a command-line program. - -This module is split into submodules, each named after the command-line -program they predominantly rely on. Backends which use several of these -submodules may be defined here in ``__init__.py``. -""" -
View file
tovid-0.34.tar.bz2/libtovid/backend/ffmpeg.py
Deleted
@@ -1,179 +0,0 @@ -"""Video encoding and identification using ``ffmpeg``. -""" - -__all__ = [ - 'encode', - 'encode_audio', - 'identify', -] - -import re -from libtovid import log -from libtovid import cli - -def encode(source, target, **kw): - """Encode a multimedia video using ffmpeg. - - source - Input `~libtovid.media.MediaFile` - target - Output `~libtovid.media.MediaFile` - kw - Keyword arguments to customize encoding behavior - - Supported keywords: - - quant - Minimum quantization, from 1-31 (1 being fewest artifacts) - vbitrate - Maximum video bitrate, in kilobits per second. - abitrate - Audio bitrate, in kilobits per second - interlace - 'top' or 'bottom', to do interlaced encoding with - top or bottom field first - - For example:: - - ffmpeg_encode(source, target, quant=4, vbitrate=7000) - """ - cmd = cli.Command('ffmpeg', '-y', '-i', source.filename) - - # Use format/tvsys that ffmpeg knows about - if target.format in ['vcd', 'svcd', 'dvd']: - cmd.add('-tvstd', target.tvsys, - '-target', '%s-%s' % (target.tvsys, target.format)) - - # Interpret keyword arguments - if 'quant' in kw: - cmd.add('-qmin', kw['quant'], '-qmax', 31) - if 'vbitrate' in kw: - cmd.add('-b', '%dk' % kw['vbitrate']) - if 'abitrate' in kw: - cmd.add('-ab', '%dk' % kw['abitrate']) - if 'interlace' in kw: - if kw['interlace'] == 'bottom': - cmd.add('-top', 0, '-flags', '+alt+ildct+ilme') - elif kw['interlace'] == 'top': - cmd.add('-top', 1, '-flags', '+alt+ildct+ilme') - - # Frame rate and audio sampling rate - cmd.add('-r', target.fps, - '-ar', target.samprate) - - # Convert scale/expand to ffmpeg's padding system - if target.scale: - cmd.add('-s', '%sx%s' % target.scale) - # Letterbox if necessary - if target.expand != target.scale: - e_width, e_height = target.expand - s_width, s_height = target.scale - h_pad = (e_width - s_width) / 2 - v_pad = (e_height - s_height) / 2 - if h_pad > 0: - cmd.add('-padleft', h_pad, '-padright', h_pad) - if v_pad > 0: - cmd.add('-padtop', v_pad, '-padbottom', v_pad) - - # Aspect - if target.widescreen: - cmd.add('-aspect', '16:9') - else: - cmd.add('-aspect', '4:3') - - cmd.add(target.filename) - cmd.run() - - -def encode_audio(source, audiofile, target): - """Encode the audio stream in a source file to a target format, saving - to the given filename. - - source - Input `~libtovid.media.MediaFile` - audiofile - Filename for encoded audio - target - Output `~libtovid.media.MediaFile` - - If no audio is present in the source file, encode silence. - """ - cmd = cli.Command('ffmpeg') - - # If source has audio, encode it - if source.has_audio: - cmd.add('-i', source.filename) - # Otherwise, encode silence (minimum 4 seconds) - else: - cmd.add('-f', 's16le', '-i', '/dev/zero') - if source.length < 4: - cmd.add('-t', '4.0') - else: - cmd.add('-t', '%f' % source.length) - - cmd.add('-vn', '-ac', '2', '-ab', '224k') - cmd.add('-ar', target.samprate) - cmd.add('-acodec', target.acodec) - cmd.add('-y', audiofile) - - cmd.run() - - -from libtovid.media import MediaFile - -def identify(filename): - """Identify a video file using ffmpeg, and return a - `~libtovid.media.MediaFile` with the video's specifications. - """ - result = MediaFile(filename) - - cmd = cli.Command('ffmpeg', '-i', filename) - cmd.run(capture=True) - - # ffmpeg puts its output on stderr - output = cmd.get_errors() - - video_line = re.compile('' - 'Stream (?P<tracknum>[^:]+): Video: ' # Track number (ex. #0.0) - '(?P<vcodec>[^,]+), ' # Video codec (ex. mpeg4) - '(?P<colorspace>[^,]+), ' # Color space (ex. yuv420p) - '(?P<width>\d+)x(?P<height>\d+), ' # Resolution (ex. 720x480) - '((?P<vbitrate>\d+) kb/s, )?' # Video bitrate (ex. 8000 kb/s) - '(?P<fps>[\d.]+)') # FPS (ex. 29.97 fps(r)) - - audio_line = re.compile('' - 'Stream (?P<tracknum>[^:]+): Audio: ' # Track number (ex. #0.1) - '(?P<acodec>[^,]+), ' # Audio codec (ex. mp3) - '(?P<samprate>\d+) Hz, ' # Sampling rate (ex. 44100 Hz) - '(?P<channels>[^,]+), ' # Channels (ex. stereo) - '(?P<abitrate>\d+) kb/s') # Audio bitrate (ex. 128 kb/s) - - # Parse ffmpeg output and set MediaFile attributes - for line in output.split('\n'): - video_match = video_line.search(line) - audio_match = audio_line.search(line) - - if video_match: - m = video_match - result.vcodec = m.group('vcodec') - result.scale = (int(m.group('width')), - int(m.group('height'))) - result.expand = result.scale - result.fps = float(m.group('fps')) - if m.group('vbitrate'): - result.vbitrate = int(m.group('vbitrate')) - - elif audio_match: - m = audio_match - result.acodec = m.group('acodec') - result.samprate = int(m.group('samprate')) - result.abitrate = int(m.group('abitrate')) - if m.group('channels') == '5.1': - result.channels = 6 - elif m.group('channels') == 'stereo': - result.channels = 2 - else: - result.channels = 1 - - return result -
View file
tovid-0.34.tar.bz2/libtovid/backend/mpeg2enc.py
Deleted
@@ -1,220 +0,0 @@ -"""Video and frame encoding using ``mpeg2enc``. -""" - -__all__ = [ - 'encode', - 'encode_video', - 'encode_frames', -] - -# TODO: Filter out some of the inter-backend dependencies - -import os, glob -from libtovid import log -from libtovid import util -from libtovid import cli -from libtovid.backend import mplex, mplayer, ffmpeg - -def encode(source, target, **kw): - """Encode a multimedia video using mplayer|yuvfps|mpeg2enc. - - source - Input `~libtovid.media.MediaFile` - target - Output `~libtovid.media.MediaFile` - kw - Keyword arguments to customize encoding behavior - - Supported keywords: - - None yet - - """ - log.warning("This encoder is very experimental, and may not work.") - - outname = target.filename - # YUV raw video FIFO, for piping video from mplayer to mpeg2enc - yuvfile = '%s.yuv' % outname - if os.path.exists(yuvfile): - os.remove(yuvfile) - - # Filenames for intermediate streams (ac3/m2v etc.) - # Appropriate suffix for audio stream - if target.format in ['vcd', 'svcd']: - audiofile = '%s.mp2' % outname - else: - audiofile = '%s.ac3' % outname - # Appropriate suffix for video stream - if target.format == 'vcd': - videofile = '%s.m1v' % outname - else: - videofile = '%s.m2v' % outname - # Do audio - ffmpeg.encode_audio(source, audiofile, target) - # Do video - mplayer.rip_video(source, yuvfile, target) - encode_video(source, yuvfile, videofile, target) - # Combine audio and video - mplex.mux(videofile, audiofile, target) - - - -def encode_video(source, yuvfile, videofile, target): - """Encode a yuv4mpeg stream to an MPEG video stream. - - source - Input `~libtovid.media.MediaFile` - yuvfile - Filename of .yuv stream coming from mplayer - videofile - Filename of .m[1|2]v to write encoded video stream to - target - Output `~libtovid.media.MediaFile` - - """ - # TODO: Control over quality (bitrate/quantization) and disc split size, - # corresp. to $VID_BITRATE, $MPEG2_QUALITY, $DISC_SIZE, etc. - # Missing options (compared to tovid) - # -S 700 -B 247 -b 2080 -v 0 -4 2 -2 1 -q 5 -H -o FILE - pipe = cli.Pipe() - - # Feed the .yuv file into the pipeline - cat = cli.Command('cat', yuvfile) - pipe.add(cat) - - # Adjust framerate if necessary by piping through yuvfps - if source.fps != target.fps: - log.info("Adjusting framerate") - yuvfps = cli.Command('yuvfps') - yuvfps.add('-r', util.float_to_ratio(target.fps)) - pipe.add(yuvfps) - - # Encode the resulting .yuv stream by piping into mpeg2enc - mpeg2enc = cli.Command('mpeg2enc') - # TV system - if target.tvsys == 'pal': - mpeg2enc.add('-F', '3', '-n', 'p') - elif target.tvsys == 'ntsc': - mpeg2enc.add('-F', '4', '-n', 'n') - # Format - format = target.format - if format == 'vcd': - mpeg2enc.add('-f', '1') - elif format == 'svcd': - mpeg2enc.add('-f', '4') - elif 'dvd' in format: - mpeg2enc.add('-f', '8') - # Aspect ratio - if target.widescreen: - mpeg2enc.add('-a', '3') - else: - mpeg2enc.add('-a', '2') - mpeg2enc.add('-o', videofile) - pipe.add(mpeg2enc) - - # Run the pipeline to encode the video stream - pipe.run() - - -# -------------------------------------------------------------------------- -# -# Frame encoder -# -# -------------------------------------------------------------------------- -from libtovid import standard - -def encode_frames(imagedir, outfile, format, tvsys, aspect, interlaced=False): - """Convert an image sequence in the given directory to match a target - `~libtovid.media.MediaFile`, putting the output stream in outfile. - - imagedir - Directory containing images (and only images) - outfile - Filename for output. - tvsys - TVsys desired for output (to deal with FPS) - aspect - Aspect ratio ('4:3', '16:9') - interlaced - Frames are interlaced material - - Currently supports JPG and PNG images; input images must already be - at the desired target resolution. - """ - - # Use absolute path name - imagedir = os.path.abspath(imagedir) - print("Creating video stream from image sequence in %s" % imagedir) - # Determine image type - images = glob.glob("%s/*" % imagedir) - extension = images[0][-3:] - if extension not in ['jpg', 'png']: - raise ValueError("Image format '%s' isn't currently supported to " - "render video from still frames" % extension) - # Make sure remaining image files have the same extension - for img in images: - if not img.endswith(extension): - raise ValueError("%s does not have a .%s extension" % - (img, extension)) - - pipe = cli.Pipe() - - # Use jpeg2yuv/png2yuv to stream images - if extension == 'jpg': - jpeg2yuv = cli.Command('jpeg2yuv') - - jpeg2yuv.add('-Ip') # Progressive - - jpeg2yuv.add('-f', '%.3f' % standard.fps(tvsys), - '-j', '%s/%%08d.%s' % (imagedir, extension)) - pipe.add(jpeg2yuv) - elif extension == 'png': - #ls = cli.Command('sh', '-c', 'ls %s/*.png' % imagedir) - #xargs = cli.Command('xargs', '-n1', 'pngtopnm') - png2yuv = cli.Command('png2yuv') - - png2yuv.add('-Ip') # Progressive - - - png2yuv.add('-f', '%.3f' % standard.fps(tvsys), - '-j', '%s/%%08d.png' % (imagedir)) - - pipe.add(png2yuv) - - #pipe.add(ls, xargs, png2yuv) - #cmd += 'pnmtoy4m -Ip -F %s %s/*.png' % standard.fps_ratio(tvsys) - - # TODO: Scale to correct target size using yuvscaler or similar - - # Pipe image stream into mpeg2enc to encode - mpeg2enc = cli.Command('mpeg2enc') - - # Anyways. - mpeg2enc.add('-I 0') # Progressive - - # Bottom-first, determined in render/drawing.py::interlace_drawings() - if (interlaced): - mpeg2enc.add('--playback-field-order', 'b') # Bottom-first field order - # conforming to drawing.py::interlace_drawings() - - mpeg2enc.add('-v', '0', - '-q' '3', - '-o' '%s' % outfile) - # Format - if format == 'vcd': - mpeg2enc.add('--format', '1') - elif format == 'svcd': - mpeg2enc.add('--format', '4') - else: - mpeg2enc.add('--format', '8') - # Aspect ratio - if aspect == '16:9': - mpeg2enc.add('-a', '3') - elif aspect == '4:3': - mpeg2enc.add('-a', '2') - - pipe.add(mpeg2enc) - - pipe.run(capture=True) - pipe.get_output() # and wait :) -
View file
tovid-0.34.tar.bz2/libtovid/backend/mplayer.py
Deleted
@@ -1,211 +0,0 @@ -"""Video encoding, ripping, and identification using ``mplayer``. -""" - -__all__ = [ - 'encode', - 'identify', - 'rip_video', -] - -from libtovid import log -from libtovid import cli -from libtovid.media import MediaFile -from libtovid.backend import ffmpeg - -def encode(source, target, **kw): - """Encode a multimedia video using mencoder. - - source - Input `~libtovid.media.MediaFile` - target - Output `~libtovid.media.MediaFile` - kw - Keyword arguments to customize encoding behavior - - Supported keywords: - - None yet - - """ - cmd = cli.Command('mencoder') - cmd.add(source.filename, - '-o', target.filename, - '-oac', 'lavc', - '-ovc', 'lavc', - '-of', 'mpeg') - # Format - cmd.add('-mpegopts') - if target.format in ['vcd', 'svcd']: - cmd.add('format=x%s' % target.format) - else: - cmd.add('format=dvd') - - # FIXME: This assumes we only have ONE audio track. - if source.has_audio: - # Adjust audio sampling rate if necessary - if source.samprate != target.samprate: - log.info("Resampling needed to achieve %d Hz" % target.samprate) - cmd.add('-srate', target.samprate) - cmd.add('-af', 'lavcresample=%s' % target.samprate) - else: - log.info("No resampling needed, already at %d Hz" % target.samprate) - - else: - log.info("No audio file, generating silence of %f seconds." % \ - source.length) - # Generate silence. - if target.format in ['vcd', 'svcd']: - audiofile = '%s.mpa' % target.filename - else: - audiofile = '%s.ac3' % target.filename - ffmpeg.encode_audio(source, audiofile, target) - # TODO: make this work, it's still not adding the ac3 file correctly. - cmd.add('-audiofile', audiofile) - - # Video codec - if target.format == 'vcd': - lavcopts = 'vcodec=mpeg1video' - else: - lavcopts = 'vcodec=mpeg2video' - # Audio codec - lavcopts += ':acodec=%s' % target.acodec - lavcopts += ':abitrate=%s:vbitrate=%s' % \ - (target.abitrate, target.vbitrate) - # Maximum video bitrate - lavcopts += ':vrc_maxrate=%s' % target.vbitrate - if target.format == 'vcd': - lavcopts += ':vrc_buf_size=327' - elif target.format == 'svcd': - lavcopts += ':vrc_buf_size=917' - else: - lavcopts += ':vrc_buf_size=1835' - # Set appropriate target aspect - if target.widescreen: - lavcopts += ':aspect=16/9' - else: - lavcopts += ':aspect=4/3' - # Pass all lavcopts together - cmd.add('-lavcopts', lavcopts) - - # FPS - if target.tvsys == 'pal': - cmd.add('-ofps', '25/1') - elif target.tvsys == 'ntsc': - cmd.add('-ofps', '30000/1001') # ~= 29.97 - - # Scale/expand to fit target frame - if target.scale: - vfilter = 'scale=%s:%s' % target.scale - # Expand is not done unless also scaling - if target.expand != target.scale: - vfilter += ',expand=%s:%s' % target.expand - cmd.add('-vf', vfilter) - - cmd.run() - - -def identify(filename): - """Identify a video file using mplayer, and return a - `~libtovid.media.MediaFile` with the video's specifications. - """ - # TODO: Raise an exception if the file couldn't be identified - # TODO: Infer aspect ratio - - media = MediaFile(filename) - - mp_dict = {} - # Use mplayer - cmd = cli.Command('mplayer', - '-identify', - '%s' % filename, - '-vo', 'null', - '-ao', 'null', - '-frames', '1', - '-channels', '6') - cmd.run(capture=True) - - # Look for mplayer's "ID_..." lines and include each assignment in mp_dict - for line in cmd.get_output().splitlines(): - log.debug(line) - if line.startswith("ID_"): - left, right = line.split('=') - mp_dict[left] = right.strip() - - # Check for existence of streams - if 'ID_VIDEO_ID' in mp_dict: - media.has_video = True - else: - media.has_video = False - if 'ID_AUDIO_ID' in mp_dict: - media.has_audio = True - else: - media.has_audio = False - - # Parse the dictionary and set appropriate values - for left, right in mp_dict.iteritems(): - if left == "ID_VIDEO_WIDTH": - media.scale = (int(right), media.scale[1]) - elif left == "ID_VIDEO_HEIGHT": - media.scale = (media.scale[0], int(right)) - elif left == "ID_VIDEO_FPS": - media.fps = float(right) - elif left == "ID_VIDEO_FORMAT": - media.vcodec = right - elif left == "ID_VIDEO_BITRATE": - media.vbitrate = int(right) / 1000 - elif left == "ID_AUDIO_CODEC": - media.acodec = right - elif left == "ID_AUDIO_FORMAT": - pass - elif left == "ID_AUDIO_BITRATE": - media.abitrate = int(right) / 1000 - elif left == "ID_AUDIO_RATE": - media.samprate = int(right) - elif left == "ID_AUDIO_NCH": - media.channels = right - elif left == 'ID_LENGTH': - media.length = float(right) - media.expand = media.scale - - # Fix mplayer's audio codec naming for ac3 and mp2 - if media.acodec == "8192": - media.acodec = "ac3" - elif media.acodec == "80": - media.acodec = "mp2" - # Fix mplayer's video codec naming for mpeg1 and mpeg2 - if media.vcodec == "0x10000001": - media.vcodec = "mpeg1" - elif media.vcodec == "0x10000002": - media.vcodec = "mpeg2" - return media - - - - -def rip_video(source, yuvfile, target): - """Rip video to the given yuv4mpeg file. - - source - Input `~libtovid.media.MediaFile` - yuvfile - File to put ripped video in - target - Output `~libtovid.media.MediaFile` - - """ - # TODO: Custom mplayer options, subtitles, interlacing, - # corresp. to $MPLAYER_OPT, $SUBTITLES, $VF_PRE/POST, $YUV4MPEG_ILACE, - # etc. - cmd = cli.Command('mplayer') - cmd.add(source.filename) - cmd.add('-vo', 'yuv4mpeg:file=%s' % yuvfile) - cmd.add('-nosound', '-benchmark', '-noframedrop') - # TODO: Support subtitles. For now, use default tovid behavior. - cmd.add('-noautosub') - if target.scale: - cmd.add('-vf', 'scale=%s:%s' % target.scale) - if target.expand > target.scale: - cmd.add('-vf-add', 'expand=%s:%s' % target.expand) - # Run the command to rip the video - cmd.run(background=True) -
View file
tovid-0.34.tar.bz2/libtovid/backend/mplex.py
Deleted
@@ -1,38 +0,0 @@ -"""Multiplexing using ``mplex``. -""" - -__all__ = [ - 'mux', -] - -from libtovid import cli - -def mux(vstream, astream, target): - """Multiplex audio and video stream files to the given target. - - vstream - Filename of MPEG video stream - astream - Filename of MP2/AC3 audio stream - target - Profile of output file - - """ - cmd = cli.Command('mplex') - format = target.format - if format == 'vcd': - cmd.add('-f', '1') - elif format == 'dvd-vcd': - cmd.add('-V', '-f', '8') - elif format == 'svcd': - cmd.add('-V', '-f', '4', '-b', '230') - elif format == 'half-dvd': - cmd.add('-V', '-f', '8', '-b', '300') - elif format == 'dvd': - cmd.add('-V', '-f', '8', '-b', '400') - # elif format == 'kvcd': - # cmd += ' -V -f 5 -b 350 -r 10800 ' - cmd.add(vstream, astream, '-o', target.filename) - # Run the command to multiplex the streams - cmd.run() -
View file
tovid-0.34.tar.bz2/libtovid/backend/spumux.py
Deleted
@@ -1,180 +0,0 @@ -"""This module is for adding subtitles to MPEG video files using spumux. - -Defined here are two functions for adding subtitles to an MPEG file: - - `add_subpictures` - Add image files (``.png``) - `add_subtitles` - Add subtitle files (``.sub``, ``.srt`` etc.) - -Use these if you just want to add subpictures or subtitles, and don't want -to think much about the XML internals. -""" - -__all__ = [ - 'add_subpictures', - 'add_subtitles', -] - -import os -from libtovid import util -from libtovid import xml -from libtovid import cli -from libtovid.backend import mplayer - -# spumux XML elements and valid attributes -# -# subpictures -# stream -# textsub -# ['filename', -# 'characterset', -# 'fontsize', -# 'font', -# 'horizontal-alignment', -# 'vertical-alignment', -# 'left-margin', -# 'right-margin', -# 'subtitle-fps', -# 'movie-fps', -# 'movie-width', -# 'movie-height'] -# button -# ['name', -# 'x0', 'y0', # Upper-left corner, inclusively -# 'x1', 'y1', # Lower-right corner, exclusively -# 'up', 'down', 'left', 'right'] -# action -# ['name'] -# spu -# ['start', -# 'end', -# 'image', -# 'highlight', -# 'select', -# 'transparent', # color code -# 'force', # 'yes' (force display, required for menus) -# 'autooutline', # 'infer' -# 'outlinewidth', -# 'autoorder', # 'rows' or 'columns' -# 'xoffset', -# 'yoffset'] - -def _get_xml(textsub_or_spu): - """Return an XML string for the given Textsub or Spu element. - """ - subpictures = xml.Element('subpictures') - stream = subpictures.add('stream') - stream.add_child(textsub_or_spu) - return str(subpictures) - - -def _get_xmlfile(textsub_or_spu): - """Write spumux XML file for the given Textsub or Spu element, and - return the written filename. - """ - xmldata = _get_xml(textsub_or_spu) - xmlfile = open(util.temp_file(suffix=".xml"), 'w') - xmlfile.write(xmldata) - xmlfile.close() - return xmlfile.name - - -def _mux_subs(subtitle, movie_filename, stream_id=0): - """Run spumux to multiplex the given subtitle with an ``.mpg`` file. - - subtitle - Textsub or Spu element - movie_filename - Name of an ``.mpg`` file to multiplex subtitle into - stream_id - Stream ID number to pass to spumux - """ - # Create XML file for subtitle element - xmlfile = _get_xmlfile(subtitle) - # Create a temporary .mpg for the subtitled output - #base_dir = os.path.dirname(movie_filename) - subbed_filename = util.temp_file(suffix=".mpg") - # spumux xmlfile < movie_filename > subbed_filename - spumux = cli.Command('spumux', '-s%s' % stream_id, xmlfile.name) - spumux.run_redir(movie_filename, subbed_filename) - spumux.wait() - - # Remove old file - os.remove(movie_filename) - # Rename temporary file to new file - os.rename(subbed_filename, movie_filename) - # Remove the XML file - os.remove(xmlfile.name) - - -def add_subpictures(movie_filename, select, image=None, highlight=None): - """Adds ``.png`` subpictures to an ``.mpg`` video file to create a DVD menu. - - select - ``.png`` filename shown for the navigational selector or "cursor" - image - ``.png`` filename shown for non-selected regions - highlight - ``.png`` filename shown when "enter" is pressed - - All images must be indexed, 4-color, transparent, non-antialiased PNG. - Button regions are auto-inferred. - """ - spu = xml.Element('spu') - spu.set(start='0', - force='yes', - select=select, - image=image, - highlight=highlight) - # TODO Find a good default outlinewidth - spu.set(autooutline='infer', outlinewidth='10') - # TODO: Support explicit button regions - _mux_subs(spu, movie_filename) - - -def add_subtitles(movie_filename, sub_filenames): - """Adds one or more subtitle files to an ``.mpg`` video file. - - movie_filename - Name of ``.mpg`` file to add subtitles to - sub_filenames - Filename or list of filenames of subtitle - files to include (``.sub``, ``.srt`` etc.) - - """ - infile = mplayer.identify(movie_filename) - width, height = infile.scale - - # Convert sub_filenames to list if necessary - if type(sub_filenames) == str: - sub_filenames = [sub_filenames] - # spumux each subtitle file with its own stream ID - for stream_id, sub_filename in enumerate(sub_filenames): - # <textsub attribute="value" .../> - textsub = xml.Element('textsub') - textsub.set(movie_fps=infile.fps, - movie_width=width, - movie_height=height, - filename=sub_filename) - _mux_subs(textsub, movie_filename, stream_id) - - - -if __name__ == '__main__': - print("spumux XML examples") - - print("Subpicture example:") - spu = xml.Element('spu') - spu.add('button', name='but1', down='but2') - spu.add('button', name='but2', up='but1') - print(_get_xml(spu)) - - print("Text subtitle example:") - textsub = xml.Element('textsub') - textsub.set(filename='foo.sub', - fontsize=14.0, - font="Luxi Mono") - print(_get_xml(textsub)) - -
View file
tovid-0.34.tar.bz2/libtovid/backend/transcode.py
Deleted
@@ -1,119 +0,0 @@ -"""Video frame ripping and video identification using ``transcode``. -""" - -# Sample output from tcprobe: -# -# [tcprobe] RIFF data, AVI video -# [avilib] V: 24.000 fps, codec=DIVX, frames=15691, width=1024, height=576 -# [avilib] A: 48000 Hz, format=0x2000, bits=0, channels=5, bitrate=448 kbps, -# [avilib] 10216 chunks, 36614144 bytes, CBR -# [tcprobe] summary for Elephants_1024.avi, (*) = not default, 0 = not -# detected -# import frame size: -g 1024x576 [720x576] (*) -# frame rate: -f 24.000 [25.000] frc=0 (*) -# audio track: -a 0 [0] -e 48000,0,5 [48000,16,2] -n 0x2000 [0x2000] (*) -# bitrate=448 kbps -# length: 15691 frames, frame_time=41 msec, duration=0:10:53.790 - -__all__ = [ - 'identify', - 'rip_frames', -] - -import os, re, glob -from libtovid import log -from libtovid import cli -from libtovid.media import MediaFile - -def identify(filename): - """Identify a video file using transcode (tcprobe), and return a - `~libtovid.media.MediaFile` with the video's specifications. - """ - result = MediaFile(filename) - - cmd = cli.Command('tcprobe', '-i', filename) - cmd.run(capture=True) - output = cmd.get_output() - - video_line = re.compile('V: ' - '(?P<fps>[\d.]+) fps, ' - 'codec=(?P<vcodec>[^,]+), ' - 'frames=\d+, ' - 'width=(?P<width>\d+), ' - 'height=(?P<height>\d+)') - - audio_line = re.compile('A: ' - '(?P<samprate>\d+) Hz, ' - 'format=(?P<acodec>[^,]+), ' - 'bits=\d+, ' - 'channels=(?P<channels>[^,]+), ' - 'bitrate=(?P<abitrate>\d+) kbps') - - for line in output.split('\n'): - if 'V: ' in line: - match = video_line.search(line) - result.fps = float(match.group('fps')) - result.vcodec = match.group('vcodec') - result.scale = (int(match.group('width')), - int(match.group('height'))) - result.expand = result.scale - - elif 'A: ' in line: - match = audio_line.search(line) - result.acodec = match.group('acodec') - result.samprate = int(match.group('samprate')) - result.abitrate = int(match.group('abitrate')) - result.channels = int(match.group('channels')) - - return result - - -def rip_frames(media, out_dir, frames='all', size=(0, 0)): - """Extract frame images from a `~libtovid.media.MediaFile` and return a - list of frame image files. - - media - `~libtovid.media.MediaFile` to extract images from - out_dir - Directory where output images should be stored; images are saved - in a subdirectory of ``out_dir`` named after the input filename - frames - Which frames to rip: ``'all'`` for all frames, ``15`` to rip frame - 15; ``[30, 90]`` to rip frames 30 through 90, etc. - size - Resolution of frame images (default: original size), used - for prescaling - - """ - out_dir = os.path.abspath(out_dir) - if os.path.exists(out_dir): - log.warning("Temp directory: %s already exists. Overwriting." % out_dir) - os.system('rm -rf "%s"' % out_dir) - os.mkdir(out_dir) - - # TODO: use tcdemux to generate a nav index, like: - # tcdemux -f 29.970 -W -i "$FILE" > "$NAVFILE" - - # Use transcode to rip frames - cmd = cli.Command('transcode', - '-i', '%s' % media.filename) - # Resize - if size != (0, 0): - cmd.add('-Z', '%sx%s' % size) - # Encode selected frames - if frames == 'all': - # transcode does all by default - pass - elif isinstance(frames, int): - # rip a single frame - cmd.add('-c', '%s-%s' % (frames, frames)) - elif isinstance(frames, list): - # rip a range of frames - cmd.add('-c', '%s-%s' % (frames[0], frames[-1])) - cmd.add('-y', 'jpg,null') - cmd.add('-o', '%s/frame_' % out_dir) - log.info("Creating image sequence from %s" % media.filename) - cmd.run() - - # Return a list of ripped files - return glob.glob('%s/frame_*.jpg' % out_dir)
View file
tovid-0.34.tar.bz2/libtovid/deps.py
Deleted
@@ -1,210 +0,0 @@ -"""This module is for verifying libtovid's run-time dependencies. -For example:: - - deps.require(deps.core) - -will look for all of tovid's core dependencies. If any cannot be found, the -missing ones are printed and an exception is raised. Run ``deps.py`` from a prompt -for further examples. - -In practice:: - - try: - deps.require(deps.core) - except deps.MissingDep: - print("Exiting...") - sys.exit(1) - -`deps.core` is an internal dictionary of tovid's core dependencies, where the -keys are the names, and the values are brief descriptions with URLs. - -Provided dependency dictionaries: - - core - grep/sed/md5sum, mplayer, mencoder, mpjpegtools, ffmpeg - magick - composite, convert - dvd - spumux, dvdauthor, growisofs - vcd - vcdxbuild, cdrdao - transcode - tcprobe, tcrequant - plugin - sox, normalize - all - ALL dependencies above - -If you don't want to use a provided dictionary, you can specify individual -program names to look for:: - - deps.require("more less cat") - -`require` also provides ways to print custom URLs and help when it cannot find -dependencies. See ``help(deps.require)`` or keep reading. -""" - -__all__ = [ - 'which', - 'require', - 'MissingDep', -] - -import subprocess -import textwrap - -from libtovid.util.output import red - -class MissingDep (Exception): - """Missing dependency exception.""" - pass - -### -### Module data -### - -# Dictionary format: {"name": "description (url)"} -all = {} - -core = { - "grep": "a GNU utility (www.gnu.org/software/grep)", - "sed": "a GNU utility (directory.fsf.org/GNU/software/sed.html)", - "md5sum": "a GNU utility (www.gnu.org/software/coreutils)", - "mplayer": "part of mplayer (www.mplayerhq.hu)", - "mencoder": "part of mplayer (www.mplayerhq.hu)", - "mplex": "part of mjpegtools (mjpeg.sf.net)", - "mpeg2enc": "part of mjpegtools (mjpeg.sf.net)", - "yuvfps": "part of mjpegtools (mjpeg.sf.net)", - "yuvdenoise": "part of mjpegtools (mjpeg.sf.net)", - "ppmtoy4m": "part of mjpegtools (mjpeg.sf.net)", - "mp2enc": "part of mjpegtools (mjpeg.sf.net)", - "jpeg2yuv": "part of mjpegtools (mjpeg.sf.net)", - "ffmpeg": "a video encoding utility (ffmpeg.mplayerhq.hu)" } -all.update(core) - -magick = { - "composite": "part of ImageMagick (www.imagemagick.org)", - "convert": "part of ImageMagick (www.imagemagick.org)" } -all.update(magick) - -dvd = { - "spumux": "part of dvdauthor (dvdauthor.sf.net)", - "dvdauthor": "part of dvdauthor (dvdauthor.sf.net)", - "growisofs": "part of dvd+rw-tools (fy.chalmers.se/~appro/linux/DVD+RW)"} -all.update(dvd) - -vcd = { - "vcdxbuild": "part of vcdimager (www.vcdimager.org)", - "cdrdao": "a cd burning application (cdrdao.sf.net)" } -all.update(vcd) - -transcode = { - "tcprobe": "part of transcode (www.transcoding.org)", - "tcrequant": "part of transcode (www.transcoding.org)" } -all.update(transcode) - -plugin = { - "sox": "swiss army knife for sound (sox.sf.net)", - "normalize": "wave gain and normalization (normalize.nongnu.org)" } -all.update(plugin) - -__missing_dependency_message = \ -"""Please install the above MISSING dependencies and try again. See -http://tovid.wikia.com/wiki/Tovid_dependencies for more help. -""" - -### -### Exported functions -### - -def which(executable): - """Locate the given executable program name on the current path. - If found, return the full pathname; otherwise, return the empty string. - """ - proc = subprocess.Popen(['which', executable], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - return proc.stdout.read().rstrip('\n') - -def require(deps, - help="You need these to finish what you were doing.", - description="oops"): - - """Assert that one or more dependencies exist on the system. If any - are missing, raise a `MissingDep` exception. - - deps - Names of dependencies to assert. May be a single name, - a python list or space-separated string list of names, - or a dictionary of the form {depname: description}. - help - A help message about why the dependencies are needed - description - A short description of the dep, and its homepage URL - (ignored if deps is a dictionary). - - If a given dependency name is found in one of the internal dictionaries, - (core, magick, etc.), its description is taken from there. - - Examples: - - require(all) - Look for ALL dependencies that are defined internally. - - require(core, "You are missing CORE dependencies!") - Use the core dictionary to determine which dependencies to - look for. Print the help message if any dependency is missing. - - require("xine", "You can't preview!", "a video player (xinehq.de)") - Check for xine and print the custom help and URL messages - if missing. - - require("mplayer mencoder", url="a video player (mplayerhq.hu)") - Look for mplayer and mencoder. Use the default help message, - but print a custom URL. - - """ - # Get the deps to check for: dictionary.keys(), or a list - if type(deps) == dict: - deps = deps.keys() - elif type(deps) == str: - deps = deps.split(' ') - elif type(deps) != list: - raise ValueError("%s is not dictionary, list, or string!" % str(deps)) - - # Find the missing dependencies - have_deps = True - for dep in deps: - if which(dep) == '': - if type(deps) == dict: - description = deps[dep] - elif dep in all: - description = all[dep] - # Tell the user which dependencies they're missing - print(red("MISSING:") + " %s, %s" % (dep, description)) - have_deps = False - - # Having reported the missing dependencies, print the help message and quit - if not have_deps: - print("\n", textwrap.fill(help + ' ' + __missing_dependency_message, 79)) - raise MissingDep("Cannot find required dependencies!") - - - -if __name__ == "__main__": - trials = [ - (core, "You are missing CORE dependencies!", "custom url 1"), - (core, "You are missing CORE dependencies!", "custom url 2"), - ("grp md5sm", "You're missing some vowels!", "custom url 4"), - ("foo", "heh, you don't have foo?!", "see foo.org") ] - - for dep, help, url in trials: - try: - print("================================================") - print("Starting test...") - require(dep, help, url) - except MissingDep: - print("(Would exit here.)\n") - else: - print("Test passed!\n") - -
View file
tovid-0.34.tar.bz2/libtovid/encode.py
Deleted
@@ -1,205 +0,0 @@ -"""Encode video to standard formats, using one of several supported backends. - -One high-level function is provided:: - - encode(infile, outfile, format, tvsys, method, **kwargs) - -For example:: - - encode('/video/foo.avi', '/video/bar.mpg', 'dvd', 'ntsc', 'ffmpeg') - -This will encode ``/video/foo.avi`` to NTSC DVD format using ffmpeg, saving -the result as ``/video/bar.mpg``. The ``format``, ``tvsys``, and ``method`` -arguments are optional; if you do:: - - encode('/video/foo.avi', '/video/bar.mpg') - -then encoding will be DVD NTSC, using ffmpeg. - -Keyword arguments may be used to further refine encoding behavior, for example:: - - encode('foo.avi', 'foo.mpg', 'dvd', 'pal', - quality=7, interlace='bottom', ...) - -The supported keywords may vary by backend, but some keywords are supported -by all backends. The available backends are: - - - `~libtovid.backend.ffmpeg` - - `~libtovid.backend.mplayer` - - `~libtovid.backend.mpeg2enc` - -""" - -__all__ = [ - 'encode', - 'eval_keywords', - 'fit', -] - -from libtovid.backend import ffmpeg, mplayer, mpeg2enc -from libtovid.media import MediaFile, standard_media, correct_aspect - - -_bitrate_limits = { - 'vcd': (1150, 1150), - 'kvcd': (400, 4000), - 'dvd-vcd': (400, 4000), - 'svcd': (900, 2400), - 'half-dvd': (600, 6000), - 'dvd': (900, 9000) - } - -# -------------------------------------------------------------------------- -# -# Primary interface -# -# -------------------------------------------------------------------------- - -def encode(infile, outfile, format='dvd', tvsys='ntsc', method='ffmpeg', - **kwargs): - """Encode a multimedia file ``infile`` according to a target profile, - saving the encoded file to ``outfile``. - - infile - Input filename - outfile - Desired output filename (``.mpg`` implied) - format - One of 'vcd', 'svcd', 'dvd' (case-insensitive) - tvsys - One of 'ntsc', 'pal' (case-insensitive) - method - Encoding backend: `~libtovid.backend.ffmpeg`, - `~libtovid.backend.mplayer`, or `~libtovid.backend.mpeg2enc` - kwargs - Additional keyword arguments (name=value) - - For example:: - - encode('/video/foo.avi', '/video/bar.mpg', 'dvd', 'ntsc', 'ffmpeg') - - This will encode ``/video/foo.avi`` to NTSC DVD format using ffmpeg, saving - the result as '/video/bar.mpg'. The ``format``, ``tvsys``, and ``method`` - arguments are optional; if you do:: - - encode('/video/foo.avi', '/video/bar.mpg') - - then encoding will be DVD NTSC, using ffmpeg. - - Keyword arguments may be used to further refine encoding behavior, for example:: - - encode('foo.avi', 'foo.mpg', 'dvd', 'pal', - quality=7, interlace='bottom', ...) - - The supported keywords may vary by backend, but some keywords are supported - by all backends. - - - """ - source = mplayer.identify(infile) - # Add .mpg to outfile if not already present - if not outfile.endswith('.mpg'): - outfile += '.mpg' - # Get an appropriate encoding target - target = standard_media(format, tvsys) - target.filename = outfile - # Set desired aspect ratio, or auto - if 'aspect' in kwargs: - target = correct_aspect(source, target, kwargs['aspect']) - else: - target = correct_aspect(source, target, 'auto') - - # Some friendly output - print("Source media:") - print(source) - print(' ') - print("Target media:") - print(target) - - # Get the appropriate encoding backend - encode_method = get_encoder(method) - # Evaluate high-level keywords - kwargs = eval_keywords(source, target, **kwargs) - # Encode! - encode_method(source, target, **kwargs) - - -# -------------------------------------------------------------------------- -# -# Helper functions -# -# -------------------------------------------------------------------------- - -def _get_encoder(backend): - """Get an encoding function.""" - if backend == 'ffmpeg': - return ffmpeg.encode - elif backend in ['mplayer', 'mencoder']: - return mplayer.encode - elif backend == 'mpeg2enc': - return mpeg2enc.encode - - -def eval_keywords(source, target, **kwargs): - """Interpret keywords that affect other keywords, and return the result. - These are keywords that can be shared between multiple encoding backends. - - Supported keywords: - - quality - From 1 (lowest) to 10 (highest) video quality. - Overrides 'quant' and 'vbitrate' keywords. - fit - Size in MiB to fit output video to (overrides 'quality') - Overrides 'quant' and 'vbitrate' keywords. - - """ - # Set quant and vbitrate to match desired quality - if 'quality' in kwargs: - kwargs['quant'] = 13-kwargs['quality'] - max_bitrate = _bitrate_limits[target.format][1] - kwargs['vbitrate'] = kwargs['quality'] * max_bitrate / 10 - # Set quant and vbitrate to fit desired size - if 'fit' in kwargs: - kwargs['quant'], kwargs['vbitrate'] = \ - fit(source, target, kwargs['fit']) - return kwargs - - -def fit(source, target, fit_size): - """Return video (quantization, bitrate) to fit a video into a given size. - - source - `~libtovid.media.MediaFile` input (the video being encoded) - target - `~libtovid.media.MediaFile` output (desired target profile) - fit_size - Desired encoded file size, in MiB - - """ - assert isinstance(source, MediaFile) - assert isinstance(target, MediaFile) - fit_size = float(fit_size) - mpeg_overhead = fit_size / 100 - aud_vid_size = fit_size - mpeg_overhead - audio_size = float(source.length * target.abitrate) / (8*1024) - video_size = aud_vid_size - audio_size - vid_bitrate = int(video_size*8*1024 / source.length) - - print("Length: %s seconds" % source.length) - print("Overhead: %s MiB" % mpeg_overhead) - print("Audio: %s MiB" % audio_size) - print("Video: %s MiB" % video_size) - print("VBitrate: %s kbps" % vid_bitrate) - - # Keep bitrates sane for each disc format - lower, upper = _bitrate_limits[target.format] - quant = 3 - if vid_bitrate < lower: - return (quant, lower) - elif vid_bitrate > upper: - return (quant, upper) - else: - return (quant, vid_bitrate) - -
View file
tovid-0.34.tar.bz2/libtovid/media.py
Deleted
@@ -1,195 +0,0 @@ -"""This module provides a multimedia file class for storing a profile of -attributes including resolution, audio and video codecs and bitrates. - -These can be used for getting a target `MediaFile` for encoding via -one of the backends in :mod:`libtovid.backend`. For example:: - - >>> dvd = standard_media('dvd', 'ntsc') - >>> print(dvd) - Filename: - Format: DVD - TVsys: NTSC - Length: 0 seconds - Video: 720x480 29.97fps 4:3 mpeg2 6000kbps - Audio: ac3 224kbps 48000hz 2-channel - -""" - -__all__ = [ - 'MediaFile', - 'standard_media', - 'correct_aspect', -] - -import copy -from libtovid import log -from libtovid import standard -from libtovid.util import ratio_to_float - -# Analysis of MediaFile attributes -# -# acodec: ID, target -# abitrate: ID, target -# channels: ID -# samprate: ID, source, target -# vcodec: ID -# vbitrate: ID, target -# length: ID, source -# scale: (ID), (source), target -# expand: target -# fps: ID, source, target -# aspect: source -# widescreen: target -# -# -# Redundancies(?): -# widescreen/aspect -# scale/expand if aspect is known - -class MediaFile: - """A multimedia video file, and its vital statistics. - """ - def __init__(self, filename='', format='none', tvsys='none'): - log.debug("MediaFile(%s, %s, %s)" % (filename, format, tvsys)) - # TODO: Set attributes to match given format and tvsys - self.filename = filename - self.format = format - self.tvsys = tvsys - self.length = 0 - # TODO: Support multiple audio and video tracks - self.has_audio = False - self.has_video = False - # Audio attributes - self.acodec = 'none' - self.abitrate = 0 - self.channels = 0 - self.samprate = 0 - # Video attributes - self.vcodec = 'none' - # TODO: Better names for scale & expand, but not so long as - # 'inner_resolution' and 'outer_resolution', or - # 'picture_res' and 'frame_res'. Suggestions? - self.scale = (0, 0) - self.expand = (0, 0) - self.vbitrate = 0 - self.fps = 0.0 - self.aspect = '0:0' - self.widescreen = False - - - def __str__(self): - """Return a string representation of the MediaFile. - """ - width, height = self.expand or self.scale - # List of lines of output - lines = [ - 'Filename: %s' % self.filename, - 'Format: %s' % self.format, - 'TVsys: %s' % self.tvsys, - 'Length: %s seconds' % self.length, - 'Video: %sx%s %sfps %s %s %skbps' % \ - (width, height, self.fps, self.aspect, self.vcodec, self.vbitrate), - 'Audio: %s %skbps %shz %s-channel' % \ - (self.acodec, self.abitrate, self.samprate, self.channels) - ] - # Add newlines and return - return '\n'.join(lines) - - -def standard_media(format, tvsys): - """Return a `MediaFile` compliant with a standard format and TV system. - - format - Standard format ('vcd', 'svcd', or 'dvd') - tvsys - TV system ('pal' or 'ntsc') - - """ - log.debug("standard_media(%s, %s)" % (format, tvsys)) - media = MediaFile('', format, tvsys) - # Set valid video attributes - media.vcodec = standard.vcodec(format) - media.scale = standard.resolution(format, tvsys) - media.expand = media.scale - media.fps = standard.fps(tvsys) - # Set valid audio attributes - media.acodec = standard.acodec(format) - media.samprate = standard.samprate(format) - # TODO: How to handle default bitrates? These functions return a range. - #media.vbitrate = standard.vbitrate(format)[1] - #media.abitrate = standard.abitrate(format)[1] - media.abitrate = 224 - if format == 'vcd': - media.vbitrate = 1150 - elif format == 'svcd': - media.vbitrate = 2600 - else: - media.vbitrate = 6000 - return media - - -def correct_aspect(source, target, aspect='auto'): - """Calculate the necessary scaling to fit source into target at a given - aspect ratio, without distorting the picture. - - source - Input `MediaFile` - target - Output `MediaFile` - aspect - Aspect ratio to assume for input file (e.g., '4:3', '16:9') - or 'auto' to use autodetection based on source aspect - - Return a new target `MediaFile` with correct scaling, using letterboxing - if appropriate, and anamorphic widescreen if available (DVD only). - """ - assert isinstance(source, MediaFile) - assert isinstance(target, MediaFile) - - # Base new target on existing one - target = copy.copy(target) - - # Convert aspect (ratio) to a floating-point value - if aspect == 'auto': - src_aspect = ratio_to_float(source.aspect) - else: - src_aspect = ratio_to_float(aspect) - - # Use anamorphic widescreen for any video ~16:9 or wider - # (Only DVD supports this) - if src_aspect >= 1.7 and target.format == 'dvd': - target_aspect = 16.0/9.0 - widescreen = True - else: - target_aspect = 4.0/3.0 - widescreen = False - - # Start by assuming direct scaling to target resolution - width, height = target.scale - - # If aspect matches target, no letterboxing is necessary - tolerance = 0.05 - if abs(src_aspect - target_aspect) < tolerance: - scale = (width, height) - # If aspect is wider than target, letterbox vertically - elif src_aspect > target_aspect: - scale = (width, int(height * target_aspect / src_aspect)) - # Otherwise (rare), letterbox horizontally - else: - scale = (int(width * src_aspect / target_aspect), height) - - # Always expand to the target resolution - expand = (width, height) - - # If input file is already the correct size, don't scale - if scale == source.scale: - scale = False - - # Final scaling/expansion for correct aspect ratio display - target.scale = scale - target.expand = expand - target.widescreen = widescreen - return target - - -
View file
tovid-0.34.tar.bz2/libtovid/opts.py
Deleted
@@ -1,254 +0,0 @@ -# opts.py - -# WARNING: This module is a hack in progress - -__all__ = [ - 'Option', - 'Usage', - 'parse', - 'validate', -] - -import sys -import textwrap -from libtovid.odict import Odict -from libtovid.util import trim - -class Option (object): - """A command-line-style option, expected argument formatting, default value, - and notes on usage and purpose. - - For example:: - - debug_opt = Option( - 'debug', - 'none|some|all', - 'some', - "Amount of debugging information to display" - ) - - This defines a 'debug' option, along with a human-readable string showing - expected argument formatting, a default value, and a string documenting the - option's purpose and/or usage information. - """ - def __init__(self, name, argformat='', default=None, - doc='Undocumented option', alias=None, - required=False): - """Create a new option definition with the given attributes. - - name - Option name - argformat - String describing format of expected arguments - default - Default value, if any - doc - Manual-page-style documentation of the option - alias - An ('option', 'value') equivalent for this option - - """ - self.name = name - self.argformat = argformat - self.default = default - self.doc = trim(doc) - self.alias = alias - self.required = required - # If an alias was provided, generate documentation. - # i.e., alias=('tvsys', 'ntsc') means this option is the same as - # giving the 'tvsys' option with 'ntsc' as the argument. - if self.alias: - self.doc = 'Same as -%s %s.' % alias - - - def num_args(self): - """Return the number of arguments expected by this option, - or -1 if unlimited. - """ - # Flag alias for another option - if self.alias: - return 0 - # Boolean: no argument - elif isinstance(self.default, bool): - return 0 - # List: unlimited arguments - elif isinstance(self.default, list): - return -1 - # Unary: one argument - else: - return 1 - - - def __str__(self): - """Return a string containing "usage notes" for this option. - """ - if self.alias: - usage = "-%s: Same as '-%s %s'\n" % \ - (self.name, self.alias[0], self.alias[1]) - else: - usage = "-%s %s " % (self.name, self.argformat) - if self.required: - usage += "(REQUIRED)\n" - else: - usage += "(default: %s)\n" % self.default - for line in textwrap.wrap(self.doc, 60): - usage += ' ' + line + '\n' - return usage - -class Usage (object): - """Command-line usage definition.""" - def __init__(self, usage_string='program [options]', *options): - """Define usage of a command-line program. - - usage_string - Command-line syntax and required options - options - List of allowed Options - - Examples:: - - usage = Usage('pytovid [options] -in FILENAME -out NAME', - Option('in', 'FILENAME', None, - "Input video file, in any format."), - Option('out', 'NAME', None, - "Output prefix or name."), - Option('format', 'vcd|svcd|dvd|half-dvd|dvd-vcd', 'dvd', - "Make video compliant with the specified format") - ) - print(usage) - print(usage.options['format']) - - """ - self.usage_string = usage_string - # Odict of options indexed by name - names = [opt.name for opt in options] - self.options = Odict(names, options) - - - def __str__(self): - """Return string-formatted usage notes. - """ - result = "Usage: %s\n" % self.usage_string - result += "Allowed options:\n" - option_list = ['-' + opt.name for opt in self.options.values()] - result += ', '.join(option_list) - return result - - - -from copy import copy - -def parse(args): - """Parse a list of arguments and return a dictionary of found options. - - args: List of command-line arguments (such as from sys.argv) - - The argument list is interpreted in this way: - - * If it begins with '-', it's an option - * Arguments that precede the first option are ignored - * Anything following an option is an argument to that option - * If there is no argument to an option, it's a flag (True if present) - * If there's one argument to an option, it's a single string value - * If there are multiple arguments to an option, it's a list of strings - - """ - args = copy(args) - options = {} - current = None - while len(args) > 0: - arg = args.pop(0) - # New option - if arg.startswith('-'): - current = arg.lstrip('-') - # Treat it as a flag unless we see arguments later - options[current] = True - - # Argument to current option - elif current: - # Was a flag, now has a single value - if options[current] is True: - options[current] = arg - # Was a single value, now a list - elif type(options[current]) != list: - options[current] = [options[current], arg] - # Was a list, so append new value - else: - options[current].append(arg) - return options - - -import re - -def validate(option, arg): - """Check whether an argument is valid for a given option. - - option: An Option to validate - arg: Candidate argument - - Expected/allowed values are inferred from the argformat string. - - argformat patterns to consider: - opta|optb|optc # Either opta, optb, or optc - [100-999] # Any integer between 100 and 999 - NUM:NUM # Any two integers separated by a colon - VAR # A single string (VAR can be any all-caps word) - VAR [, VAR] # List of strings - (empty) # Boolean; no argument required - - All very experimental... - """ - # TODO: Eliminate hackery; find a more robust way of doing this. - # Also, pretty inefficient, since regexp matching is done every - # time this function is called. - - # Empty argformat means boolean/no argument expected - if option.argformat == '': - if arg in [True, False, '']: - return True - else: - return False - - # Any alphanumeric word (any string) - if re.compile('^\w+$').match(option.argformat): - if arg.__class__ == str: - return True - else: - return False - - # Square-bracketed values are ranges, i.e. [1-99] - match = re.compile('^\[\d+-\d+\]$').match(option.argformat) - if match: - # Get min/max by stripping and splitting argformat - limits = re.split('-', match.group().strip('[]')) - option.min = int(limits[0]) - option.max = int(limits[1]) - if int(arg) >= option.min and int(arg) <= option.max: - return True - else: - return False - - # Values separated by | are mutually-exclusive - if re.compile('[-\w]+\|[-\w]+').match(option.argformat): - if arg in option.argformat.split('|'): - return True - else: - return False - - # For now, accept any unknown cases - return True - - - -if __name__ == '__main__': - print("Option-parsing demo") - - print("You passed the following arguments:") - print(sys.argv[1:]) - - print("Parsing...") - options = parse(sys.argv[1:]) - - print("Found the following options:") - print(options) -
View file
tovid-0.34.tar.bz2/libtovid/render
Deleted
-(directory)
View file
tovid-0.34.tar.bz2/libtovid/render/__init__.py
Deleted
@@ -1,7 +0,0 @@ -__all__ = [ - 'animation', - 'drawing', - 'effect', - 'flipbook', - 'layer', -]
View file
tovid-0.34.tar.bz2/libtovid/render/animation.py
Deleted
@@ -1,316 +0,0 @@ -"""This module provides classes and functions for working with animation. -Two classes are provided: - - `Keyframe` - A frame with a specific data value - `Tween` - A data sequence interpolated from Keyframes - -The data being interpolated may represent color, opacity, location, or anything -else that can be described numerically. Keyframe data may be scalar (single -integers or decimal values) or vector (tuples such as ``(x, y)`` coordinates or -``(r, g, b)`` color values). - -For example, let's define three keyframes:: - - >>> keys = [Keyframe(1, 0), - ... Keyframe(6, 50), - ... Keyframe(12, 10)] - -The value increases from 0 to 50 over frames 1-6, then back down to 10 -over frames 6-12. The values at intermediate frames (2-5 and 7-11) can be -interpolated or "tweened" automatically, using the Tween class:: - - >>> tween = Tween(keys) - >>> tween.data - [0, 10, 20, 30, 40, 50, 43, 36, 30, 23, 16, 10] - -Another example using tweening of ``(x, y)`` coordinates:: - - >>> keys = [Keyframe(1, (20, 20)), - ... Keyframe(6, (80, 20)), - ... Keyframe(12, (100, 100))] - -Here, a point on a two-dimensional plane starts at (20, 20), moving first -to the right, to (80, 20), then diagonally to (100, 100):: - - >>> tween = Tween(keys) - >>> for (x, y) in tween.data: - ... print((x, y)) - ... - (20, 20) - (32, 20) - (44, 20) - (56, 20) - (68, 20) - (80, 20) - (83, 33) - (86, 46) - (90, 60) - (93, 73) - (96, 86) - (100, 100) - -""" - -__all__ = [ - 'Keyframe', - 'Tween', - 'lerp', - 'cos_interp', - 'interpolate', -] - -import copy -import doctest -import math - -class Keyframe: - """Associates a specific frame in an animation with a numeric value. - A Keyframe is a ``(frame, data)`` pair defining a "control point" on a graph:: - - 100 | - | Keyframe(10, 50) - data | * - | - 0 |__________________________ - 1 10 20 30 - frame - - The data can represent anything you like. For instance, opacity:: - - 100 |* Keyframe(1, 100) - | - opacity(%) | - | - 0 |____________________* Keyframe(30, 0) - 1 10 20 30 - frame - - See the `Tween` class below for what you can do with these Keyframes, - once you have them. - """ - def __init__(self, frame, data): - """Create a keyframe, associating a given frame with some data. - The data may be an integer, floating-point value, or a tuple like - (x, y) or (r, g, b). - """ - self.frame = frame - self.data = data - - -### -------------------------------------------------------------------------- -### Interpolation algorithms -### -------------------------------------------------------------------------- - -def lerp(x, (x0, y0), (x1, y1)): - """Do linear interpolation between points ``(x0, y0)``, ``(x1, y1)``, and - return the ``y`` for the given ``x``. - - This form of interpolation simply connects two points with a straight - line. Blunt, but effective. - """ - return y0 + (x - x0) * (y1 - y0) / (x1 - x0) - - -def cos_interp(x, (x0, y0), (x1, y1)): - """Do cosine-based interpolation between ``(x0, y0)``, ``(x1, y1)`` and - return the ``y`` for the given ``x``. - - Essentially, a crude alternative to polynomial spline interpolation; this - method transitions between two values by matching a segment of the cosine - curve [0, pi] (for decreasing value) or [pi, 2*pi] (for increasing value) - to the interval between the given points. - - It gives smoother results at inflection points than linear interpolation, - but will result in "ripple" effects if keyframes are too dense or many. - """ - # Map the interpolation area (domain of x) to [0, pi] - x_norm = math.pi * (x - x0) / (x1 - x0) - # For y0 < y1, use upward-sloping part of the cosine curve [pi, 2*pi] - if y0 < y1: - x_norm += math.pi - # Calculate and return resulting y-value - y_min = min(y1, y0) - y_diff = abs(y1 - y0) - return y_min + y_diff * (math.cos(x_norm) + 1) / 2.0 - - -def interpolate(frame, left, right, method='linear'): - """Return the interpolated value at ``frame``, between two `Keyframe` - endpoints, using the given interpolation method ('linear' or 'cosine'). - - The left and right Keyframes mark the endpoints of the curve to be - interpolated. For example, if a value changes from 50 to 80 over the - course of frames 1 to 30:: - - >>> left = Keyframe(1, 50) - >>> right = Keyframe(30, 80) - - Then, the value at frame 10 can be interpolated as follows:: - - >>> interpolate(10, left, right, 'linear') - 59 - >>> interpolate(10, left, right, 'cosine') - 56.582194019564263 - - For frames outside the keyframe interval, the corresponding endpoint value - is returned:: - - >>> interpolate(0, left, right, 'linear') - 50 - >>> interpolate(40, left, right, 'linear') - 80 - - """ - assert isinstance(left, Keyframe) and isinstance(right, Keyframe) - # At or beyond endpoints, return endpoint value - if frame <= left.frame: - return left.data - elif frame >= right.frame: - return right.data - - # Use the appropriate interpolation function - if method == 'cosine': - interp_func = cos_interp - else: # method == 'linear' - interp_func = lerp - - # Interpolate integers or floats - if isinstance(left.data, int) or isinstance(left.data, float): - p0 = (left.frame, left.data) - p1 = (right.frame, right.data) - return interp_func(frame, p0, p1) - # Interpolate a tuple (x, y, ...) - elif isinstance(left.data, tuple): - # Interpolate each dimension separately - dim = 0 - result = [] - while dim < len(left.data): - interp_val = interp_func(frame, - (left.frame, left.data[dim]), - (right.frame, right.data[dim])) - result.append(interp_val) - dim += 1 - return tuple(result) - - -class Tween: - """An "in-between" sequence, calculated by interpolating the data in a - list of keyframes according to a given interpolation method. - - First, define some keyframes:: - - >>> keyframes = [Keyframe(1, 1), Keyframe(10, 25)] - - At frame 1, the value is 1; at frame 10, the value is 25. To get an - interpolation of the data between these two keyframes, use:: - - >>> tween = Tween(keyframes) - - Now, retrieve the interpolated data all at once:: - - >>> tween.data - [1, 3, 6, 9, 11, 14, 17, 19, 22, 25] - - Or by using array notation, indexed by frame number:: - - >>> tween[3] - 6 - >>> tween[8] - 19 - - """ - def __init__(self, keyframes, method='linear'): - """Create an in-between sequence from a list of keyframes. The - interpolation method can be 'linear' or 'cosine'. - - See `libtovid.render.effect` for implementation examples. - """ - for keyframe in keyframes: - assert isinstance(keyframe, Keyframe) - self.keyframes = keyframes - self.start = self.keyframes[0].frame - self.end = self.keyframes[-1].frame - self.method = method - # Do the tweening - self.data = self._calculate() - - - def _calculate(self): - """Perform in-betweening calculation on the current keyframes and - return a list of tweened values, indexed by frame number. - """ - data = [] - # TODO: Sort keyframes in increasing order by frame number (to ensure - # keyframes[0] is the first frame, and keyframes[-1] is the last frame) - # Make a copy of keyframes - keys = copy.copy(self.keyframes) - first = self.start - last = self.end - - # If keyframe interval is empty, use constant data from first keyframe - if first == last: - return keys[0].data - - # Pop off keyframes as each interval is calculated - left = keys.pop(0) - right = keys.pop(0) - frame = first - # Interpolate until the last frame is reached - while frame <= last: - value = interpolate(frame, left, right, self.method) - data.append(value) - # Get the next interval, if it exists - if frame == right.frame and len(keys) > 0: - left = right - right = keys.pop(0) - frame += 1 - - return data - - - def __getitem__(self, frame): - """Return the interpolated data at the given frame. This allows - accessing a tweened value with subscripting by frame number:: - - >>> keys = [Keyframe(1, 1), Keyframe(30, 50)] - >>> tween = Tween(keys) - >>> tween[1] - 1 - >>> tween[30] - 50 - >>> tween[21] - 34 - - Frame numbers outside the keyframed region have the same values as - those at the corresponding endpoints:: - - >>> tween[0] - 1 - >>> tween[100] - 50 - """ - # If data is a single value, frame is irrelevant - if not isinstance(self.data, list): - return self.data - # Otherwise, return the value for the given frame, extending endpoints - elif frame < self.start: - return self.data[0] - elif frame > self.end: - return self.data[-1] - else: - return self.data[frame - self.start] - - -if __name__ == '__main__': - doctest.testmod(verbose=True) - - p0 = (1, 1) - p1 = (20, 20) - - print("Interpolation methods") - print("x lerp cos_interp") - for x in range(1, 21): - print("%s %s %s" % \ - (x, lerp(x, p0, p1), cos_interp(x, p0, p1)))
View file
tovid-0.34.tar.bz2/libtovid/render/drawing.py
Deleted
@@ -1,1456 +0,0 @@ -# -=- encoding: latin-1 -=- - -# Run this script standalone for a demonstration: -# $ python libtovid/render/drawing.py - -# To use this module from your Python interpreter, run: -# $ python -# >>> from libtovid.render.drawing import * - -"""Interactive vector drawing and rendering interface. - -This module provides a class called Drawing, which provides a blank canvas -that can be painted with vector drawing functions, and later rendered to -a raster image file (.png, .jpg etc.) at any desired resolution. - -To create a new, blank Drawing:: - - >>> d = Drawing(800, 600) # width, height - -Here, (800, 600) defines two things: - - - On-screen display size, in pixels (800px x 600px) - - Intended viewing aspect ratio (800:600 or 4:3) - -Note that you are still doing vector drawing, so whatever size you pick here -has no bearing on your final target resolution--it's mostly intended for a -convenient "preview" size while doing interactive drawing. - -Back on topic: you can now add shapes to the drawing, fill and stroke them:: - - >>> d.circle(500, 300, 150) # (x, y, radius) - >>> d.fill('blue', 0.8) # color name with optional alpha - >>> d.stroke('rgb(0, 128, 255)') # rgb values 0-255 - -Then add more shapes:: - - >>> d.rectangle(25, 25, 320, 240) # x, y, width, height - >>> d.fill('rgb(40%, 80%, 10%)') # rgb percentages - >>> d.stroke('#FF0080', 0.5) # rgb hex notation with an alpha - -To see what the drawing looks like so far, do:: - - >>> display(d) # display at existing size - >>> display(d, 720, 480) # display at different size - >>> display(d, fix_aspect=True) # display in correct aspect ratio - -You may then decide to add more to the drawing:: - - >>> d.set_source('white') - >>> d.text("Dennis", 50, 100) # text, x, y - -And preview again:: - - >>> display(d) - -Once you finish your beautiful painting, save it as a nice high-res PNG:: - - >>> save_png(d, "my.png", 1600, 1200) - -Cairo references: - - [1] http://www.cairographics.org - [2] http://tortall.net/mu/wiki/CairoTutorial - -""" - -__all__ = [ - 'Drawing', - 'render', - 'display', - 'save_image', - 'save_jpg', - 'save_pdf', - 'save_png', - 'save_ps', - 'save_svg', - 'write_ppm', -] - -import os -import sys -import time -import commands -from copy import copy -from math import pi, sqrt -import cairo -import Image # for JPG export -import ImageColor # for getrgb, getcolor -import ImageFile # for write_png() -from libtovid import log -from libtovid.util import to_unicode - -def get_surface(width, height, surface_type='image', filename=''): - """Get a cairo surface at the given dimensions. - """ - if type(width) != int or type(height) != int: - log.warning("Surface width and height should be integers."\ - " Converting to int.") - - if surface_type == 'image': - return cairo.ImageSurface(cairo.FORMAT_ARGB32, - int(width), int(height)) - elif surface_type == 'svg': - return cairo.SVGSurface(filename, width, height) - elif surface_type == 'pdf': - return cairo.PDFSurface(filename, width, height) - elif surface_type == 'ps': - return cairo.PSSurface(filename, width, height) - - - -### -------------------------------------------------------------------- -### Classes -### -------------------------------------------------------------------- -class Step: - """An atomic drawing procedure, consisting of a closed function that - draws on a given cairo surface, and human-readable information about - what parameters were given to it. - """ - def __init__(self, function, *args): - self.function = function - self.name = function.__name__.lstrip('_') - self.args = args - def __str__(self): - return "%s%s" % (self.name, self.args) - - -# Drawing class notes -# -# The Drawing class has a number of methods (circle, rectangle, fill, stroke -# and many others) that need to operate on a Cairo surface. But we'd like to -# delay execution of actually drawing on that surface--otherwise, we can't -# easily render a given Drawing to a custom resolution. -# -# Closures save the day here--that is, functions without "free variables". -# Anytime you "paint" on the Drawing, what's actually happening is a new -# function is getting created, whose sole purpose in life is to carry out that -# specific paint operation. These tiny, single-purpose functions are then -# added to a list of steps (self.steps) that will actually be executed at -# rendering-time (i.e., when you do display() or save_png). -# -# This not only lets us render a Drawing to different resolutions, but allows -# the possibility of rendering to different Cairo surfaces. - -class Drawing: - - tk = None # tkinter widget to send redraws to - - def __init__(self, width=800, height=600, autodraw=False): - """Create a blank drawing at the given size. - - width, height - Dimensions of the drawable region, in arbitrary units - autodraw - Redraw a preview image after each drawing operation - """ - self.size = (width, height) - self.w = width - self.h = height - self.aspect = float(width) / height - self.autodraw = autodraw - #self.commands = [] - self.steps = [] - # "Dummy" surface/context at the original resolution; - # should not be drawn on - self.surface = get_surface(width, height, 'image') - self.cr = cairo.Context(self.surface) - - - def addStep(self, func, *args): - """Add a Step to self.steps using the given function and args.""" - step = Step(func, *args) - self.steps.append(step) - if self.autodraw and step.name in ['fill', 'stroke']: - display(self, 640, 480, True) - - - def doStep(self, func, *args): - """Add the given Step, and execute it.""" - self.addStep(func, *args) - func(self.cr) - - - def history(self): - """Return a formatted string of all steps in this Drawing.""" - result = '' - for number, step in enumerate(self.steps): - result += '%d. %s\n' % (number, step) - return result - - - def affine(self, rot_x, rot_y, scale_x, scale_y, translate_x, translate_y): - """Define a 3x3 transformation matrix:: - - [ scale_x rot_y translate_x ] - [ rot_x scale_y translate_y ] - [ 0 0 1 ] - - This is scaling, rotation, and translation in a single matrix, - so it's a compact way to represent any transformation. - - See [http://www.w3.org/TR/SVG11/coords.html] for more on - these matrices and how to use them. - """ - mtx = cairo.Matrix(scale_x, rot_x, rot_y, scale_y, - translate_x, translate_y) - def _affine(cr): - cr.set_matrix(mtx) - self.doStep(_affine, rot_x, rot_y, scale_x, scale_y, - translate_x, translate_y) - - - def arc(self, x, y, radius, start_deg, end_deg): - """Draw an arc from (x, y), with the specified radius, starting at - degree start_deg and ending at end_deg. - """ - def _arc(cr): - cr.arc(x, y, radius, start_deg * pi/180., end_deg * pi/180.) - self.doStep(_arc, x, y, radius, start_deg, end_deg) - - - def arc_rad(self, x, y, radius, start_rad, end_rad): - """Draw an arc from (x, y), with the specified radius, starting at - radian start_rad and ending at end_rad. - """ - def _arc_rad(cr): - cr.arc(x, y, radius, start_rad, end_rad) - self.doStep(_arc_rad, x, y, radius, start_rad, end_rad) - - - # TODO: Rewrite/cleanup bezier function - def bezier(self, points, rel=False, close_path=False): - """Create a Bezier curve. - - Points should look like:: - - points = [[(x0, y0), (x_ctl1, y_ctl1), (x_ctl2, y_ctl2)], - [(x0, y0), (x_ctl1, y_ctl1), (x_ctl2, y_ctl2)], - [(x0, y0), (x_ctl1, y_ctl1), (x_ctl2, y_ctl2)], - [(x0, y0)], - ] - - where (x0, y0) are the point coordinates, and x_ctl* are the control - points coordinates. - - - ctl1 - control from last point - - ctl2 - control to next point - - The last line would specify that control points - are at the same place (x0, y0), drawing straight lines. - - rel - when this is True, the x_ctl and y_ctl become relatives - to the (x0, y0) points - close_path - set this to True to call cr.close_path() before stroking. - - """ - assert len(points) > 1, "You need at least two points" - for pt in points: - # If only one point is specified, copy it for control points - if len(pt) == 1: - pt.append(pt[0]) # add the two identical - pt.append(pt[0]) # control points - assert len(pt) == 3, "You need to specify three tuples for each point, or one single" - for y in pt: - assert isinstance(y, tuple) and len(y) == 2, "You need "\ - "to specify two-values tuples" - # Map relative stuff to absolute, when rel=True - if rel: - for x in range(0, len(points)): - pt = points[x] - assert len(pt) == 3, "In relative mode, you must "\ - "specify control points" - # Render relative values to absolute values. - npt = [] - # # x # y - npt.append([pt[0][0], pt[0][1]]) # x0, y0 - npt.append([pt[0][0] + pt[1][0], pt[0][1] + pt[1][1]]) - npt.append([pt[0][0] + pt[2][0], pt[0][1] + pt[2][1]]) - points[x] = npt - - # Define the actual drawing function - def _bezier(cr): - # Move to the first x,y in the first point - cr.new_path() - cr.move_to(points[0][0][0], points[0][0][1]) - for pt in points: - cr.curve_to(pt[2][0], pt[2][1], - pt[0][0], pt[0][1], - pt[1][0], pt[1][1]) - if close_path: - cr.close_path() - self.doStep(_bezier, points, rel, close_path) - - - def circle(self, center_x, center_y, radius): - """Draw a circle defined by center point and radius.""" - def _circle(cr): - cr.new_path() - cr.arc(center_x, center_y, radius, 0, 2*pi) - self.doStep(_circle, center_x, center_y, radius) - - - def fill(self, source=None, opacity=None): - """Fill the current (closed) path with an optionally given color. - - If arguments are present, they are passed to set_source() - before filling. Note that this source will be applied to further - fill()ings or stroke()ings or text() calls. - """ - # Optionally set fill color, and save it. - if source is not None: - self.set_source(source, opacity) - - def _fill(cr): - cr.fill_preserve() - self.doStep(_fill, source, opacity) - - - def fill_rule(self, rule): - """Set the fill rule to one of: - - evenodd, winding (nonzero) - - This determines which parts of an overlapping path polygon will - be filled with the fill() command. - - http://www.w3.org/TR/SVG/painting.html#FillRuleProperty - """ - tr = {'evenodd': cairo.FILL_RULE_EVEN_ODD, - 'winding': cairo.FILL_RULE_WINDING} - - # Test value - tr[rule] - - def _fill_rule(cr): - cr.set_fill_rule(tr[rule]) - self.doStep(_fill_rule, rule) - - - def font(self, name, slant='normal', weight='normal'): - """Set the current font. - - name - name of the Font, or family (sans-serif, serif) - slant - one of: italic, normal, oblique - weight - one of: normal, bold - """ - sl = {'italic': cairo.FONT_SLANT_ITALIC, - 'normal': cairo.FONT_SLANT_NORMAL, - 'oblique': cairo.FONT_SLANT_OBLIQUE} - wg = {'normal': cairo.FONT_WEIGHT_NORMAL, - 'bold': cairo.FONT_WEIGHT_BOLD} - def _font(cr): - cr.select_font_face(name, sl[slant], wg[weight]) - self.doStep(_font, name, slant, weight) - - - def font_size(self, pointsize): - """Set the current font size in points. - """ - def _font_size(cr): - cr.set_font_size(pointsize) - self.doStep(_font_size, pointsize) - - - def font_stretch(self, x=1.0, y=1.0): - """Set the font stretch type in both directions to one of: - - = 1.0 -- normal - > 1.0 -- strench - < 1.0 -- shrink - - """ - def _font_stretch(cr): - m = cr.get_font_matrix() - m.scale(x, y) - cr.set_font_matrix(m) - self.doStep(_font_stretch, x, y) - - - def font_rotate(self, degrees): - """Set the font rotation, in degrees. - """ - def _font_rotate(cr): - m = cr.get_font_matrix() - m.rotate(degrees * pi/180.) - cr.set_font_matrix(m) - self.doStep(_font_rotate, degrees) - - - def image_surface(self, x, y, width, height, surface, mask=None): - """Draw a given cairo.ImageSurface centered at (x, y), at the given - width and height. - - If you specify mask, it must be a cairo ImageSurface. - """ - # Calculate centering and scaling - add_x, add_y = (0, 0) - dw = float(width) / float(surface.get_width()) - dh = float(height) / float(surface.get_height()) - if (dw > dh): - scale = dh - add_x = (width - dh * float(surface.get_width())) / 2 - else: - scale = dw - add_y = (height - dw * float(surface.get_height())) / 2 - - # Save context and get the surface to right dimensions - self.save() - self.translate(x + add_x, y + add_y) - self.scale(scale, scale) - - # Create and append the drawing function - if (mask): - def _image_surface(cr): - cr.set_source_surface(surface) - cr.mask_surface(mask) - self.doStep(_image_surface, x, y, width, height, surface, mask) - else: - def _image_surface(cr): - cr.set_source_surface(surface) - cr.paint() - self.doStep(_image_surface, x, y, width, height, surface, mask) - - self.restore() - - - def image(self, x, y, width, height, source): - """Draw an image centered at (x, y), scaled to the given width and - height. Return the corresponding cairo.ImageSurface object. - - source - - a .png filename (quicker and alpha present), - - a cairo.ImageSurface object, which is even better, - - a file object - - a filename - any file supported by python-imaging, - a.k.a PIL [1] - - Ref: - [1] http://www.pythonware.com/library/pil/handbook/formats.htm - - You can apply some operator() to manipulation how the image is going - to show up. See operator() - """ - # Determine what type of source was given, and make it into - # a cairo.ImageSurface - if isinstance(source, cairo.ImageSurface): - surface = source - # PNG files can be added directly - elif isinstance(source, str) and source.endswith('.png'): - surface = cairo.ImageSurface.create_from_png(source) - # Other formats must be converted to PNG - else: - infile = Image.open(source) - outfile = open('/tmp/export.png', 'wb+') - infile.save(outfile, 'PNG') - outfile.seek(0) - surface = cairo.ImageSurface.create_from_png(outfile) - outfile.close() - # Let someone else do the dirty work - self.image_surface(x, y, width, height, surface) - - return surface - - - def line(self, x0, y0, x1, y1): - """Set new path as a line from (x0, y0) to (x1, y1). - - Don't forget to stroke() - """ - def _line(cr): - cr.new_path() - cr.move_to(x0, y0) - cr.line_to(x1, y1) - self.doStep(_line, x0, y0, x1, y1) - - - def operator(self, operator='clear'): - """Set the operator mode. - - operator - One of: clear, source, over, in, out, atop, dest, - dest_over, dest_in, dest_out, dest_atop, xor, add, saturate - - """ - ops = {'clear': cairo.OPERATOR_CLEAR, - 'source': cairo.OPERATOR_SOURCE, - 'over': cairo.OPERATOR_OVER, - 'in': cairo.OPERATOR_IN, - 'out': cairo.OPERATOR_OUT, - 'atop': cairo.OPERATOR_ATOP, - 'dest': cairo.OPERATOR_DEST, - 'dest_over': cairo.OPERATOR_DEST_OVER, - 'dest_in': cairo.OPERATOR_DEST_IN, - 'dest_out': cairo.OPERATOR_DEST_OUT, - 'dest_atop': cairo.OPERATOR_DEST_ATOP, - 'xor': cairo.OPERATOR_XOR, - 'add': cairo.OPERATOR_ADD, - 'saturate': cairo.OPERATOR_SATURATE, - } - - # Test bad value - ops[operator] - - def _operator(cr): - cr.set_operator(ops[operator]) - self.doStep(_operator, operator) - - - def paint(self): - """Paint the current source everywhere within the current clip - region. - """ - def _paint(cr): - cr.paint() - self.doStep(_paint) - - - def paint_with_alpha(self, alpha): - """Paints the current source everywhere within the current clip - region using a mask of constant alpha value alpha. - - The effect is similar to paint(), but the drawing is faded out - using the alpha value. - """ - def _paint_with_alpha(cr): - cr.paint_with_alpha(alpha) - self.doStep(_paint_with_alpha, alpha) - - - def point(self, x, y): - """Draw a point at (x, y). - """ - # Circle radius 1/1000 the drawing width - radius = float(self.size[0]) / 1000 - def _point(cr): - cr.new_path() - cr.arc(x, y, radius, 0, 2*pi) - self.doStep(_point, x, y) - - - def polygon(self, points, close_path=True): - """Define a polygonal path defined by (x, y) points in the given - list. - - points = [(x0, y0), - (x1, y1), - (x2, y2)] - - Draw strokes and filling yourself, with fill() and stroke(). - """ - nlist = [] - for tup in points: - nlist.append([tup]) - self.bezier(nlist, False, close_path) - - - def polyline(self, points, close_path=True): - """Draw a polygon defined by (x, y) points in the given list. - - This is a short- (or long-) hand for polygon. In Cairo, you draw - your filling (fill()), or strokes (stroke()) yourself, so - having polyline and polygon is basiclly useless. - """ - self.polygon(points, close_path) - - - def rectangle_corners(self, x0, y0, x1, y1): - """Draw a rectangle defined by opposite corners (x0, y0) and (x1, y1). - """ - def _rectangle_corners(cr): - cr.new_path() - cr.rectangle(x0, y0, x1-x0, y1-y0) - self.doStep(_rectangle_corners, x0, y0, x1, y1) - - - def rectangle(self, x, y, width, height): - """Draw a rectangle with top-left corner at (x, y), and (width x height) - in size. - """ - def _rectangle(cr): - cr.new_path() - cr.rectangle(x, y, width, height) - self.doStep(_rectangle, x, y, width, height) - - - def rotate_deg(self, degrees): - """Rotate by the given number of degrees. - """ - def _rotate_deg(cr): - m = cr.get_matrix() - m.rotate(degrees * pi/180.) - cr.set_matrix(m) - self.doStep(_rotate_deg, degrees) - - rotate = rotate_deg - def rotate_rad(self, rad): - """Rotate by the given number of radians. - """ - def _rotate_rad(cr): - m = cr.get_matrix() - m.rotate(rad) - cr.set_matrix(m) - self.doStep(_rotate_rad, rad) - - - def roundrectangle(self, x0, y0, x1, y1, bevel_width, bevel_height): - """Draw a rounded rectangle from (x0, y0) to (x1, y1), with - a bevel size of (bevel_width, bevel_height). - """ - bw = bevel_width - bh = bevel_height - # Add bezier points - tl1 = [(x0, y0 + bh), (0, 0), (0, 0)] - tl2 = [(x0 + bw, y0), (0, 0), (-bw, 0)] - tr1 = [(x1 - bw, y0), (0, 0), (-bw, 0)] - tr2 = [(x1, y0 + bh), (0, 0), (0, -bw)] - br1 = [(x1, y1 - bh), (0, 0), (0, -bh)] - br2 = [(x1 - bw, y1), (0, 0), (+bw, 0)] - bl1 = [(x0 + bw, y1), (0, 0), (+bw, 0)] - bl2 = [(x0, y1 - bh), (0, 0), (0, +bh)] - end = [(x0, y0 + bh), (0, 0), (0, 0)] - # Call in relative mode bezier control points. - mylst = [tl1, tl2, tr1, tr2, br1, br2, bl1, bl2, end] - # Let bezier do the work - self.bezier(mylst, True) - - - def set_source(self, source, opacity=None): - """Set the source. - - source - One of the following color formats as a string or a tuple - (see below), another Surface or Surface-derivative object, - or a Pattern object (and its derivatives). - opacity - Opacity ranging from 0.0 to 1.0. Defaults to None. If - you specify a 'string' or 'tuple' RGB-like code as - source, opacity defaults to 1.0 - - You can use the following *tuple* format to specify color: - - - (red, green, blue) with colors ranging from 0.0 to 1.0, - like Cairo wants them - - You can use the following *string* formats to specify color: - - - Hexadecimal color specifiers, given as '#rgb' or '#rrggbb'. - For example, '#ff0000' specifies pure red. - - RGB functions, given as 'rgb(red, green, blue)' where the colour - values are integers in the range 0 to 255. Alternatively, the color - values can be given as three percentages (0% to 100%). For example, - 'rgb(255,0,0)' and 'rgb(100%,0%,0%)' both specify pure red. - - Hue-Saturation-Lightness (HSL) functions, given as: - 'hsl(hue, saturation%, lightness%)' where hue is the colour given as - an angle between 0 and 360 (red=0, green=120, blue=240), saturation - is a value between 0% and 100% (gray=0%, full color=100%), and - lightness is a value between 0% and 100% (black=0%, normal=50%, - white=100%). For example, 'hsl(0,100%,50%)' is pure red. - - Common HTML colour names. The ImageColor module provides some 140 - standard colour names, based on the colors supported by the X - Window system and most web browsers. Colour names are case - insensitive. For example, 'red' and 'Red' both specify pure red. - - """ - mysource = self.create_source(source, opacity) - def _set_source(cr): - cr.set_source(mysource) - # Only do the step if the source could be created - if mysource: - self.doStep(_set_source, source, opacity) - - - def create_source(self, source, opacity=None): - """Return a source pattern (solid, gradient, image surface) - with anything fed into it. Returns None if the source could not - be created successfully. - - See the set_source() documentation for more details on inputs. - - You can feed anything returned by this function into set_source() - """ - if isinstance(source, cairo.Pattern): - return source - # A string--color name, rgb(), hsv(), or hexadecimal - elif isinstance(source, str): - try: - (r, g, b) = ImageColor.getrgb(source) - except ValueError, err: - log.error(err) - return None - alpha = 1.0 - if opacity is not None: - alpha = opacity - return cairo.SolidPattern(r / 255.0, g / 255.0, - b / 255.0, alpha) - # An (r, g, b) tuple - elif isinstance(source, tuple): - assert len(source) == 3 - (r, g, b) = source - alpha = 1.0 - if opacity is not None: - alpha = opacity - return cairo.SolidPattern(r, g, b, alpha) - # A cairo Gradient - elif isinstance(source, cairo.Gradient): - return source - # A cairo Surface - elif isinstance(source, cairo.Surface): - return cairo.SurfacePattern(source) - else: - raise TypeError, "source must be one of: str, tuple, "\ - "cairo.Pattern, cairo.Gradient or cairo.Surface" - - - def get_source(self): - """Return the actually used source pattern - - This returns either of these: - - cairo.SolidPattern (RGB or RGBA color) - cairo.SurfacePattern (some other image) - cairo.LinearGradient (linear gradient :) - cairo.RadialGradient (radial gradient :) - - You can then use this source in set_source(), to use the same - pattern for fill()ing or stroke()ing. - """ - # TODO: Fix or remove this function - return self.cr.get_source() - - - def scale(self, factor_x, factor_y): - """Set scaling to (factor_x, factor_y), where 1.0 means no scaling. - - Note that the center point for scaling is (0,0); to scale from a - different center point, use scale_centered() - """ - def _scale(cr): - m = cr.get_matrix() - m.scale(factor_x, factor_y) - cr.set_matrix(m) - self.doStep(_scale, factor_x, factor_y) - - - def scale_centered(self, center_x, center_y, factor_x, factor_y): - """Set scaling to (dx, dy), where dx and dy are horizontal and - vertical ratios (floats). - - scale_centered() will keep the (center_x, center_y) in the middle - of the scaling, operating a translation in addition to scaling. - """ - def _scale_centered(cr): - m = cr.get_matrix() - # Ouch, we want to keep the center x,y at the same place?! - m.translate(-(center_x * factor_x - center_x), - -(center_y * factor_y - center_y)) - m.scale(factor_x, factor_y) - cr.set_matrix(m) - self.doStep(_scale_centered, center_x, center_y, factor_x, factor_y) - - - def stroke(self, source=None, opacity=None): - """Stroke the current shape. - - See fill() documentation for parameter explanation. They are the - same. - """ - # Optionally set stroke color, and save it. - if source is not None: - self.set_source(source, opacity) - - def _stroke(cr): - # Optionally set fill color, and save it. - cr.stroke_preserve() - self.doStep(_stroke, source, opacity) - - - def stroke_antialias(self, do_antialias=True): - """Enable/disable antialiasing for strokes. - - do_antialias: True, False, 'none', 'default', or 'gray' - - This does not affect text. See text_antialias() for more info - on text antialiasing. - """ - if do_antialias: - aa_type = cairo.ANTIALIAS_GRAY - else: - aa_type = cairo.ANTIALIAS_NONE - - def _stroke_antialias(cr): - cr.set_antialias(aa_type) - self.doStep(_stroke_antialias, do_antialias) - - - def stroke_dash(self, array, offset=0.0): - """Set the dash style. - - array - A list of floats, alternating between ON and OFF for - each value - offset - An offset into the dash pattern at which the stroke - should start - - For example:: - - >>> stroke_dash([5.0, 3.0]) - - alternates between 5 pixels on, and 3 pixels off. - """ - def _stroke_dash(cr): - cr.set_dash(array, offset) - self.doStep(_stroke_dash, array, offset) - - - def stroke_linecap(self, cap_type): - """Set the type of line cap to use for stroking. - - cap_type - 'butt', 'round', or 'square' - """ - dic = {'butt': cairo.LINE_CAP_BUTT, - 'round': cairo.LINE_CAP_ROUND, - 'square': cairo.LINE_CAP_SQUARE} - - # Test value - dic[cap_type] - - def _stroke_linecap(cr): - cr.set_line_cap(dic[cap_type]) - self.doStep(_stroke_linecap, cap_type) - - - def stroke_linejoin(self, join_type): - """Set the type of line-joining to do for stroking. - - join_type - 'bevel', 'miter', or 'round' - """ - dic = {'bevel': cairo.LINE_JOIN_BEVEL, - 'miter': cairo.LINE_JOIN_MITER, - 'round': cairo.LINE_JOIN_ROUND} - - # Test value - dic[join_type] - - def _stroke_linejoin(cr): - cr.set_line_join(dic[join_type]) - self.doStep(_stroke_linejoin, join_type) - - - def stroke_width(self, width): - """Set the current stroke width in pixels.""" - # (Pixels or points?) - def _stroke_width(cr): - cr.set_line_width(width) - self.doStep(_stroke_width, width) - - - def text(self, text_string, x, y, align='left'): - """Draw the given text string. - - text_string - utf8 encoded text string - x, y - lower-left corner position - - Set the text's color with set_source() before calling text(). - """ - text_string = to_unicode(text_string) - - def _text(cr): - (dx, dy, w, h, ax, ay) = cr.text_extents(text_string) - if align == 'right': - nx = x - w - elif align == 'center': - nx = x - w / 2 - else: - nx = x - cr.move_to(nx, y) - cr.show_text(text_string) - self.doStep(_text, text_string, x, y, align) - - - def text_path(self, text_string, x, y): - """Same as text(), but sets a path and doesn't draw anything. - Call stroke() or fill() yourself. - - Has the parameters and returns the same values as text(). - - Beware that text() calls the Cairo function show_text() which - caches glyphs, so is more efficient when dealing with large - texts. - """ - if not isinstance(text_string, unicode): - text_string = unicode(text_string.decode('latin-1')) - def _text_path(cr): - cr.move_to(x, y) - cr.text_path(text_string) - self.doStep(_text_path, text_string, x, y) - - - def text_extents(self, text): - """Returns the dimensions of the to-be-drawn text. - - Call this before calling text() if you want to place it well, - according to the dimensions of the text rectangle to be drawn. - - See text()'s return value for details. - - Returns: - (x_bearing, y_bearing, width, height, x_advance, y_advance) - """ - text = to_unicode(text) - return self.cr.text_extents(text) - - - def translate(self, dx, dy): - """Do a translation by (dx, dy) pixels.""" - def _translate(cr): - m = cr.get_matrix() - m.translate(dx, dy) - cr.set_matrix(m) - self.doStep(_translate, dx, dy) - - - def push_group(self): - """Temporarily redirects drawing to an intermediate surface - known as a group. - - The redirection lasts until the group is completed by a call - to pop_group() or pop_group_to_source(). These calls provide - the result of any drawing to the group as a pattern, (either - as an explicit object, or set as the source pattern). - """ - def _push_group(cr): - cr.push_group() - self.doStep(_push_group) - - - def pop_group_to_source(self): - """Terminates the redirection begun by a call to push_group() and - installs the resulting pattern as the source pattern in the current - cairo context. - """ - def _pop_group_to_source(cr): - cr.pop_group_to_source() - self.doStep(_pop_group_to_source) - - - def save(self): - """Save state for Cairo and local contexts. - - You can save in a nested manner, and calls to restore() will pop - the latest saved context. - """ - def _save(cr): - cr.save() - self.doStep(_save) - - BEGIN = save - def restore(self): - """Restore the previously saved context. - """ - def _restore(cr): - cr.restore() - self.doStep(_restore) - - END = restore - def font_family(self, family): - """Set the current font, by family name.""" - def _font_family(cr): - cr.select_font_face(family) - self.doStep(_font_family, family) - - font_face = font_family - def text_align(self, text_string, x, y, align='left'): - """Draw the given text string. - - text_string - UTF-8 encoded text string - x, y - Lower-left corner position - align - 'left', 'center', 'right'. This only changes the - alignment in 'x', and 'y' stays the baseline. - - Set the text's color with set_source() before calling text(). - """ - (dx, dy, w, h, ax, ay) = self.cr.text_extents(text_string) - w = 0 - if align == 'right': - x = x - w - elif align == 'center': - x = x - w / 2 - else: # 'left' - x = x - # Let text() do the drawing - self.text(text_string, x, y) - - - def text_path_align(self, x, y, text_string, centered=False): - """Same as text_align(), but sets a path and doesn't draw anything. - Call stroke() or fill() yourself. - """ - (dx, dy, w, h, ax, ay) = self.cr.text_extents(text_string) - if centered: - x = x - w / 2 - y = y + h / 2 - # Let text_path() do the drawing - self.text_path(text_string, x, y) - - -### -------------------------------------------------------------------- -### Exported functions -### -------------------------------------------------------------------- -# Cached masks, rendered only once. -interlace_fields = None - - -def interlace_drawings(draw1, draw2): - """Merge two drawings into one, using interlacing fields. - - This method interlaces with the BOTTOM-FIRST field order. - """ - global interlace_fields - - dr = Drawing(draw1.w, draw1.h) - - # create masks (only once) - if (not interlace_fields): - fields = [0, 1] - for f in range(0, 2): - img = cairo.ImageSurface(cairo.FORMAT_ARGB32, draw1.w, draw1.h) - cr = cairo.Context(img) - cr.set_antialias(cairo.ANTIALIAS_NONE) - cr.set_source_rgba(0.5, 0.5, 0.5, 1) - cr.set_line_width(1) - - for x in range(0, draw1.h / 2): - # x*2 + f = top field first.., each two lines.. - # -1 à draw1.w +1 -> pour être sur de couvrir aussi les bouts. - cr.move_to(-1, x*2 + f) - cr.line_to(draw1.w + 1, x*2 + f) - cr.stroke() - - fields[f] = img - interlace_fields = fields - else: - fields = interlace_fields - - # For bottom first, use fields[0] first, and fields[1] after. - # For top-first, use draw1 with fields[1] and draw2 with fields[0] - # paint first image - dr.image_surface(0, 0, dr.w, dr.h, draw1.surface, fields[0]) - # paint second image - dr.image_surface(0, 0, dr.w, dr.h, draw2.surface, fields[1]) - - return dr - - - -def render(drawing, context, width, height): - """Render a Drawing to the given cairo context at the given size. - """ - # Scale from the original size - scale_x = float(width) / drawing.size[0] - scale_y = float(height) / drawing.size[1] - drawing.scale(scale_x, scale_y) - # Sneaky bit--scaling needs to happen before everything else - drawing.steps.insert(0, drawing.steps.pop(-1)) - - # Execute all draw commands - for step in drawing.steps: - log.debug("Drawing step: %s" % step) - step.function(context) - - # Remove scaling function - drawing.steps.pop(0) - - -def display(drawing, width=None, height=None, fix_aspect=False): - """Render and display the given Drawing at the given size. - - drawing - A Drawing object to display - width - Pixel width of displayed image, - or 0 to use the given Drawing's size - height - Pixel height of displayed image, - or 0 to use the given Drawing's size - fix_aspect - True to adjust height to make the image - appear in the correct aspect ratio - """ - if not width: - width = drawing.size[0] - if not height: - height = drawing.size[1] - - # Adjust height to fix aspect ratio if desired - if fix_aspect: - height = width / drawing.aspect - # Render and display a .png - png_file = '/tmp/drawing.png' - save_png(drawing, png_file, width, height) - print("Displaying %s at %sx%s" % (png_file, width, height)) - print("(press 'q' in image window to continue)") - print(commands.getoutput('display %s' % png_file)) - - -def write_ppm(drawing, pipe, width, height, workdir=None): - """Write image as a PPM file to a file-object - - workdir - Unused in this context, just to have parallel parameters - with write_png(). - - Useful to pipe directly in ppmtoy4m and to pipe directly to mpeg2enc. - """ - # Timing - start = time.time() - if (width, height) == drawing.size: - #print("Not re-rendering") - surface = drawing.surface - else: - surface = get_surface(width, height, 'image') - context = cairo.Context(surface) - render(drawing, context, width, height) - - buf = surface.get_data() - # Assumes surface is cairo.FORMAT_ARGB32 - im = Image.frombuffer('RGBA', (surface.get_width(), surface.get_height()), - buf) - im = im.transpose(Image.FLIP_TOP_BOTTOM) - im.save(pipe, 'ppm') - - #print("write_ppm took %s seconds" % (time.time() - start)) - - -def write_png(drawing, pipe, width, height, workdir): - """Write image as a PPM file to a file-object - - Useful to pipe directly in:: - - pngtopnm -mix -background=rgb:00/00/00 | ppmtoy4m | mpeg2enc. - """ - # Timing - start = time.time() - if (width, height) == drawing.size: - #print("Not re-rendering") - surface = drawing.surface - else: - surface = get_surface(width, height, 'image') - context = cairo.Context(surface) - render(drawing, context, width, height) - - surface.write_to_png('%s/tmp.png' % workdir) - im = Image.open('%s/tmp.png' % workdir) - im.load() - im.save(pipe, 'ppm') - - #print("write_png took %s seconds" % (time.time() - start)) - - -def save_png(drawing, filename, width, height): - """Saves a drawing to PNG, keeping alpha channel intact. - - This is the quickest, since Cairo itself exports directly to .png - """ - # Timing - start = time.time() - if (width, height) == drawing.size: - #print("Not re-rendering") - surface = drawing.surface - else: - surface = get_surface(width, height, 'image') - context = cairo.Context(surface) - render(drawing, context, width, height) - surface.write_to_png(filename) - #print("save_png took %s seconds" % (time.time() - start)) - - -def save_jpg(drawing, filename, width, height): - """Saves a drawing to JPG, losing alpha channel information. - """ - f = open('/tmp/export.png', 'wb+') - save_png(drawing, f, width, height) - f.seek(0) - im = Image.open(f) - im.save(filename) - del(im) - f.close() - - -def save_image(drawing, img_filename, width, height): - """Render drawing to a .jpg, .png or other image. - """ - log.info("Saving Drawing to %s" % img_filename) - if img_filename.endswith('.png'): - save_png(drawing, img_filename, width, height) - elif img_filename.endswith('.jpg'): - save_jpg(drawing, img_filename, width, height) - else: - log.debug("Creating temporary .png") - temp_png = '/tmp/%s.png' % img_filename - save_png(drawing, temp_png, width, height) - log.debug("Converting temporary png to %s" % img_filename) - cmd = "convert -size %sx%s " % drawing.size - cmd += "%s %s" % (temp_png, img_filename) - print(commands.getoutput(cmd)) - - -def save_svg(drawing, filename, width, height): - """Render drawing to an SVG file. - """ - surface = get_surface(width, height, 'svg', filename) - context = cairo.Context(surface) - render(drawing, context, width, height) - context.show_page() - surface.finish() - print("Saved SVG to %s" % filename) - - -def save_pdf(drawing, filename, width, height): - """Render drawing to a PDF file. - """ - surface = get_surface(width, height, 'pdf', filename) - context = cairo.Context(surface) - render(drawing, context, width, height) - context.show_page() - surface.finish() - print("Saved PDF to %s" % filename) - - -def save_ps(drawing, filename, width, height): - """Render drawing to a PostScript file. - """ - surface = get_surface(width, height, 'ps', filename) - context = cairo.Context(surface) - render(drawing, context, width, height) - context.show_page() - surface.finish() - print("Saved PostScript to %s" % filename) - - -### -------------------------------------------------------------------- -### Demo functions -### -------------------------------------------------------------------- -def draw_fontsize_demo(drawing): - """Draw font size samples on the given drawing. - """ - assert isinstance(drawing, Drawing) - - # Save context - drawing.save() - # TODO: Remove this scaling hack - drawing.scale(800.0/720, 600.0/480) - - # Draw white text in a range of sizes - drawing.set_source('white') - - for size in [12, 16, 20, 24, 28, 32]: - ypos = size * size / 5 - drawing.font('Nimbus Sans') - drawing.font_size(size) - drawing.text("%s pt: The quick brown fox" % size, 700, ypos, 'right') - - # Restore context - drawing.restore() - - -def draw_font_demo(drawing): - """Draw samples of different fonts on the given drawing. - """ - assert isinstance(drawing, Drawing) - - # Save context - drawing.save() - # TODO: Remove this scaling hack - drawing.scale(800.0/720, 600.0/480) - - fontsize = 24 - drawing.font_size(fontsize) - fonts = [ - 'Arial', - 'Baskerville', - 'Dragonwick', - 'Georgia', - 'Helvetica', - 'Linotext', - 'Luxi Mono', - 'Nimbus Sans', - 'Old-Town', - 'Sharktooth', - 'Tahoma', - 'Times'] - ypos = 0 - for font in fonts: - drawing.font(font) - # Transparent shadow - drawing.set_source('darkblue', 0.4) - drawing.text(font, 3, ypos+3) - # White text - drawing.set_source('white', 1.0) - drawing.text(font, 0, ypos) - ypos += fontsize - - # Restore context - drawing.restore() - - -def draw_shape_demo(drawing): - """Draw shape samples on the given drawing. - """ - assert isinstance(drawing, Drawing) - - # Save context - drawing.save() - # TODO: Remove this scaling hack - drawing.scale(800.0/720, 600.0/480) - - # Large orange circle with black stroke - drawing.save() - drawing.stroke_width(12) - # Circle at (500, 200), with radius 200 - drawing.circle(500, 200, 200) - drawing.stroke('black') - drawing.fill('orange') - drawing.restore() - - # Grey-stroked blue circles - drawing.save() - # TODO: - # All circles have the same stroke width and color (and, in other cases, - # might all have the same fill style as well). A simpler interface is - # called for, e.g.: - # drawing.set_style(fill='#8080FF', stroke='#777', stroke_width=2) - # drawing.circle((65, 50), 15) - # drawing.circle((65, 100), 10) - # drawing.circle((65, 150), 5) - # drawing.set_style(fill='black') # stroke stays the same as before - # drawing.rectangle((40, 30), (50, 150)) - - drawing.stroke_width(2) - drawing.circle(65, 50, 15) - drawing.fill('#8080FF') - drawing.stroke('#777') - - drawing.circle(60, 100, 10) - drawing.fill('#2020F0') - drawing.stroke('#777') - - drawing.circle(55, 150, 5) - drawing.fill('#0000A0') - drawing.stroke('#777') - drawing.restore() - - # Semitransparent green rectangles - drawing.save() - drawing.translate(50, 400) - for scale in [0.2, 0.4, 0.7, 1.1, 1.6, 2.2, 2.9, 3.7]: - drawing.save() - drawing.translate(scale * 70, scale * -50) - drawing.scale(scale, scale) - drawing.stroke_width(scale) - # roundrectangle broken? - drawing.roundrectangle(-30, -30, 30, 30, 8, 8) - #drawing.rectangle(-30, -30, 30, 30) - drawing.fill('lightgreen', scale / 5.0) - drawing.stroke('black') - drawing.restore() - drawing.restore() - - # Restore context - drawing.restore() - - -def draw_stroke_demo(drawing): - """Draw a stroke/strokewidth demo on the given drawing. - """ - assert isinstance(drawing, Drawing) - - # Save context - drawing.save() - # TODO: Remove this scaling hack - drawing.scale(800.0/720, 600.0/480) - - for width in [1, 2, 4, 6, 8, 10, 12, 14, 16]: - drawing.stroke_width(width) - rgb = ((255 - width * 8), (120 - width * 5), 0) - offset = width * 10 - drawing.line(0, offset, -offset, offset) - drawing.stroke('rgb(%s,%s,%s)' % rgb) - - # Restore context - drawing.restore() - - -if __name__ == '__main__': - mytime = time.time() # Benchmark - - drawing = Drawing(800, 600) - - # Start a new - drawing.save() - - # Add a background fill - #->Background - drawing.set_source('darkgray') - drawing.rectangle(0, 0, 800, 600) - drawing.fill() - - # Shape demo - drawing.save() - draw_shape_demo(drawing) - drawing.restore() - - # Font size demo - drawing.save() - draw_fontsize_demo(drawing) - drawing.restore() - - # Stroke demo - drawing.save() - drawing.translate(680, 240) - draw_stroke_demo(drawing) - drawing.restore() - - # Font face demo - drawing.save() - drawing.translate(60, 160) - draw_font_demo(drawing) - drawing.restore() - - # Close out the Cairo rendering... - drawing.restore() - - print("Took %f seconds" % (time.time() - mytime)) - - # Render and display the Drawing at several different sizes - resolutions = [(352, 240), (352, 480), (720, 480), (800, 600)] - #resolutions = [(720, 480)] - for w, h in resolutions: - display(drawing, w, h) - - #save_svg(drawing, "/tmp/drawing.svg", 400, 300) - #save_pdf(drawing, "/tmp/drawing.pdf", 400, 300) - #save_ps(drawing, "/tmp/drawing.ps", 400, 300)
View file
tovid-0.34.tar.bz2/libtovid/render/effect.py
Deleted
@@ -1,457 +0,0 @@ -"""This module defines classes for creating and drawing effects on a series -of drawings (as in a Flipbook). - -Effect classes are arranged in a (currently) simple hierarchy:: - - Effect (base class) - Movement - Translate - Fade - FadeInOut - Colorfade - Spectrum - Scale - Whirl - PhotoZoom - KeyFunction - -""" - -__all__ = [ - 'Effect', - 'Movement', - 'Translate', - 'Fade', - 'FadeInOut', - 'Colorfade', - 'Spectrum', - 'Scale', - 'Whirl', - 'PhotoZoom', - 'KeyFunction', -] - -from libtovid.render.drawing import Drawing -from libtovid.render.animation import Keyframe, Tween -from random import randint - -class Effect: - """A "special effect" created by keyframing a Cairo drawing command - along the given frame interval. - """ - def __init__(self, start, end): - """Create an effect lasting from start frame to end frame. - """ - self.start = start - self.end = end - # List of Keyframes - self.keyframes = [Keyframe(self.start, 0), Keyframe(self.end, 0)] - self.tween = Tween(self.keyframes) - - # Parents - self._parent_flipbook = None - self._parent_layer = None - - - def init_parent_flipbook(self, fb): - self._parent_flipbook = fb - - - def init_parent_layer(self, layer): - self._parent_layer = layer - - - def pre_draw(self, drawing, frame): - """Set up effect elements that must be applied before drawing a Layer. - - drawing - The Drawing to apply effects to - frame - The frame for which to render the effect - - Extend this function in derived classes. - """ - drawing.save() - - - def post_draw(self, drawing, frame): - """Finalize effect elements after a Layer is drawn. - - drawing - The Drawing to apply effects to - frame - The frame for which to render the effect - - Extend this function in derived classes. - """ - drawing.restore() - - -# New Effect template -# -# Copy and paste this code to create your own Effect -# -# The first line defines your effect's name. (Effect) means it inherits from -# the base Effect class, and shares some properties with it. - -class MyEffect (Effect): - """Modify this documentation string to describe what your effect does. - """ - # The __init__ function is called whenever a MyEffect is created. Make - # sure your __init__ takes start and end arguments; additional arguments - # (such as start_val and end_val below) allow someone using your effect - # class to customize its behavior in some way. See the other effects below - # for examples. - def __init__(self, start, end, start_val, end_val): - """Create a MyEffect lasting from start to end frame. - """ - # Be sure to call this first-thing: - Effect.__init__(self, start, end) - # It initializes the base Effect class with start and end frames. - - # Next, define any keyframes your effect needs to use. This - # effect just varies something from start_val to end_val: - self.keyframes = [ - Keyframe(start, start_val), - Keyframe(end, end_val) - ] - - # Call this afterwards, to calculate the values at all frames - self.tween = Tween(self.keyframes) - - def draw(self, drawing, frame): - """Undocumented""" - # Example function that can be called when drawing a layer. - # The Layer must know that his particular effect requires the - # calling of this function, or to add special parameters, or to - # draw between items in the layer. - - # First, it's good to make sure we really have a Drawing class - assert isinstance(drawing, Drawing) - - # This effect varies the stroke width across a sequence of frames. - # Replace 'stroke_width' with your own drawing function(s) - drawing.stroke_width(self.tween[frame]) - - # Effect rendering occurs in two phases: pre_draw and post_draw. - # These functions are already defined in the Effect base class; extend - # them to do your effect rendering. - def pre_draw(self, drawing, frame): - """Do preliminary effect rendering.""" - # Always call the base class pre_draw first: - Effect.pre_draw(self, drawing, frame) - - # This effect varies the stroke width across a sequence of frames. - # Replace 'stroke_width' with your own drawing function(s) - drawing.stroke_width(self.tween[frame]) - - # Extend post_draw to do any post-rendering cleanup you need to do. Most - # of the time, you won't need to extend this, but if you do, be sure to - # call the base class post_draw at the end: - def post_draw(self, drawing, frame): - """Do post-drawing cleanup.""" - # Post-drawing cleanup here - Effect.post_draw(self, drawing, frame) - - -class Movement (Effect): - """A movement effect, from one point to another.""" - def __init__(self, start, end, (x0, y0), (x1, y1)): - """Move from start (x0, y0) to end (x1, y1). - """ - Effect.__init__(self, start, end) - self.keyframes = [ - Keyframe(start, (x0, y0)), - Keyframe(end, (x1, y1)) - ] - self.tween = Tween(self.keyframes) - - def pre_draw(self, drawing, frame): - drawing.save() - drawing.translate(*self.tween[frame]) - - def post_draw(self, drawing, frame): - drawing.restore() - -class Translate (Movement): - """Translates the layer to some relative (x,y) coordinates - """ - def __init__(self, start, end, (dx, dy)): - Movement.__init__(self, start, end, (0, 0), (dx, dy)) - - -class Fade (Effect): - """A generic fade effect, varying the opacity of a layer. - """ - def __init__(self, keyframes, method='linear'): - """Fade in from start, for fade_length frames; hold at full - opacity, then fade out for fade_length frames before end. - - fade_length - Number of frames to fade-in from start, and number of - frames to fade-out before end. Everything in-between - is at full opacity. - keyframes - A set of Keyframe() objects, determining the fading - curve. Values of the Keyframe() must be floats ranging - from 0.0 to 1.0 (setting opacity). - method - 'linear' or 'cosine' interpolation - - """ - # A fill-opacity curve, something like: - # ______ 100% - # / \ - # start./ \.end 0% - # - if isinstance(keyframes, list): - if not isinstance(keyframes[0], Keyframe): - raise ValueError, "Must be a list of Keyframe objects" - self.keyframes = keyframes - else: - raise ValueError, "List of Keyframe objects required" - - self.tween = Tween(self.keyframes, method) - - - def pre_draw(self, drawing, frame): - """Called before drawing on a layer. - """ - drawing.push_group() - - - def post_draw(self, drawing, frame): - """Called after drawing on a layer. - """ - assert isinstance(drawing, Drawing) - drawing.pop_group_to_source() - drawing.paint_with_alpha(self.tween[frame]) - -class FadeInOut (Fade): - def __init__(self, start, end, fade_length=30): - """Fade in from start, for fade_length frames; hold at full - opacity, then fade out for fade_length frames before end. - - fade_length - Number of frames to fade-in from start, and number of - frames to fade-out before end. Everything in-between - is at full opacity. - """ - # A fill-opacity curve, something like: - # ______ 100% - # / \ - # start./ \.end 0% - # - self.keyframes = [ - Keyframe(start, 0.0), # Start fading in - Keyframe(start + fade_length, 1.0), # Fade-in done - Keyframe(end - fade_length, 1.0), # Start fading out - Keyframe(end, 0.0) # Fade-out done - ] - - self.tween = Tween(self.keyframes) - -class Colorfade (Effect): - """A color-slide effect between an arbitrary number of RGB colors. - """ - def __init__(self, start, end, (r0, g0, b0), (r1, g1, b1)): - """Fade between the given RGB colors.""" - Effect.__init__(self, start, end) - self.keyframes = [ - Keyframe(start, (r0, g0, b0)), - Keyframe(end, (r1, g1, b1)) - ] - self.tween = Tween(self.keyframes) - - - def pre_draw(self, drawing, frame): - """Set source color""" - drawing.set_source(self.tween[frame]) - - - def post_draw(self, drawing, frame): - pass - - -class Spectrum (Effect): - """A full-spectrum color-fade effect between start and end frames. - """ - def __init__(self, start, end): - Effect.__init__(self, start, end) - step = (end - start) / 6 - self.keyframes = [ - Keyframe(start, (1.0, 0, 0)), - Keyframe(start + step, (1.0, 0, 1.0)), - Keyframe(start + step*2, (0, 0, 1.0)), - Keyframe(start + step*3, (0, 1.0, 1.0)), - Keyframe(start + step*4, (0, 1.0, 0)), - Keyframe(start + step*5, (1.0, 1.0, 0)), - Keyframe(end, (1.0, 0, 0)) - ] - self.tween = Tween(self.keyframes) - - - def pre_draw(self, drawing, frame): - drawing.set_source(self.tween[frame]) - - - def post_draw(self, drawing, frame): - pass - -class Scale (Effect): - """A Scaling effect, from one size to another. - """ - def __init__(self, start, end, (w0, h0), (w1, h1)): - Effect.__init__(self, start, end) - self.keyframes = [ - Keyframe(start, (w0, h0)), - Keyframe(end, (w1, h1)) - ] - self.tween = Tween(self.keyframes) - - - def pre_draw(self, drawing, frame): - drawing.save() - drawing.scale(self.tween[frame]) - - - def post_draw(self, drawing, frame): - drawing.restore() - -class Whirl (Effect): - """Rotates an object a number of times. - """ - def __init__(self, keyframes, center=(0, 0), method='linear', units='deg'): - """Create a Whirl effect - - method - 'linear' or 'cosine', for passing from one angle to another - units - 'deg' or 'rad', the unit used in the Keyframes - """ - if units != 'deg' and units != 'rad': - raise ValueError, "units must be 'rad' (radians) or 'deg' (degrees)" - self.units = units - - if not isinstance(center, tuple): - raise ValueError, "center must be a two-value tuple" - self.center = center - - self.keyframes = keyframes - self.tween = Tween(self.keyframes, method) - - - def pre_draw(self, drawing, frame): - drawing.save() - # how to center the thing ? so you give a rotation point ? - drawing.translate(*self.center) - if self.units is 'deg': - drawing.rotate_deg(self.tween[frame]) - elif self.units is 'rad': - drawing.rotate_rad(self.tween[frame]) - - - def post_draw(self, drawing, frame): - drawing.translate(- self.center[0], - self.center[1]) - drawing.restore() - -class PhotoZoom (Effect): - """Zoom in and create dynamism by moving a picture. - - Normally applies to an Image layer, but can be used with others. - """ - def __init__(self, keyframes, subject=(0, 0), direction=None, - movement=50, method='linear'): - """Create a PhotoZoom effect - - keyframes - 0.0 for beginning of effect, and 1.0 to reach the end, - intermediate values show the intermediate state of the effect. - subject - Position of the subject of interest. That is the point where - the zoom in/out will focus it's attention. - If (0, 0), the focus will be chosen randomly in the 2/3 of - the center of the screen. - direction - 'in', 'out', None (random) - movement - 0 to 100, percentage of movement to create. - method - 'linear' or 'cosine' - """ - if direction not in ['in', 'out', None]: - raise ValueError, "'direction' must be 'in', 'out' or None" - if (direction == None): - self.direction = randint(0, 1) and 'in' or 'out' - else: - self.direction = direction - - print("Zoom in direction: %s" % self.direction) - - self.subject = subject - - self.movement = movement - - self.keyframes = keyframes - self.tween = Tween(self.keyframes, method) - - - def pre_draw(self, drawing, frame): - drawing.save() - - fb = self._parent_flipbook - # Use subject, or randomize in the center 1/3 of the image. - if (self.subject == (0, 0)): - self.subject = (randint(int(0.33 * fb.w), - int(0.66 * fb.w)), - randint(int(0.33 * fb.h), - int(0.66 * fb.h))) - - # Max moving = 25% * pixels estimation * movement factor - zoomfactor = 0.25 * (self.movement / 100.) - - inter = self.tween[frame] - - if (self.direction == 'in'): - gozoom = 1.0 + (1.0 - inter) * zoomfactor - else: - gozoom = 1.0 + inter * zoomfactor - - drawing.scale_centered(self.subject[0], self.subject[1], - gozoom, gozoom) - - - def post_draw(self, drawing, frame): - drawing.restore() - -class KeyFunction (Effect): - """A keyframed effect on an arbitrary Drawing function. - """ - def __init__(self, draw_function, keyframes, method='linear'): - """Create an effect using the given Drawing function, with values - determined by the given list of Keyframes. For example:: - - KeyFunction(Drawing.stroke_width, - [Keyframe(1, 1), Keyframe(30, 12)]) - - This says to vary the stroke width from 1 (at frame 1) to 12 (at - frame 30). - - The 'method' argument defines an interpolation method to use between - keyframes, and may be either 'linear' or 'cosine'. - """ - # Call base constructor with start and end frames - Effect.__init__(self, keyframes[0].frame, keyframes[-1].frame) - # TODO: Make sure a valid function name is given - self.draw_function = draw_function - self.keyframes = keyframes - # Tween keyframes using the given interpolation method - self.tween = Tween(self.keyframes, method) - - def pre_draw(self, drawing, frame): - drawing.save() - self.draw_function(drawing, self.tween[frame]) - - def post_draw(self, drawing, frame): - drawing.restore() -
View file
tovid-0.34.tar.bz2/libtovid/render/flipbook.py
Deleted
@@ -1,428 +0,0 @@ -"""This module provides the Flipbook class, a collection of drawings that, when -displayed in sequence, make up an animation or video. - -Run this module standalone for a demonstration: - - $ python flipbook.py - -To use this module interactively, run 'python' from the command-line, and do: - - >>> from libtovid.render.flipbook import Flipbook - -To create a Flipbook 10 seconds long with 'dvd' and 'ntsc' standards, do: - - >>> flipbook = Flipbook(10, 'dvd', 'ntsc', '4:3') - -You can retrieve the canvas width and height with: - - >>> flipbook.canvas - (640, 480) - >>> flipbook.w - 640 - >>> flipbook.h - 480 - -All drawing upon a Flipbook is achieved through the use of layers (layer.py). -To use them, import the layer module: - - >>> from libtovid.render import layer - -You can add layers to a Flipbook on-the-fly: - - >>> flipbook.add(layer.Background('black')) - >>> flipbook.add(layer.Text("Hello, world")) - -Or, create layers separately before adding them to the Flipbook: - - >>> text = Text("Elephant talk") - >>> flipbook.add(text) - -This latter approach is useful if you plan to apply animation effects to the -Layer. For this, effects classes (effect.py) may be applied. First, import: - - >>> from libtovid.render import effect - -Now, say we want the text "Elephant talk" to move across the screen, say from -(100, 100) to (500, 100) over the course of the first 90 frames. The -effect.Movement class does the trick: - - >>> text.add_effect(effect.Movement(1, 90, (100, 100), (500, 100))) - -You can preview a specific frame of the Flipbook by calling render(): - - >>> flipbook.render(50) - -Or, you can generate all frames and create an .m2v video stream file by calling -render_video(): - - >>> filename = flipbook.render_video() - -See the demo below for more on what's possible with Flipbooks. -""" - -__all__ = ['Flipbook'] - -import os -import sys -import time -import math -import cairo -import shutil -import random -from libtovid.render.animation import Keyframe -from libtovid.render.drawing import Drawing, interlace_drawings -from libtovid.render.drawing import write_ppm, write_png, save_png -from libtovid.render import layer, effect -from libtovid import standard -from libtovid.media import MediaFile -from libtovid.backend import mplex, mplayer, ffmpeg - - -class Flipbook: - """A collection of Drawings that together comprise an animation. - """ - def __init__(self, seconds, format, tvsys, aspect='4:3', interlaced=False): - """Create a flipbook of the given length in seconds, at the given - resolution. - - seconds - Length of flipbook playback in seconds - format - 'dvd', 'vcd', 'svcd', 'dvd-vcd', or 'half-dvd' - tvsys - 'ntsc' or 'pal' - aspect - '4:3' or '16:9' (the latter only for format='dvd') - interlaced - True/False. When enabled, the framerate will be doubled, - but only half the frames (twice the fields) will be rendered. - - Once you've created the Flipbook, you can grab the dimensions - in with the property: - - flipbook.canvas as (width, height) - - and with the two properties: - - flipbook.w (width) - flipbook.h (height) - """ - self.tmpdir = '/tmp' - if 'TMPDIR' in os.environ: - self.tmpdir = os.environ['TMPDIR'] - self.seconds = float(seconds) - self.fps = standard.fps(tvsys) - self.fps_ratio = standard.fps_ratio(tvsys) - if (interlaced): - self.fps *= 2 - self.interlaced = interlaced - self.frames = int(seconds * self.fps) - self.output_size = standard.resolution(format, tvsys) - # TODO: We'll need aspect ratio here.. 4:3 or 16:9 anamorphic ? - self.format = format - self.tvsys = tvsys - if (aspect not in ['4:3', '16:9']): - raise ValueError, "aspect must be: '4:3' or '16:9'" - self.aspect = aspect - self.widescreen = False - if (aspect == '16:9'): - self.widescreen = True - - self.canvas = self.get_canvas_size() - self.w = self.canvas[0] - self.h = self.canvas[1] - - # Empty layers, and currently no drawings. - self.layers = [] - self.drawings = [] - - self.called_init_childs = False - - - def init_childs(self): - """Give access to all descendant layers and effects to their parents. - - In layers, you can access your parent layer (if sublayed) with: - layer._parent_layer - and to the top Flipbook object with: - layer._parent_flipbook - - This function gets called just before rendering a video with - render_video() - - It's also called in emergency if you call directly get_drawing(). - """ - for x in range(0, len(self.layers)): - self.layers[x][0].init_parent_flipbook(self) - self.layers[x][0].init_childs() - - self.called_init_childs = True - - - def stof(self, seconds): - """Return the number of frames to the specified time (in seconds). - """ - return int(self.fps * float(seconds)) - - - def get_canvas_size(self): - """Return the dimensions of the canvas. - """ - #ow = self.output_size[0] - oh = self.output_size[1] - a = self.aspect.split(':') - - # Calculate the square pixels canvas size based on aspect ratio - # and intended output size. - x = float(a[0]) * float(oh) / float(a[1]) - # Make sure they are factor of '2' - nw = int(math.ceil(x / 2.0) * 2) - - # We'll always change only the width, like it seems the standard, - # since on TVs, the number of *lines* can't change (when interlacing - # is into business) - return (nw, oh) - - - def add(self, layer, position=(0, 0)): - """Add a Layer to the flipbook. - """ - self.layers.append((layer, position)) - - - def render(self, frame=1): - """Render the given frame. - """ - print("DEPRECATED FUNCTION.") - exit() - - filename = "/tmp/flipbook_%s.png" % frame - print("Rendering Flipbook frame %s to %s" % (frame, filename)) - drawing = self.get_drawing(frame) - - save_png(drawing, filename, self.output_size[0], self.output_size[1]) - - - def get_drawing(self, frame): - """Get a Drawing of the given frame - - TODO: 0-based or 1-based ? - """ - - # Make sure all layers and effects has been initialized with parents. - if (not self.called_init_childs): - self.init_childs() - - drawing = Drawing(self.canvas[0], self.canvas[1]) - # Draw each layer - for layer, position in self.layers: - drawing.save() - drawing.translate(position[0], position[1]) - # Apply effects and draw - layer.draw_with_effects(drawing, frame) - drawing.restore() - return drawing - - - def render_video(self, out_filename=None): - """Render the flipbook to an .m2v video stream file. - - out_filename - Filename for output. If not specified, a temporary filename - will be given, and returned from the function. - - Return the filename of the output, in both cases. - """ - # Make sure layers and effects have been initialized with parents. - self.init_childs() - - # - # if self.tmpdir = /tmp, we get: - # /tmp - # /tmp/flipbook-120391232-work/ - # /tmp/flipbook-120391232-work/bunch-of-files..m2v, .ac3, etc. - # /tmp/flipbook-120391232.mpg -> final output.. - # - - tmp_prefix = '' - tmp_workdir = '' - while 1: - rnd = random.randint(1000000, 9999999) - tmp_prefix = "%s/flipbook-%s" % (self.tmpdir, rnd) - tmp_workdir = "%s-work" % (tmp_prefix) - - if not os.path.exists(tmp_workdir): - break - - # In case no filename has been specified. - if not out_filename: - out_filename = "%s.mpg" % tmp_workdir - - os.mkdir(tmp_workdir) - - # Encode the frames to an .m2v file - m2v_file = "%s/video.m2v" % tmp_workdir - ac3_file = "%s/audio.ac3" % tmp_workdir - - - try: - #cairo.ImageSurface.get_data - pngorpnm = 'ppmtoy4m -F %s -A %s -Ip -B -S 420mpeg2' % \ - (self.fps_ratio, self.aspect) - _write_img = write_ppm # set write function just below - except: - pngorpnm = 'ppmtoy4m -F %s -A %s -Ip -S 420mpeg2' % \ - (self.fps_ratio, self.aspect) - _write_img = write_png - - # Cinelerra params: -b 0 -q 5 -a 2 -F 4 -I 0 -M 2 -f 8 -R 0 - # TODO: move this to encode.py - # -M (multi-threading, num CPUs) - # - # -b 0 -q 5 - # or - # -b 7500 - pipe = os.popen("%s | mpeg2enc -q 5 -g 45 -G 45 -f 8 -a 2 -I 0 " - "-o '%s'" % (pngorpnm, m2v_file), 'w') - - frame = 1 - while frame <= self.frames: - print("Drawing frame %s of %s" % (frame, self.frames)) - - if (self.interlaced): - draw1 = self.get_drawing(frame) - frame += 1 - draw2 = self.get_drawing(frame) - - drawing = interlace_drawings(draw1, draw2) - else: - drawing = self.get_drawing(frame) - - # jpeg2yuv likes frames to start at 0 - _write_img(drawing, pipe, - self.output_size[0], self.output_size[1], - tmp_workdir) - - frame += 1 - - print("Closing encoder. Output to %s" % out_filename) - pipe.close() - - print("Waiting for encoder to finish...") - time.sleep(0.5) - - os.system("ls -al %s" % m2v_file) - os.system("cp %s /tmp/go.m2v" % m2v_file) - vidonly = mplayer.identify(m2v_file) - - # Fix length - vidonly.length = float(self.seconds) - - outvid = MediaFile(out_filename, self.format, self.tvsys) - outvid.aspect = self.aspect - # Important to render 16:9 video correctly. - outvid.widescreen = self.widescreen - - print("Running audio encoder...") - ffmpeg.encode_audio(vidonly, ac3_file, outvid) - - print("Mplex...") - mplex.mux(m2v_file, ac3_file, outvid) - - # Clean up - print("Cleaning up %s ..." % tmp_workdir) - shutil.rmtree(tmp_workdir) - - print("Output: %s" % out_filename) - return out_filename - - -def draw_text_demo(flipbook): - """Draw a demonstration of Text layers with various effects. - """ - assert isinstance(flipbook, Flipbook) - - last_frame = flipbook.frames - - # Background image - bgd = layer.Background('black') - flipbook.add(bgd) - - text1 = layer.Text(u"Spectrum effect demo", color=None) - text1.add_effect(effect.Spectrum(1, last_frame)) - flipbook.add(text1, (20, 30)) - - #text2 = layer.Text(u"FadeInOut effect demo") - #text2.add_effect(effect.FadeInOut(1, last_frame, last_frame / 4)) - #flipbook.add(text2, (20, 60)) - - text3 = layer.Text(u"Movement effect demo") - text3.add_effect(effect.Movement(1, last_frame, (0, 0), (300, 50))) - flipbook.add(text3, (20, 90)) - - text4 = layer.Text(u"Whirl effect demo", color=None, align='center') - k = [Keyframe(0, 0), - Keyframe(30, 0), - Keyframe(40, 15), - Keyframe(45, -10), - Keyframe(50, 10), - Keyframe(55, -2), - Keyframe(60, 0)] - text4.add_effect(effect.Whirl(k, center=(25, 10), units='deg')) - text4.add_effect(effect.Colorfade(1, last_frame, (1.0, 0, 0), (0, 1.0, 0))) - flipbook.add(text4, (340, 350)) - - text5 = layer.Text(u'Whirl effect demo2 ', color='white', align="center") - k2 = [Keyframe(0, 0), - Keyframe(last_frame, 720)] - text5.add_effect(effect.Whirl(k2, center=(25, 10), units='deg')) - flipbook.add(text5, (450, 400)) - - # Keyframed opacity demos, using both linear and cosine interpolation - pulse = [Keyframe(1, 0.2), - Keyframe(last_frame * 2/10, 1.0), - Keyframe(last_frame * 4/10, 0.2), - Keyframe(last_frame * 6/10, 1.0), - Keyframe(last_frame * 8/10, 0.5), - Keyframe(last_frame, 1.0)] - # Text Layers - text_linear = layer.Text("Keyframed opacity (linear)", color='lightgreen') - text_cosine = layer.Text("Keyframed opacity (cosine)", color='lightgreen') - # Effects - eff_linear = effect.Fade(pulse, 'linear') - eff_cosine = effect.Fade(pulse, 'cosine') - # Graph of the keyframe effects - graph_linear = layer.InterpolationGraph(pulse, method='linear') - graph_cosine = layer.InterpolationGraph(pulse, method='cosine') - # Add effects to the text layers - text_linear.add_effect(eff_linear) - text_cosine.add_effect(eff_cosine) - # Add layers to the flipbook - flipbook.add(text_linear, (20, 150)) - flipbook.add(graph_linear, (20, 180)) - flipbook.add(text_cosine, (340, 150)) - flipbook.add(graph_cosine, (340, 180)) - - -if __name__ == '__main__': - start_time = time.time() # Benchmark - - if len(sys.argv) > 1: - seconds = int(sys.argv[1]) - else: - seconds = 3 - flip = Flipbook(seconds, 'dvd', 'ntsc') - - draw_text_demo(flip) - - # Video clip - #clip = layer.VideoClip(video, (320, 240)) - #clip.rip_frames(0, 90) - #clip.effects.append(effect.Fade(1, 90, 20)) - #flip.add(clip, (260, 200)) - - # Render the final video - filename = flip.render_video('/tmp/flipbook.mpg') - - print("Took %f seconds to render: %s" % (time.time() - start_time, filename)) -
View file
tovid-0.34.tar.bz2/libtovid/render/layer.py
Deleted
@@ -1,898 +0,0 @@ -"""This module provides a Layer class and several derivatives. A Layer -is a graphical overlay that may be composited onto an image canvas. - -Run this script standalone for a demonstration: - - $ python libtovid/layer.py - -Layer subclasses may combine graphical elements, including other Layers, -into a single interface for drawing and customizing those elements. Layers may -exhibit animation, through the use of keyframed drawing commands, or through -use of the Effect class (and its subclasses, as defined in libtovid/effect.py). - -Each Layer subclass provides (at least) an __init__ function, and a draw -function. For more on how to use Layers, see the Layer class definition and -template example below. -""" - -__all__ = [ - 'Layer', - 'Background', - 'Text', - 'ShadedText', - 'Label', - 'VideoClip', - 'Image', - 'Thumb', - 'ThumbGrid', - 'SafeArea', - 'Scatterplot', - 'InterpolationGraph', - 'ColorBars', -] - -import os -import sys -import math -import commands -from libtovid.util import get_file_type -from libtovid.render.drawing import Drawing, save_image -from libtovid.render.effect import Effect -from libtovid.render.animation import Keyframe, Tween -from libtovid.media import MediaFile -from libtovid.backend import transcode -from libtovid import log - -class Layer: - """A visual element, or a composition of visual elements. Conceptually - similar to a layer in the GIMP or Photoshop, with support for animation - effects and sub-Layers. - """ - def __init__(self): - """Initialize the layer. Extend this in derived classes to accept - configuration settings for drawing the layer; call this function - from any derived __init__ functions. - """ - self.effects = [] - self.sublayers = [] - self._parent_flipbook = None - self._parent_layer = None - - ### - ### Child-parent initialization - ### - def init_childs(self): - """Give access to all descendant layers and effects to their parents. - - In layers, you can access your parent layer (if sublayed) with: - layer._parent_layer - and to the top Flipbook object with: - layer._parent_flipbook - """ - for x in range(0, len(self.effects)): - self.effects[x].init_parent_flipbook(self._parent_flipbook) - self.effects[x].init_parent_layer(self) - for x in range(0, len(self.sublayers)): - self.sublayers[x][0].init_parent_flipbook(self._parent_flipbook) - self.sublayers[x][0].init_parent_layer(self) - self.sublayers[x][0].init_childs(self) - - def init_parent_flipbook(self, flipbook): - self._parent_flipbook = flipbook - - def init_parent_layer(self, layer): - self._parent_layer = layer - - - ### - ### Derived-class interface - ### - - def draw(self, drawing, frame): - """Draw the layer and all sublayers onto the given Drawing. Override - this function in derived layers. - """ - assert isinstance(drawing, Drawing) - - ### - ### Sublayer and effect interface - ### - - def add_sublayer(self, layer, position=(0, 0)): - """Add the given Layer as a sublayer of this one, at the given position. - Sublayers are drawn in the order they are added; each sublayer may have - its own effects, but the parent Layer's effects apply to all sublayers. - """ - assert isinstance(layer, Layer) - self.sublayers.append((layer, position)) - - def draw_sublayers(self, drawing, frame): - """Draw all sublayers onto the given Drawing for the given frame. - """ - assert isinstance(drawing, Drawing) - for sublayer, position in self.sublayers: - drawing.save() - drawing.translate(*position) - sublayer.draw(drawing, frame) - drawing.restore() - - def add_effect(self, effect): - """Add the given Effect to this Layer. A Layer may have multiple effects - applied to it; all effects apply to the current layer, and all sublayers. - """ - assert isinstance(effect, Effect) - self.effects.append(effect) - - def draw_with_effects(self, drawing, frame): - """Render the entire layer, with all effects applied. - - drawing: A Drawing object to draw the Layer on - frame: The frame number that is being drawn - - """ - # Do preliminary effect rendering - for effect in self.effects: - effect.pre_draw(drawing, frame) - # Draw the layer and sublayers - self.draw(drawing, frame) - # Close out effect rendering, in reverse (nested) order - for effect in reversed(self.effects): - effect.post_draw(drawing, frame) - - -# Layer template -# -# Copy and paste the following code to create your own Layer. -# -# Layer subclasses should define two things: -# -# __init__(): How to initialize the layer with parameters -# draw(): How do draw the layer on a Drawing -# -# First, declare the layer class name. Include (Layer) to indicate that your -# class is a Layer. - -class MyLayer (Layer): - """Overlapping semitransparent rectangles. - (Modify this documentation string to describe what's in your layer)""" - # Here's the class initialization function, __init__. Define here any - # parameters that might be used to configure your layer's behavior or - # appearance in some way (along with default values, if you like). Here, - # we're allowing configuration of the fill and stroke colors, with default - # values of 'blue' and 'black', respectively: - - def __init__(self, fill_color='blue', stroke_color='black'): - """Create a MyLayer with the given fill and stroke colors.""" - # Initialize the base Layer class. Always do this. - Layer.__init__(self) - # Store the given colors, for later use - self.fill_color = fill_color - self.stroke_color = stroke_color - - # The draw() function is responsible for rendering the contents of the - # layer onto a Drawing. It will use the configuration given to __init__ - # (in this case, fill and stroke colors) to render something onto a Drawing - # associated with a particular frame number: - - def draw(self, drawing, frame): - """Draw MyLayer contents onto the given drawing, at the given frame - number.""" - - # For safety's sake, make sure you really have a Drawing object: - assert isinstance(drawing, Drawing) - - # Save the drawing context. This prevents any upcoming effects or - # style changes from messing up surrounding layers in the Drawing. - drawing.save() - - # Get a Cairo pattern source for the fill and stroke colors - # (TODO: Make this easier, or use a simpler example) - fc = drawing.create_source(self.fill_color, 0.6) - sc = drawing.create_source(self.stroke_color) - - # And a stroke width of 1, say: - drawing.stroke_width(1) - - # Now, draw something. Here, a couple of pretty semitransparent - # rectangles, using the fill and stroke color patterns created earlier: - drawing.rectangle(0, 0, 50, 20) - drawing.fill(fc) - drawing.stroke(sc) - drawing.rectangle(15, 12, 45, 28) - drawing.fill(fc) - drawing.stroke(sc) - - # Be sure to restore the drawing context afterwards: - drawing.restore() - - -class Background (Layer): - """A background that fills the frame with a solid color, or an image.""" - def __init__(self, color='black', filename=''): - Layer.__init__(self) - self.color = color - self.filename = filename - - def draw(self, drawing, frame): - assert isinstance(drawing, Drawing) - log.debug("Drawing Background") - width, height = drawing.size - drawing.save() - # Fill drawing with an image - if self.filename is not '': - drawing.image(0, 0, width, height, self.filename) - # Fill drawing with a solid color - elif self.color: - drawing.rectangle(0, 0, width, height) - drawing.fill(self.color) - drawing.restore() - - -class Image (Layer): - """A rectangular image, scaled to the given size. - - image_source - Can be anything Drawing::image() can accept. - See documentation in render/drawing.py. - """ - def __init__(self, image_source, (x, y), (width, height)): - Layer.__init__(self) - self.size = (width, height) - self.image_source = image_source - self.position = (x, y) - - - def draw(self, drawing, frame=1): - assert isinstance(drawing, Drawing) - log.debug("Drawing Image") - drawing.save() - # Save the source for future calls to draw, so no further - # processing will be necessary. And other effects can be done - # without interferring with the original source. - self.image_source = drawing.image(self.position[0], self.position[1], - self.size[0], self.size[1], - self.image_source) - drawing.restore() - - -class VideoClip (Layer): - """A rectangular video clip, scaled to the given size. - - TODO: num_frames should accept a range [first, end], an int (1-INT) and - rip frames accordingly. For now, it only accepts an INT for the range 1-INT - """ - def __init__(self, filename, (width, height), - position=(0, 0), num_frames=120): - Layer.__init__(self) - self.filename = filename - self.mediafile = MediaFile(filename) - self.size = (width, height) - # List of filenames of individual frames - self.frame_files = [] - # TODO: be able to change hardcoded default values - self.rip_frames(1, num_frames) - # Set (x,y) position - assert(isinstance(position, tuple)) - self.position = position - - def rip_frames(self, start, end): - """Rip frames from the video file, from start to end frames.""" - log.info("VideoClip: Ripping frames %s to %s" % (start, end)) - outdir = '/tmp/%s_frames' % self.filename - self.frame_files = transcode.rip_frames(self.mediafile, outdir, - [start, end]) - - def draw(self, drawing, frame=1): - """Draw ripped video frames to the given drawing. For now, it's - necessary to call rip_frames() before calling this function. - - Video is looped. - """ - assert isinstance(drawing, Drawing) - log.debug("Drawing VideoClip") - if len(self.frame_files) == 0: - log.error("VideoClip: need to call rip_frames() before drawing.") - sys.exit(1) - drawing.save() - # Loop frames (modular arithmetic) - if frame >= len(self.frame_files): - frame = frame % len(self.frame_files) - filename = self.frame_files[frame-1] - drawing.image(self.position, self.size, filename) - drawing.restore() - - -class Text (Layer): - """A simple text string, with size, color and font. - """ - def __init__(self, text, position=(0, 0), color='white', fontsize=20, \ - font='Helvetica', align='left'): - """Create a Text layer. - - text - UTF8 encoded string. - """ - Layer.__init__(self) - self.text = text - self.color = color - self.fontsize = fontsize - self.font = font - self.align = align - # Set (x,y) position - self.position = position - - # TODO: This is gonna be pretty broken... - def extents(self, drawing): - """Return the extents of the text as a (x0, y0, x1, y1) tuple. - """ - assert isinstance(drawing, Drawing) - drawing.save() - drawing.font(self.font) - drawing.font_size(self.fontsize) - x_bearing, y_bearing, width, height, x_adv, y_adv = \ - drawing.text_extents(self.text) - drawing.restore() - # Add current layer's position to the (x,y) bearing of extents - x0 = int(self.position[0] + x_bearing) - y0 = int(self.position[1] + y_bearing) - x1 = int(x0 + width) - y1 = int(y0 + height) - return (x0, y0, x1, y1) - - def draw(self, drawing, frame=1): - assert isinstance(drawing, Drawing) - log.debug("Drawing Text") - # Drop in debugger - drawing.save() - drawing.font(self.font) - drawing.font_size(self.fontsize) - if self.color is not None: - drawing.set_source(self.color) - # TODO: DO something with the align !! - drawing.text(self.text, self.position[0], self.position[1], self.align) - drawing.restore() - - -class ShadedText (Layer): - """A simple text string, with size, color and font. - """ - def __init__(self, text, position=(0, 0), offset=(5, 5), - color='white', shade_color='gray', fontsize=20, - font='Nimbus Sans', align='left'): - Layer.__init__(self) - shade_position = (position[0] + offset[0], - position[1] + offset[1]) - self.under = Text(text, shade_position, shade_color, - fontsize, font, align) - self.over = Text(text, position, color, fontsize, font, align) - - def draw(self, drawing, frame=1): - assert isinstance(drawing, Drawing) - log.debug("Drawing Text") - drawing.save() - self.under.draw(drawing, frame) - self.over.draw(drawing, frame) - drawing.restore() - - -class Label (Text): - """A text string with a rectangular background. - - You can access Text's extents() function from within here too. - """ - def __init__(self, text, position=(0, 0), color='white', bgcolor='#555', - fontsize=20, font='NimbusSans'): - Text.__init__(self, text, position, color, fontsize, font) - self.bgcolor = bgcolor - # Set (x,y) position - assert(isinstance(position, tuple)) - self.position = position - - def draw(self, drawing, frame=1): - assert isinstance(drawing, Drawing) - log.debug("Drawing Label") - #(dx, dy, w, h, ax, ay) = self.extents(drawing) - (x0, y0, x1, y1) = self.extents(drawing) - # Save context - drawing.save() - - # Calculate rectangle dimensions from text size/length - width = x1 - x0 - height = y1 - y0 - # Padding to use around text - pad = self.fontsize / 3 - # Calculate start and end points of background rectangle - start = (-pad, -height - pad) - end = (width + pad, pad) - - # Draw a stroked round rectangle - drawing.save() - drawing.stroke_width(1) - drawing.roundrectangle(start[0], start[1], end[0], end[1], pad, pad) - drawing.stroke('black') - drawing.fill(self.bgcolor, 0.3) - drawing.restore() - - # Call base Text class to draw the text - Text.draw(self, drawing, frame) - - # Restore context - drawing.restore() - - -class Thumb (Layer): - """A thumbnail image or video. - """ - def __init__(self, filename, (width, height), position=(0, 0), title=''): - Layer.__init__(self) - self.filename = filename - self.size = (width, height) - self.title = title or os.path.basename(filename) - # Set (x,y) position - assert(isinstance(position, tuple)) - self.position = position - - # Determine whether file is a video or image, and create the - # appropriate sublayer - filetype = get_file_type(filename) - if filetype == 'video': - self.add_sublayer(VideoClip(filename, self.size, self.position)) - elif filetype == 'image': - self.add_sublayer(Image(filename, self.size, self.position)) - self.lbl = Label(self.title, fontsize=15) - self.add_sublayer(self.lbl, self.position) - - def draw(self, drawing, frame=1): - assert isinstance(drawing, Drawing) - log.debug("Drawing Thumb") - drawing.save() - (x0, y0, x1, y1) = self.lbl.extents(drawing) - drawing.translate(0, x1-x0) - self.draw_sublayers(drawing, frame) - drawing.restore() - - -class ThumbGrid (Layer): - """A rectangular array of thumbnail images or videos.""" - def __init__(self, files, titles=None, (width, height)=(600, 400), - (columns, rows)=(0, 0), aspect=(4,3)): - """Create a grid of thumbnail images or videos from a list of files, - fitting in a space no larger than the given size, with the given number - of columns and rows. Use 0 to auto-layout columns or rows, or both - (default). - """ - assert files != [] - if titles: - assert len(files) == len(titles) - else: - titles = files - Layer.__init__(self) - self.size = (width, height) - # Auto-dimension (using desired rows/columns, if given) - self.columns, self.rows = \ - self._fit_items(len(files), columns, rows, aspect) - # Calculate thumbnail size, keeping aspect - w = (width - self.columns * 16) / self.columns - h = w * aspect[1] / aspect[0] - thumbsize = (w, h) - - # Calculate thumbnail positions - positions = [] - for row in range(self.rows): - for column in range(self.columns): - x = column * (width / self.columns) - y = row * (height / self.rows) - positions.append((x, y)) - - # Add Thumb sublayers - for file, title, position in zip(files, titles, positions): - title = os.path.basename(file) - self.add_sublayer(Thumb(file, thumbsize, (0, 0), title), position) - - def _fit_items(self, num_items, columns, rows, aspect=(4, 3)): - # Both fixed, nothing to calculate - if columns > 0 and rows > 0: - # Make sure num_items will fit (columns, rows) - if num_items < columns * rows: - return (columns, rows) - # Not enough room; auto-dimension both - else: - log.warning("ThumbGrid: Can't fit %s items" % num_items +\ - " in (%s, %s) grid;" % (columns, rows) +\ - " doing auto-dimensioning instead.") - columns = rows = 0 - # Auto-dimension to fit num_items - if columns == 0 and rows == 0: - # TODO: Take aspect ratio into consideration to find an optimal fit - root = int(math.floor(math.sqrt(num_items))) - return ((1 + num_items / root), root) - # Rows fixed; use enough columns to fit num_items - if columns == 0 and rows > 0: - return ((1 + num_items / rows), rows) - # Columns fixed; use enough rows to fit num_items - if rows == 0 and columns > 0: - return (columns, (1 + num_items / columns)) - - def draw(self, drawing, frame=1): - assert isinstance(drawing, Drawing) - log.debug("Drawing ThumbGrid") - drawing.save() - self.draw_sublayers(drawing, frame) - drawing.restore() - - -class SafeArea (Layer): - """Render a safe area box at a given percentage. - """ - def __init__(self, percent, color): - self.percent = percent - self.color = color - - def draw(self, drawing, frame=1): - assert isinstance(drawing, Drawing) - log.debug("Drawing SafeArea") - # Calculate rectangle dimensions - scale = float(self.percent) / 100.0 - width, height = drawing.size - topleft = ((1.0 - scale) * width / 2, - (1.0 - scale) * height / 2) - # Save context - drawing.save() - drawing.translate(topleft[0], topleft[1]) - # Safe area box - drawing.stroke_width(3) - drawing.rectangle(0, 0, width * scale, height * scale) - drawing.stroke(self.color) - # Label - drawing.font_size(18) - drawing.set_source(self.color) - drawing.text(u"%s%%" % self.percent, 10, 20) - # Restore context - drawing.restore() - - -class Scatterplot (Layer): - """A 2D scatterplot of data. - """ - def __init__(self, xy_dict, width=240, height=80, x_label='', y_label=''): - """Create a scatterplot using data in xy_dict, a dictionary of - lists of y-values, indexed by x-value. - """ - self.xy_dict = xy_dict - self.width, self.height = (width, height) - self.x_label = x_label - self.y_label = y_label - - def draw(self, drawing, frame): - """Draw the scatterplot.""" - assert isinstance(drawing, Drawing) - log.debug("Drawing Scatterplot") - width, height = (self.width, self.height) - x_vals = self.xy_dict.keys() - max_y = 0 - for x in x_vals: - largest = max(self.xy_dict[x] or [0]) - if largest > max_y: - max_y = largest - # For numeric x, scale by maximum x-value - x_is_num = isinstance(x_vals[0], int) or isinstance(x_vals[0], float) - if x_is_num: - x_scale = float(width) / max(x_vals) - # For string x, scale by number of x-values - else: - x_scale = float(width) / len(x_vals) - # Scale y according to maximum value - y_scale = float(height) / max_y - - # Save context - drawing.save() - drawing.rectangle(0, 0, width, height) - drawing.fill('white', 0.75) - - # Draw axes - #->comment("Axes of scatterplot") - drawing.save() - drawing.stroke_width(2) - drawing.line(0, 0, 0, height) - drawing.stroke('black') - drawing.line(0, height, width, height) - drawing.stroke('black') - drawing.restore() - - # Axis labels - drawing.save() - drawing.set_source('blue') - - drawing.save() - for i, x in enumerate(x_vals): - drawing.save() - if x_is_num: - drawing.translate(x * x_scale, height + 15) - else: - drawing.translate(i * x_scale, height + 15) - drawing.rotate(30) - drawing.text(x, 0, 0) - drawing.restore() - - drawing.font_size(20) - drawing.text(self.x_label, width/2, height+40) - drawing.restore() - - drawing.save() - drawing.text(max_y, -30, 0) - drawing.translate(-25, height/2) - drawing.rotate(90) - drawing.text(self.y_label, 0, 0) - drawing.restore() - - drawing.restore() - - # Plot all y-values for each x (as small circles) - #->comment("Scatterplot data") - drawing.save() - for i, x in enumerate(x_vals): - if x_is_num: - x_coord = x * x_scale - else: - x_coord = i * x_scale - # Shift x over slightly - x_coord += 10 - # Plot all y-values for this x - for y in self.xy_dict[x]: - y_coord = height - y * y_scale - drawing.circle(x_coord, y_coord, 3) - drawing.fill('red', 0.2) - drawing.restore() - - # Restore context - drawing.restore() - - -class InterpolationGraph (Layer): - # TODO: Support graphing of tuple data - """A graph of an interpolation curve, defined by a list of Keyframes and - an interpolation method. - """ - def __init__(self, keyframes, size=(240, 80), method='linear'): - """Create an interpolation graph of the given keyframes, at the given - size, using the given interpolation method. - """ - Layer.__init__(self) - - self.keyframes = keyframes - self.size = size - self.method = method - # Interpolate keyframes - self.tween = Tween(keyframes, method) - - def draw(self, drawing, frame): - """Draw the interpolation graph, including frame/value axes, - keyframes, and the interpolation curve.""" - assert isinstance(drawing, Drawing) - log.debug("Drawing InterpolationGraph") - data = self.tween.data - # Calculate maximum extents of the graph - width, height = self.size - x_scale = float(width) / len(data) - y_scale = float(height) / max(data) - - #->drawing.comment("InterpolationGraph Layer") - - # Save context - drawing.save() - - # Draw axes - #->drawing.comment("Axes of graph") - drawing.save() - drawing.stroke_width(3) - drawing.polyline([(0, 0), (0, height), (width, height)], False) - drawing.stroke('#ccc') - drawing.restore() - - # Create a list of (x, y) points to be graphed - curve = [] - x = 1 - while x <= len(self.tween.data): - # y increases downwards; subtract from height to give a standard - # Cartesian-oriented graph (so y increases upwards) - point = (int(x * x_scale), int(height - data[x-1] * y_scale)) - curve.append(point) - x += 1 - drawing.save() - # Draw the curve - drawing.stroke_width(2) - drawing.polyline(curve, False) - drawing.stroke('blue') - drawing.restore() - - # Draw Keyframes as dotted vertical lines - drawing.save() - # Vertical dotted lines - drawing.set_source('red') - drawing.stroke_width(2) - for key in self.keyframes: - x = int(key.frame * x_scale) - drawing.line(x, 0, x, height) - drawing.stroke('red') - - # Draw Keyframe labels - drawing.set_source('white') - for key in self.keyframes: - x = int(key.frame * x_scale) - y = int(height - key.data * y_scale - 3) - drawing.text(u"(%s,%s)" % (key.frame, key.data), x, y) - - drawing.restore() - - # Draw a yellow dot for current frame - #->drawing.comment("Current frame marker") - drawing.save() - pos = (frame * x_scale, height - data[frame-1] * y_scale) - drawing.circle(pos[0], pos[1], 2) - drawing.fill('yellow') - drawing.restore() - - # Restore context - drawing.restore() - - -class ColorBars (Layer): - """Standard SMPTE color bars - (http://en.wikipedia.org/wiki/SMPTE_color_bars) - """ - def __init__(self, size, position=(0, 0)): - """Create color bars in a region of the given size and position. - """ - Layer.__init__(self) - self.size = size - # Set (x,y) position - assert(isinstance(position, tuple)) - self.position = position - - def draw(self, drawing, frame=1): - assert isinstance(drawing, Drawing) - log.debug("Drawing ColorBars") - x, y = self.position - width, height = self.size - - drawing.save() - # Get to the right place and size - drawing.translate(x, y) - drawing.scale(width, height) - # Video-black background - drawing.rectangle(0, 0, 1, 1) - drawing.fill('rgb(16, 16, 16)') - - # Top 67% of picture: Color bars at 75% amplitude - top = 0 - bottom = 2.0 / 3 - seventh = 1.0 / 7 - size = (seventh, bottom) - bars = [(0, top, seventh, bottom, 'rgb(191, 191, 191)'), - (seventh, top, seventh, bottom, 'rgb(191, 191, 0)'), - (2*seventh, top, seventh, bottom, 'rgb(0, 191, 191)'), - (3*seventh, top, seventh, bottom, 'rgb(0, 191, 0)'), - (4*seventh, top, seventh, bottom, 'rgb(191, 0, 191)'), - (5*seventh, top, seventh, bottom, 'rgb(191, 0, 0)'), - (6*seventh, top, seventh, bottom, 'rgb(0, 0, 191)')] - - # Next 8% of picture: Reverse blue bars - top = bottom - bottom = 0.75 - height = bottom - top - bars.extend([(0, top, seventh, height, 'rgb(0, 0, 191)'), - (seventh, top, seventh, height, 'rgb(16, 16, 16)'), - (2*seventh, top, seventh, height, 'rgb(191, 0, 191)'), - (3*seventh, top, seventh, height, 'rgb(16, 16, 16)'), - (4*seventh, top, seventh, height, 'rgb(0, 191, 191)'), - (5*seventh, top, seventh, height, 'rgb(16, 16, 16)'), - (6*seventh, top, seventh, height, 'rgb(191, 191, 191)')]) - - # Lower 25%: Pluge signal - top = bottom - bottom = 1.0 - sixth = 1.0 / 6 - height = bottom - top - bars.extend([(0, top, 1.0, height, 'rgb(16, 16, 16)'), - (0, top, sixth, height, 'rgb(0, 29, 66)'), - (sixth, top, sixth, height, 'rgb(255, 255, 255)'), - (2*sixth, top, sixth, height, 'rgb(44, 0, 92)'), - # Sub- and super- black narrow bars - (4*sixth, top, 0.33*sixth, height, 'rgb(7, 7, 7)'), - (4.33*sixth, top, 0.33*sixth, height,'rgb(16, 16, 16)'), - (4.66*sixth, top, 0.33*sixth, height, 'rgb(24, 24, 24)')]) - - # Draw and fill all bars - for x, y, width, height, color in bars: - drawing.rectangle(x, y, width, height) - drawing.fill(color) - - drawing.restore() - - - - -if __name__ == '__main__': - images = None - # Get arguments, if any - if len(sys.argv) > 1: - # Use all args as image filenames to ThumbGrid - images = sys.argv[1:] - - # A Drawing to render Layer demos to - drawing = Drawing(800, 600) - - # Draw a background layer - bgd = Background(color='#7080A0') - bgd.draw(drawing, 1) - - # Draw color bars - bars = ColorBars((320, 240), (400, 100)) - bars.draw(drawing, 1) - - # Draw a label - drawing.save() - drawing.translate(460, 200) - label = Label("tovid loves Linux") - label.draw(drawing, 1) - drawing.restore() - - # Draw a text layer, with position. - text = Text("Jackdaws love my big sphinx of quartz", - (82, 62), '#bbb') - text.draw(drawing, 1) - - # Draw a text layer - drawing.save() - drawing.translate(80, 60) - text = Text("Jackdaws love my big sphinx of quartz") - text.draw(drawing, 1) - drawing.restore() - - # Draw a template layer (overlapping semitransparent rectangles) - template = MyLayer('white', 'darkblue') - # Scale and translate the layer before drawing it - drawing.save() - drawing.translate(50, 100) - drawing.scale(3.0, 3.0) - template.draw(drawing, 1) - drawing.restore() - - # Draw a safe area test (experimental) - safe = SafeArea(93, 'yellow') - safe.draw(drawing, 1) - - # Draw a thumbnail grid (if images were provided) - if images: - drawing.save() - drawing.translate(350, 300) - thumbs = ThumbGrid(images, (320, 250)) - thumbs.draw(drawing, 1) - drawing.restore() - - # Draw an interpolation graph - drawing.save() - drawing.translate(60, 400) - # Some random keyframes to graph - keys = [Keyframe(1, 25), Keyframe(10, 5), Keyframe(30, 35), - Keyframe(40, 35), Keyframe(45, 20), Keyframe(60, 40)] - interp = InterpolationGraph(keys, (400, 120), method="cosine") - interp.draw(drawing, 25) - drawing.restore() - - # Draw a scatterplot - drawing.save() - xy_data = { - 5: [2, 4, 6, 8], - 10: [3, 5, 7, 9], - 15: [5, 9, 13, 17], - 20: [8, 14, 20, 26]} - drawing.translate(550, 350) - #drawing.scale(200, 200) - plot = Scatterplot(xy_data, 200, 200, "Spam", "Eggs") - plot.draw(drawing, 1) - drawing.restore() - - log.info("Output to /tmp/my.png") - save_image(drawing, '/tmp/my.png', 800, 600) -
View file
tovid-0.34.tar.bz2/libtovid/runtest.py
Deleted
@@ -1,64 +0,0 @@ -# runtest.py - -"""libtovid test script - -Execute this script to run tests on the modules in libtovid. These tests -consist of executing each libtovid module standalone; it is presumed that -each module to be tested contains at least the following:: - - import unittest - if __name__ == '__main__': - unittest.main() - -which runs unit tests, or:: - - import doctest - if __name__ == '__main__': - doctest.testmod(verbose=True) - -which does an automated verification of the docstrings in each module. - -NB -- You're going to get lots of output, so a ``> log.txt`` is advised. -""" - -import os -import commands -from glob import glob - -libtovid_modules = [ - 'author.py', - 'cli.py', - 'deps.py', - 'encode.py', - 'media.py', - 'odict.py', - 'opts.py', - 'standard.py', - 'stats.py', - 'xml.py', -] - -subdirs = [ - 'backend', - 'metagui', - 'render', - 'template', - 'test', - 'util', -] - -subdir_modules = [] -for subdir in subdirs: - subdir_modules.extend(glob('%s/*.py' % subdir)) - -all_modules = libtovid_modules + subdir_modules - -if __name__ == '__main__': - # Execute each module - for mod in all_modules: - print("Testing: %s" % mod) - try: - print(commands.getoutput('python %s' % mod)) - except KeyboardInterrupt: - print("Test interrupted.") - exit()
View file
tovid-0.34.tar.bz2/libtovid/standard.py
Deleted
@@ -1,147 +0,0 @@ -# standard.py - -"""This module defines functions for retrieving information about multimedia -standards, including functions for determining the appropriate resolution, -video and audio codec, fps, and bitrates for a given format. -""" - -__all__ = [ - 'abitrate', - 'acodec', - 'fps', - 'fps_ratio', - 'resolution', - 'samprate', - 'vbitrate', - 'vcodec', -] - -def resolution(format, tvsys): - """Return the pixel resolution (x,y) for the given format and TV system. - For example:: - - >>> resolution('dvd', 'pal') - (720, 576) - >>> resolution('half-dvd', 'ntsc') - (352, 480) - """ - # Valid resolutions, indexed by format and tvsys - valid_size = { - 'vcd': - {'pal': (352, 288), 'ntsc': (352, 240)}, - 'dvd-vcd': - {'pal': (352, 288), 'ntsc': (352, 240)}, - 'svcd': - {'pal': (480, 576), 'ntsc': (480, 480)}, - 'half-dvd': - {'pal': (352, 576), 'ntsc': (352, 480)}, - 'dvd': - {'pal': (720, 576), 'ntsc': (720, 480)} - } - return valid_size[format][tvsys] - - -def vcodec(format): - """Return the video codec used by the given format. - For example:: - - >>> vcodec('vcd') - 'mpeg1' - >>> vcodec('svcd') - 'mpeg2' - """ - if format == 'vcd': - return 'mpeg1' - else: - return 'mpeg2' - - -def acodec(format): - """Return the audio codec (or codecs) supported by the given format. - For example:: - - >>> acodec('vcd') - 'mp2' - >>> acodec('dvd') - 'ac3' - """ - if format in ['vcd', 'svcd']: - return 'mp2' - else: - return 'ac3' - - -def samprate(format): - """Return the audio sampling rate used by the given format. - """ - if format in ['vcd', 'svcd']: - return 44100 - else: - return 48000 - - -def fps(tvsys): - """Return the number of frames per second for the given TV system. - For example:: - - >>> print(fps('ntsc')) - 29.97 - >>> print(fps('pal')) - 25.0 - """ - # Valid frames per second, by TV system - _fps = { - 'pal': 25.0, - 'ntsc': 29.97, - 'ntscfilm': 23.976, - } - return _fps[tvsys] - - -def fps_ratio(tvsys): - """Return the number of frames per second for the given TV system, - in ratio form. For example:: - - >>> fps_ratio('ntsc') - '30000:1001' - >>> fps_ratio('pal') - '25:1' - """ - # Valid frames per second, by TV system - _fps = { - 'pal': '25:1', - 'ntsc': '30000:1001', - 'ntscfilm': '24000:1001', - } - return _fps[tvsys] - - -def vbitrate(format): - """Return the range (min, max) of valid video bitrates (in kilobits per - second) for the given format. min and max are the same for constant-bitrate - formats. - """ - # Valid video bitrates, indexed by format - valid_bitrates = { - 'vcd': (1150, 1150), - 'svcd': (0, 2600), - 'dvd-vcd': (0, 9800), - 'half-dvd': (0, 9800), - 'dvd': (0, 9800) - } - return valid_bitrates[format] - - -def abitrate(format): - """Return the range (min, max) of valid audio bitrates (in kilobits per - second) for the given format. For constant-bitrate formats, min == max. - """ - if format == 'vcd': - return (224, 224) - elif format == 'svcd': - return (32, 384) - else: - return (32, 1536) - - -
View file
tovid-0.34.tar.bz2/libtovid/stats.py
Deleted
@@ -1,238 +0,0 @@ -# stats.py - -"""Classes and functions for dealing with tovid statistics. - -Future interface ideas: - -* Display certain records, or a range of records (records 1-10; last 15 records; - records with a certain field (or any field) matching given text/regexp -* Display formatted output of all records, or a selection of records, - with control over which fields are displayed - -""" - -import csv -import sys -from copy import copy - -# Order of fields in stats.tovid -FIELDS = [ - 'tovid_version', - 'final_name', - 'length', # a.k.a. CUR_LENGTH - 'format', # RES - 'tvsys', - 'final_size', - 'tgt_bitrate', - 'avg_bitrate', - 'peak_bitrate', - 'gop_minsize', - 'gop_maxsize', - 'encoding_time', # SCRIPT_TOT_TIME - 'cpu_model', - 'cpu_speed', - 'in_vcodec', - 'in_acodec', - 'encoding_mode', - 'in_md5', - 'in_width', - 'in_height', - 'quant', - 'kbpm', - 'enc_time_ratio', - 'backend', - ] - -# Integer numeric fields -int_fields = [ - 'length', - 'avg_bitrate', - 'tgt_bitrate', - 'peak_bitrate', - 'encoding_time', - 'final_size', - 'cpu_speed', - 'in_width', - 'in_height', - 'quant', - 'kbpm', - ] - -class Statlist: - """A list of statistics that may be queried with a simple database-like - interface.""" - def __init__(self, records=None, filename=''): - """Create a Statlist, using the given list of records, or by reading - from the given filename (CSV text). - """ - # Use provided records, if any - if records: - self.records = copy(records) - # Otherwise, read from any provided filename - else: - self.records = [] - if filename != '': - self.read_csv(filename) - - - def read_csv(self, filename): - """Import stats from a CSV (comma-delimited quoted text) file.""" - self.records = [] - statfile = open(filename, 'r') - csv_reader = csv.DictReader(statfile, FIELDS, skipinitialspace=True) - for line in csv_reader: - # Convert some string and numeric fields - line['format'] = str.lower("%s" % line['format']) - line['tvsys'] = str.lower("%s" % line['tvsys']) - for field in int_fields: - try: - num = int("%s" % line[field]) - except (ValueError, TypeError): - num = 0 - line[field] = num - self.records.append(line) - - statfile.close() - print("Read %s lines from %s" % (len(self.records), filename)) - - - def unique(self, field): - """Return a list of unique values of the given field.""" - unique_values = [] - for record in self.records: - if record[field] not in unique_values: - unique_values.append(record[field]) - return unique_values - - - def count_unique(self, field): - """Count the occurrences of each unique value of the given field. - Return a dictionary of unique values and the number of occurrences - of each.""" - counts = {} - # Go through all records and total up occurrences of each value - for record in self.records: - value = record[field] - if value is None or value == '': - pass - elif value not in counts: - counts[value] = 1 - else: - counts[value] += 1 - return counts - - - def average(self, attribute): - """Calculate the average value for a given numeric VidStat attribute. - For example, average('bitrate') returns the average overall bitrate of - all videos in the list.""" - # Error if attribute is non-numeric - if attribute not in int_fields: - print("Can't average %s: not defined as a numeric field") - sys.exit() - - values = [] - for record in self.records: - # Only append non-zero values - if record[attribute] != 0: - values.append(record[attribute]) - if len(values) > 0: - return float(sum(values) / len(values)) - else: - return 0.0 - - - def average_by(self, attribute, by_attribute): - """Return a dictionary of averages of an attribute, indexed by another - attribute. For example, average_by('bitrate', 'format') returns average - bitrates for each format.""" - # Error if attribute is non-numeric - if attribute not in int_fields: - print("Can't average %s: not defined as a numeric field") - sys.exit() - - values_by = self.list_by(attribute, by_attribute) - # Calculate averages for each value-list - averages = {} - if len(values_by) > 0: - for key, samples in values_by.iteritems(): - try: - averages[key] = float(sum(samples) / len(samples)) - except ZeroDivisionError: - averages[key] = 0.0 - return averages - - - def list_by(self, attribute, by_attribute, sort_lists=False): - """Return a dictionary of lists of values of the given attribute, - indexed by another attribute. If sort_lists is True, sort all lists.""" - # Create a dictionary of value-lists, indexed by by_attribute - values_by = {} - for record in self.records: - byval = record[by_attribute] - if not values_by.has_key(byval): - values_by[byval] = [] - # Only include non-zero values - if record[attribute] != 0: - values_by[byval].append(record[attribute]) - if sort_lists: - for index in values_by.iterkeys(): - values_by[index].sort() - return values_by - - - def get_matching(self, attribute, value): - """Return a list of records where the given attribute equals the given - value. Records are field-indexed dictionaries of values. - """ - # List of matching records - matches = [] - for record in self.records: - if record[attribute] == value: - matches.append(record) - return matches - - - def length(self, field): - """Return the length of the longest record in the given field, or the - width of the field name itself, whichever is greater.""" - longest = len(field) - for record in self.records: - cur_len = len(str(record[field])) - if cur_len > longest: - longest = cur_len - return longest - - - def show(self, show_records='all', show_fields='all'): - """Print records matching given criteria, showing only the given fields. - - show_records - Number of record to show, or range of numbers - show_fields - List of fields, by name as shown in FIELDS - """ - # Remember field sizes (character widths) - size = {} - # Create field headings - heading = '' - if show_fields == 'all': - show_fields = FIELDS - for field in show_fields: - if field in FIELDS: - size[field] = self.length(field) - heading += "%s " % str.ljust(field, size[field]) - else: - print("Error: field '%s' does not exist" % field) - sys.exit() - print(heading) - # Print fields from matching records - for record in self.records: - # TODO: support show_records - line = '' - for field in show_fields: - line += "%s " % str.ljust(str(record[field]), size[field]) - print(line) - # Print heading at end too - print(heading) -
View file
tovid-0.34.tar.bz2/libtovid/xml.py
Deleted
@@ -1,138 +0,0 @@ -"""This module is for defining XML elements and attributes, and for creating -element hierarchies. - -To create a new element, use the `Element` constructor, providing at -least the element name:: - - >>> video = Element('video') - -To see an XML representation of the Element:: - - >>> print(video) - <video></video> - -Since this is an empty element with no attributes yet, it's pretty boring. -You can add or change attributes using the `~Element.set` method:: - - >>> video.set(file="Brian.mpg") - >>> print(video) - <video file="Brian.mpg"></video> - -To add children to an element, use the `~Element.add` method:: - - >>> length = video.add('length', '15') - >>> print(video) - <video file="Brian.mpg"> - <length>15</length> - </video> - -See `libtovid.author` and `libtovid.backend.spumux` for additional -examples. -""" - -__all__ = ['Element'] - -class Element (object): - """A named XML element having optional content, attributes, and children. - - Attribute values may be set in the constructor, or by calling `set` with a - dictionary and/or attribute=value keywords. - - Use `add` or `add_child` to create a hierarchy of Elements. - """ - def __init__(self, name, content='', **attributes): - """Create a new Element with the given attributes. - - name - Name of the Element - content - Text content of the Element - attributes - Keyword=value for specific attributes - """ - self.name = name - self.content = content - self.attributes = {} - self.children = [] - # Set attributes from those provided - self.set(**attributes) - - - def set(self, **attributes): - """Set values for one or more attributes. - - attributes - Keyword arguments for setting specific attributes - - Underscores in attribute names are converted to hyphens. If you don't - like this behavior, please suggest a workaround :-) - """ - # Set attribute values; convert underscores to hyphens - for key, value in attributes.iteritems(): - key = key.replace('_', '-') - self.attributes[key] = value - - - def add(self, child_name, content='', **attributes): - """Create and add a new child Element by providing its name, content, - and attributes. Return the newly-added Element. - - child - String name of child element - content - String content of child element - attributes - Keyword arguments for setting child's attributes - - This is a convenience function for creating and adding children - on-the-fly. - """ - child = Element(child_name, content, **attributes) - self.children.append(child) - return child - - - def add_child(self, element): - """Add the given Element as a child of this Element. - """ - assert isinstance(element, Element) - self.children.append(element) - - - def xml(self, indent_level=0): - """Return formatted XML for this Element and all descendants. - """ - indent = ' ' * indent_level - # No children; write a single line - if len(self.children) == 0: - text = indent + self._open() + self.content + self._close() + '\n' - # If children, write an indented block - else: - text = indent + self._open() + self.content + '\n' - for child in self.children: - text += child.xml(indent_level + 1) - text += indent + self._close() + '\n' - return text - - - def __str__(self): - """Return a string containing formatted XML for the Element. - """ - return self.xml().rstrip('\n') - - - def _open(self): - """Return the XML opening tag for the Element. - """ - attribs = '' - for key, value in self.attributes.items(): - attribs += ' %s="%s"' % (key, value) - return '<' + self.name + attribs + '>' - - - def _close(self): - """Return the XML closing tag for the Element. - """ - return '</' + self.name + '>' - -
View file
tovid-0.34.tar.bz2/src/make_titlesets
Deleted
@@ -1,259 +0,0 @@ -#!/bin/bash -# Part of the tovid suite -# ======================= -# A bash script that calls the tovid GUI in order to allow titlesets, -# something the GUI is not capable of on its own at the moment. -# This script depends on the GUI, in addition to the other command -# line scripts of the tovid suite such as todisc, makempg, and idvid. -# -# Project homepage: http://tovid.wikia.com -# -# Copyright (C) 2005-2010 -# -# 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 2 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, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Or see: -# -# http://www.gnu.org/licenses/gpl.txt - - -# Written by Robert ("grepper") Sohn -# grepper at gmail dot com - -############################################################################# -###############################Variables #################################### -############################################################################# -path=$(tovid -prefix) -PATH=$path:$PATH -SEP=$(for i in {1..79}; do printf '='; done) -final_tmp_script=$(mktemp -t todisc.XXXXXXXX) -final_script="$PWD/todisc_commands.bash" - -############################################################################## -################################## Functions ################################# -############################################################################## -# read_script name -read_script() -{ - script_exists=0 - script_name="$1" - # if user just pressed enter, test that the default name exists (it should) - if [[ -z $script_name ]]; then - script_name="$final_script" - [[ -e $script_name ]] && script_exists=1 - fi - # else test if the file name path passed in exists - while ! (( script_exists )); do - read script_name - script_name=$(readlink -f "$script_name") - if [[ -e "$script_name" ]] ; then - script_exists=1 - else - echo "Sorry, $script_name does not point to an existing file." - echo "Please re-enter the path to the script." - echo "You can use the full path or the path relative to $PWD" - fi - done - SCRIPT="$script_name" -} - -run_gui() -{ - todiscgui &>/dev/null & - tovid_pid=$! - sleep 2 - echo $SEP - echo "Make your selections, then save your script and exit GUI to continue..." - wait $tovid_pid - echo $SEP - echo "Press <ENTER> to accept the default path and filename " - echo "for the file you just saved." - echo "Or enter the relative or full path" - echo "[${final_script}]" - read script - read_script "$script" - - todisc_tmp=$(mktemp todisc_tmpXXXXXX) - mv "$SCRIPT" "$todisc_tmp" - echo $SEP - echo "Okay, the content is saved, please save to the same file next time." - echo "Press <ENTER> to continue" - read cont -} - -# clean_script file -clean_script() -{ - file="$1" - # remove shebang and PATH - sed -i '/\#\!\/usr\/bin\/env bash/d;/PATH/d' "$file" - # remove todisc command - sed -i '/^todisc \\$/d' "$file" - # remove opening blank lines - sed -i '/./,/^$/!d' "$file" -} - -############################################################################## -############################ Main body starts here ########################### -############################################################################## - -############################################################################## -############################## General Options ############################### -############################################################################## -cat <<EOF - -$SEP -We are going to create a complete DVD with titlesets and menus. - -I am going to start tovid gui. Please enter the general -options there that you would like to apply to every titleset. -"Output name" (bottom of main screen) is the only required general -option. When you are done, press the 'Save script' button and save to -"${final_script}" -accepting the default filename and making sure you are -in the correct directory. You must then close the GUI in order to continue. - -Press <ENTER> to continue... -EOF -read cont -if [[ -e $final_script ]]; then - new_name=$(TMPDIR=`pwd` mktemp -t todisc_commands.bash.XXXXXX) - echo "The file we will use to save options: \"${final_script}\", - exists in the current directory. It will be renamed: - to $new_name if you continue." |sed 's/^[ \t]*//;s/[ \t]*$//' - echo "press <ENTER> to continue..." - read cont -fi -[[ -e "$final_script" ]] && mv "$final_script" "$new_name" - -run_gui -############################################################################## -################################# VMGM Menu ################################## -############################################################################## - -####################### Titleset Titles for VMGM menu ######################## -cat <<EOF - -Now we will save options for your root (VMGM) menu -The only option you really need is the titleset titles. -Since you can not save titles in the GUI without loading videos -you will need to enter them here. -These titleset names will appear as menu titles for the respective menu -in your DVD -EOF -echo $SEP -echo "Press <ENTER> to continue..." -read cont -cat <<EOF - -Enter the names of your titlesets, one per line pressing <ENTER> each time. -Do not use quotes unless you want them to appear literally in the title. -Type "done" when you are finished. -EOF - -done=0 -while ! ((done)); do - read title - if [[ $title == "done" ]]; then - done=1 - else - MENU_TITLES+=("$title") - fi -done -# add backslash to last line; add -vmgm and -titles; add menu titles -sed -i "\$s/$/ \\\/" "$todisc_tmp" -sed -i '$ a -vmgm \\' "$todisc_tmp" -sed -i '$ a -titles \\' "$todisc_tmp" -printf '"%s" \\\n' "${MENU_TITLES[@]}" >> "$todisc_tmp" -mv "$todisc_tmp" "$final_tmp_script" - -############################# VMGM Menu options ############################## -cat <<EOF - -Now I will bring the GUI up again - enter options for your root -(VMGM) menu. -Remember that this menu (VMGM) does not need video files. -You still have many options, but none are strictly necessary. For example -you may wish to use background (audio and/or image/video), a -showcased image/video, set the fonts, use a "Playall" button... -You should also set the menu title to a new name. When you are done save -the script again to -$final_script -and close the GUI to continue. -EOF -echo "Press <ENTER> to continue..." -read cont -run_gui -clean_script "$todisc_tmp" -# add backslash to last line -sed -i "\$s/$/ \\\/" "$todisc_tmp" -# add -end-vmgm as last line -sed -i '$ a -end-vmgm \\' "$todisc_tmp" -cat "$todisc_tmp" >> "$final_tmp_script" -rm -f "$todisc_tmp" -done=0 - -############################################################################## -################################## Titlesets ################################# -############################################################################## - -echo "Now finally we will make your titlesets" -get_message() -{ - message=$( - cat <<EOF - -Bringing up the GUI for titleset $tset. -Make your titleset, leaving out the general options you gave earlier -unless you wish to change them (-out can not be changed). -Press <ENTER> to continue or type "done" if you have no more titlesets -EOF - ) - echo "$message" -} -while ! ((done)); do - ((tset++)) - get_message - read title - if [[ $title == "done" ]]; then - done=1 - else - run_gui - clean_script "$todisc_tmp" - # add backslash to last line of temp file - sed -i "\$s/$/ \\\/" "$todisc_tmp" - # add "-titleset \" as 1st line - sed -i '1i -titleset \\' "$todisc_tmp" - # add "-end-titleset" as last line - sed -i '$a -end-titleset \\' "$todisc_tmp" - # concatenate - cat "$todisc_tmp" >> "$final_tmp_script" - rm -f "$todisc_tmp" - fi -done - -############################################################################### -############################## Run Final Script ############################### -############################################################################### - -# remove backslash on last line -sed -i "\$s/\\\//" "$final_tmp_script" -echo $SEP -mv "$final_tmp_script" "$final_script" -echo final script is "$final_script" -echo "Do you want to run it now?, type yes if you do, or press <ENTER> to leave" -read answer -if [[ $answer == "yes" ]]; then - bash "$final_script" -fi
View file
tovid-0.34.tar.bz2/src/makemenu
Deleted
@@ -1,878 +0,0 @@ -#!/usr/bin/env bash -ME="[makemenu]:" -. tovid-init 2>/dev/null || -{ echo -e "===============================================================\n" -echo -e "'tovid-init' not found. Was tovid improperly installed?" -echo -e "Or are you trying to run the script directly?" -echo -e "Please run makemenu as:\ntovid menu OPTIONS" -exit 1 ; } - -# version $Id: makemenu 3336 2011-06-30 21:49:22Z grepper $ -# makemenu -# Part of the tovid suite -# ======================= -# A bash script for generating menus for use with DVD, VCD, or SVCD. -# Given a background image and a list of titles, and an optional audio -# file to use as background music, this script produces an MPEG video -# displaying the specified text, with subtitle-multiplexed menu -# highlights (for DVD) or enumerated titles (for (S)VCD). -# -# Project homepage: http://tovid.wikia.com -# -# Copyright (C) 2005-2010 -# -# 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 2 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, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Or see: -# -# http://www.gnu.org/licenses/gpl.txt - -# Options to consider -# font selection -# font color, highlight color, selection color -# font shadow, border -# icons, graphic overlays -# Support for full-motion video menus - -SCRIPT_NAME=`cat << EOF --------------------------------- -tovid menu -Generate DVD/(S)VCD menus -Version $TOVID_VERSION -$TOVID_HOME_PAGE --------------------------------- -EOF` - -USAGE=`cat << EOF -Usage: tovid menu [OPTIONS] "Title1" "Title2" ... -out {output prefix} - -Common options: - - -pal | -ntsc | -ntscfilm Set TV standard - -dvd | -vcd | -svcd Encode to standard format - -background IMAGE ex: -background star_field.png - -audio AUDIOFILE ex: -audio foo_fighters.mp3 - -font "FONTNAME" ex: -font Courier - -Example: - - tovid menu -background ocean.jpg "First" "Second" "Third" -out mymenu - Create 'mymenu.mpg' with three titles and a custom background image. - -See the tovid manual page ('man tovid') for additional documentation. - -EOF` - -# Defaults and function definitions - -# Print script name, usage notes, and optional error message, then exit. -# Args: $@ == text string containing error message -usage_error () -{ - printf "%s\n" "$USAGE" - printf "%s\n" "$SEPARATOR" - printf "*** %s\n" "$@" - exit 1 -} - -# Clean up the temporary files -function cleanup() -{ - if $DEBUG; then - echo "Leaving temporary files in $TMP_DIR" - echo "Debugging log saved to $LOG_FILE" - else - echo "Cleaning up... " - rm -rf "$TMP_DIR" - fi -} - -# Initializations - -# No background image or audio -BG_IMAGE="" -BG_AUDIO="" -MENU_LENGTH="" -# NTSC DVD -TVSYS="ntsc" -RES="dvd" -# Use a safe area -SAFE_AREA=: -# Number of titles -NUM_TITLES=0 -MAX_VCD_TITLES=9 -MAX_DVD_TITLES=36 -OVER_MAX_TITLES=false -# Scale up and crop non-4:3 images by default -SCALECROP="crop" -# Colors for menu items (RGB) -TEXT_COLOR="white" -HIGHLIGHT_COLOR="yellow" -SELECT_COLOR="red" -# Default title font and point size -TITLE_FONT="Helvetica" -TITLE_SIZE="24" -FONT_DECO="-stroke black -strokewidth 1" -TEXT_ALIGN="northwest" -# Default menu title settings -MAKE_TITLE=false -# Button char -BUTTON_FONT="" -BUTTON_CHAR=">" -BTN_STROKE="none" -# NTSC DVD -SAMPRATE="48000" -ASUF="ac3" -VSUF="m2v" -FPS="2997" -MPEG2ENC_FMT="-f 8" -MPLEX_OPTS="-V" -MPEG2ENC_SYS="-F 4 -n n" -# Figure out what version of ppmtoy4m is in use; -# mjpegtools 1.6.2 seems to require 420_mpeg2 -if mplex 2>&1 | grep -q "version 1.6.2"; then - CHROMA_MODE="420_mpeg2" -else - CHROMA_MODE="420mpeg2" -fi -IM_VERSION=$(convert -list configure | awk '/LIB_VERSION_NUMBER/ {print $2}') -if test_version $IM_VERSION 6.3.5.7; then - IM_LISTARG='font' -else - IM_LISTARG='type' -fi -# imagemagick's font listing structure depends on version -if test_version $IM_VERSION 6.4.0.0; then - im_field=2 -else - im_field=1 -fi -PPM_OPTS="-S $CHROMA_MODE -A 10:11 -F 30000:1001" -# Direct stuff to /dev/null -REDIR="/dev/null" -# Not doing debugging -DEBUG=false -QUIET=false -# Don't overwrite output files -OVERWRITE=false -OUT_PREFIX="" -LOG_FILE="makemenu.log" -NOASK=false -# How far to space titles and buttons -TITLE_BOTTOM_SPACE=12 -TITLE_LEFT_SPACE=10 - - -# =========================================================================\ -# E X E C U T I O N B E G I N S H E R E -# -# - -echo "$SCRIPT_NAME" - -assert_dep "$magick" "You are missing dependencies required for making menus!" - -# Process all options -while test $# -gt 0; do - case "$1" in - "-ntsc" | "-ntscfilm" ) - TVSYS="ntsc" - MPEG2ENC_SYS="-F 4 -n n" - PPM_OPTS="-S $CHROMA_MODE -A 10:11 -F 30000:1001" - FPS="2997" - ;; - "-pal" ) - TVSYS="pal" - MPEG2ENC_SYS="-F 3 -n p" - PPM_OPTS="-S $CHROMA_MODE -A 59:54 -F 25:1" - FPS="2500" - ;; - "-dvd" ) - RES="dvd" - MPEG2ENC_FMT="-f 8" - # Variable bitrate - MPLEX_OPTS="-V" - VSUF="m2v" - ;; - "-vcd" ) - RES="vcd" - MPEG2ENC_FMT="-f 1" - # Constant bitrate - MPLEX_OPTS="" - VSUF="m1v" - ;; - "-svcd" ) - RES="vcd" - MPEG2ENC_FMT="-f 4" - # Variable bitrate - MPLEX_OPTS="-V" - VSUF="m2v" - ;; - "-audio" ) - shift - # Make sure file exists - if test -f "$1"; then - BG_AUDIO=$1 - else - usage_error "Can't find background audio file: $1" - fi - ;; - "-background" ) - shift - # Make sure file exists - if test -f "$1"; then - BG_IMAGE=$1 - else - usage_error "Can't find background image file: $1" - fi - ;; - "-overwrite" ) OVERWRITE=: ;; - "-crop" ) SCALECROP="crop" ;; - "-scale" ) SCALECROP="scale" ;; - "-nosafearea" ) SAFE_AREA=false ;; - "-font" ) - shift - TITLE_FONT="$1" - ;; - "-fontsize" ) - shift - TITLE_SIZE="$1" - ;; - "-fontdeco" ) - shift - FONT_DECO="$1" - ;; - "-textcolor" ) - shift - TEXT_COLOR="$1" - ;; - "-highlightcolor" ) - shift - HIGHLIGHT_COLOR="$1" - ;; - "-selectcolor" ) - shift - SELECT_COLOR="$1" - ;; - "-align" ) - shift - case "$1" in - "left" ) TEXT_ALIGN="northwest" ;; - "right" ) TEXT_ALIGN="northeast" ;; - "center" ) TEXT_ALIGN="north" ;; - "middle" ) TEXT_ALIGN="center" ;; - * ) TEXT_ALIGN=$(echo "$1" | tr A-Z a-z) - esac - ;; - "-button" ) - shift - case "$1" in - "play" ) - BUTTON_FONT="Webdings" - BUTTON_CHAR=4 - ;; - "movie" ) - BUTTON_FONT="Webdings" - OFFICIAL_PRINTF=$(which printf) - BUTTON_CHAR=$($OFFICIAL_PRINTF '\u00b8') - ;; - "utf8" ) - shift - OFFICIAL_PRINTF=$(which printf) - BUTTON_CHAR=$($OFFICIAL_PRINTF "\u$1") - ;; - * ) - BUTTON_CHAR="$1" - if test $(echo -n "$BUTTON_CHAR" | wc -c ) -ne 1; then - usage_error "Buttons must have only _one_ characater." - fi - ;; - esac - ;; - "-debug" ) - DEBUG=: - REDIR="$LOG_FILE" - ;; - "-quiet" ) - QUIET=: - ;; - "-out" ) - shift - OUT_PREFIX="$1" - ;; - "-noask" ) NOASK=: ;; - "-button-outline" ) - shift - BTN_STROKE="$1" - ;; - "-button-font" ) - shift - BUTTON_FONT="$1" - ;; - "-menu-title" ) - shift - MENU_TITLE="$1" - MAKE_TITLE=: - ;; - "-menu-title-fontsize" ) - shift - MENU_TITLE_SIZE="$1" - ;; - "-length" ) - shift - MENU_LENGTH="-t $1" - ;; - # Assume anything in quotes is a video title - ""*"" ) - TITLES=("${TITLES[@]}" "$1") - ;; - * ) - test -n "$1" && usage_error "Unrecognized command-line option: $1" - ;; - esac - - # Get the next argument - shift -done - -NUM_TITLES=${#TITLES[@]} -# If no titles were provided, exit with error -if test $NUM_TITLES -eq 0; then - usage_error "Please provide at least one title string, enclosed in double-quotes." -fi - -# If output prefix was not provided, exit with error -if test -z "$OUT_PREFIX"; then - usage_error "Please provide an output prefix with the -out option." -fi - -# Make sure we're not overwriting an existing menu -if test -f "$OUT_PREFIX.mpg"; then - if $OVERWRITE; then - rm -f "$OUT_PREFIX.mpg" - else - echo "There is already a file named \"$OUT_PREFIX.mpg\" in this directory!" - echo "Use '-overwrite' to replace this file. (tovid menu -overwrite ...)" - echo "Exiting..." - exit 1 - fi -fi - - -OUT_FILENAME="$OUT_PREFIX.mpg" -# Temporary directory named after the given -out prefix -OUTNAME=$(basename "$OUT_PREFIX") -TMP_DIR=$(tempdir "$WORKING_DIR/$OUTNAME") -$DEBUG && echo "Storing temporary files in $TMP_DIR" -BG_CANVAS="$TMP_DIR/bg_canvas.png" -MENU_PPM="$TMP_DIR/menu.ppm" -MENU_MPEG="$TMP_DIR/menu.mpg" -SPUMUX_XML="$TMP_DIR/menu_buttons.xml" - -SELECT_PNG="$TMP_DIR/select.png" -HIGHLIGHT_PNG="$TMP_DIR/highlight.png" -TILE_CANVAS="$TMP_DIR/00_tile_canvas.png" -BUTTON_PAD="$TMP_DIR/00_button_pad.png" -BUTTON_PLACEHOLDER="$TMP_DIR/00_button-placeholder.png" -HIGHLIGHT_BUTTON="$TMP_DIR/00_highlight-button.png" -SELECT_BUTTON="$TMP_DIR/00_select-button.png" -HIGHLIGHT_TEXT="$TMP_DIR/02_highlight-text.png" -MENU_TEXT="$TMP_DIR/02_menu-text.png" -SAFETY_CANVAS="$TMP_DIR/02_safety-canvas.png" -SELECT_TEXT="$TMP_DIR/02_select-text.png" -ACTIVE_TEXT="$TMP_DIR/03_active-text.png" -ACTIVE_HIGHLIGHT="$TMP_DIR/03_active-highlight.png" -ACTIVE_SELECT="$TMP_DIR/03_active-select.png" -MENU_TITLE_TEXT="$TMP_DIR/02_menu-title.png" -MENU_TITLE_PLACEHOLDER="$TMP_DIR/02_menu-title-placeholder.png" - -# Use appropriate settings for DVD -if test $RES = "dvd"; then - assert_dep "$dvd" "You are missing dependencies required for making DVD menus!" - WIDTH="720" - SAMPRATE="48000" - test $TVSYS = "ntsc" && HEIGHT="480" - test $TVSYS = "pal" && HEIGHT="576" -# And for (S)VCD -else - WIDTH="352" - SAMPRATE="44100" - test $TVSYS = "ntsc" && HEIGHT="240" - test $TVSYS = "pal" && HEIGHT="288" - # Reduce font size and spacing - TITLE_SIZE=$(expr $TITLE_SIZE \/ 2) -fi - -# Set audio stream format -if test "$RES" = "dvd"; then - ASUF="ac3" -else - ASUF="mp2" -fi -VIDEO_STREAM="$TMP_DIR/video.$VSUF" -AUDIO_STREAM="$TMP_DIR/audio.$ASUF" - -# Make sure there are 9 or fewer titles for VCD and 36 or fewere for DVD -if test "$RES" = "vcd" && test "$NUM_TITLES" -gt $MAX_VCD_TITLES; then - OVER_MAX_TITLES=: - DISC_TYPE="(S)VCD" - MAX_TITLES=$MAX_VCD_TITLES -elif test "$RES" = "dvd" && test "$NUM_TITLES" -gt $MAX_DVD_TITLES; then - OVER_MAX_TITLES=: - DISC_TYPE="DVD" - MAX_TITLES=$MAX_DVD_TITLES -fi -if $OVER_MAX_TITLES; then - echo $SEPARATOR - echo "I read $NUM_TITLES titles for your $DISC_TYPE menu, which is more than the maximum number" - echo "of titles allowed on one menu for ${DISC_TYPE}s ($MAX_TITLES is the limit)." - echo "Please try using fewer titles on this menu." - cleanup - exit 1 -fi - -# Use a foreground canvas the size of the background minus safe area -if $SAFE_AREA; then - FG_WIDTH=$(expr $WIDTH \* 4 \/ 5) - FG_HEIGHT=$(expr $HEIGHT \* 4 \/ 5) -else - FG_WIDTH=$(expr $WIDTH \- 10) - FG_HEIGHT=$(expr $HEIGHT \- 10) -fi - -# If no button font was given with -button-font, default to the title font -if test -z "$BUTTON_FONT"; then - BUTTON_FONT=$TITLE_FONT -fi - -# Confirm the title font, or use a similar one -if test -s "$TITLE_FONT"; then - # Using ttf font file for ImageMagick - USE_TITLE_FONT="$TITLE_FONT" -else - # Check to see if the given font name is available in ImageMagick - # (only return the first exact match) - USE_TITLE_FONT=$( convert -list $IM_LISTARG | \ - grep -m 1 "$TITLE_FONT" | awk -v f=$im_field '{print $f}' ) - - # If not available, try to use something similar - if test -z $USE_TITLE_FONT ; then - echo $SEPARATOR - echo "Font: \"$TITLE_FONT\" does not appear to be either a font file or registered with ImageMagick." - USE_TITLE_FONT=$( convert -list $IM_LISTARG | \ - grep -i -m 1 "${TITLE_FONT:0:20}" | awk -v f=$im_field '{print $f}' ) - - # If a similarly-named one does't exist, default to Helvetica - if test -z "$USE_TITLE_FONT"; then - echo "A similarly-named font was not found. Sorry!" - USE_TITLE_FONT="Helvetica" - fi - echo "The font \"$USE_TITLE_FONT\" will be used instead." - echo $SEPARATOR - fi -fi - -# Set the title font with the one that was found/compatible -TITLE_FONT="$USE_TITLE_FONT" - -# Confirm the button font and button's existance in the font -if test $RES = 'dvd'; then - # Confirm the button font, or use a similar one - if test -s "$BUTTON_FONT"; then - # Using ttf font file for ImageMagick - USE_BUTTON_FONT="$BUTTON_FONT" - else - # Check to see if the given button font is available in ImageMagick - # (only return the first exact match) - USE_BUTTON_FONT=$( convert -list $IM_LISTARG | \ - grep -m 1 "$BUTTON_FONT" | awk -v f=$im_field '{print $f}' ) - - # If not available, try to use something similar - if test -z $USE_BUTTON_FONT ; then - echo $SEPARATOR - echo "Button: \"$BUTTON_FONT\" does not appear to be either a font file or registered with ImageMagick." - USE_BUTTON_FONT=$( convert -list $IM_LISTARG | \ - grep -i -m 1 "${BUTTON_FONT:0:20}" | awk -v f=$im_field '{print $f}' ) - - # If a similarly-named one does't exist, default to Helvetica - if test -z "$USE_BUTTON_FONT"; then - echo "A similarly-named font was not found. Sorry!" - USE_BUTTON_FONT="$TITLE_FONT" - fi - echo "The font \"$USE_BUTTON_FONT\" will be used instead." - echo $SEPARATOR - fi - fi - -# Confirm that the button character exists in the font - if convert -size 720x200 xc:none -fill white \ - -font $USE_BUTTON_FONT -pointsize $TITLE_SIZE -weight bold \ - +antialias -annotate +20+80 "$BUTTON_CHAR" -trim +repage \ - -bordercolor none -border 10 info: >> /dev/null 2>&1; then : - else - echo $SEPARATOR - echo "The button \"$BUTTON_CHAR\" doesn't exist in \"$USE_BUTTON_FONT\"" - USE_BUTTON_FONT="$TITLE_FONT" - echo "The font \"$USE_BUTTON_FONT\" will be used instead." - echo $SEPARATOR - fi -fi - -# Set the button font with the one that was found/compatible -BUTTON_FONT="$USE_BUTTON_FONT" - -# ==========================================================================\ -# M E N U D R A W I N G -# -# - -# Measure the font's vertical height -TILE_HEIGHT=$(convert -format %h -size 720x200 xc:none -fill white -pointsize $TITLE_SIZE -font $TITLE_FONT -antialias $FONT_DECO -annotate +20+80 "Al" -trim +repage info:) - -let "TILE_HEIGHT=TILE_HEIGHT+TITLE_BOTTOM_SPACE" - -# Make text 'tiles' for each title. These will be pieced together later on. -echo "Adding $NUM_TITLES titles to the menu:" -for ((i=0; i<$NUM_TITLES; i++)); do - SEQNUM=$(printf "%02d" ${i}) - let "j=i+1" - echo " $j: ${TITLES[i]}" - # Enumerate (S)VCD titles - if test $RES = "vcd" ; then - ENTRY="${j}. ${TITLES[i]}" - - # Get the width of text and pad it - TILE_WIDTH=$(convert -format %w -size 720x200 xc:none -fill $TEXT_COLOR -pointsize $TITLE_SIZE -font $TITLE_FONT -antialias $FONT_DECO -annotate +20+80 "$ENTRY" -trim +repage info:) - let "TILE_WIDTH=TILE_WIDTH+TITLE_LEFT_SPACE" - - # Draw the text, and put it on a blank tile - convert -size 720x100 xc:none -font $TITLE_FONT -antialias $FONT_DECO -fill $TEXT_COLOR -pointsize $TITLE_SIZE -annotate +20+80 "$ENTRY" -trim +repage "$TMP_DIR/01_entry-$SEQNUM.png" - convert -size ${TILE_WIDTH}x${TILE_HEIGHT} xc:none "$TILE_CANVAS" - composite -compose Over -gravity north "$TMP_DIR/01_entry-$SEQNUM.png" \ - "$TILE_CANVAS" "$TMP_DIR/01_entry-$SEQNUM.png" - - # Use a highlight cursor for DVD titles (drawn later, for now just text) - else - ENTRY="${TITLES[i]}" - - # Get the width of the text and pad it - TILE_WIDTH=$(convert -format %w -size 720x200 xc:none -fill $TEXT_COLOR -pointsize $TITLE_SIZE -font $TITLE_FONT -antialias $FONT_DECO -annotate +20+80 "$ENTRY" -trim +repage info:) - let "TILE_WIDTH=TILE_WIDTH+TITLE_LEFT_SPACE" - - # Draw the text, and put it on a blank tile - convert -size 720x100 xc:none -font $TITLE_FONT -antialias $FONT_DECO -fill $TEXT_COLOR -pointsize $TITLE_SIZE -annotate +20+80 "$ENTRY" -trim +repage "$TMP_DIR/00_title-$SEQNUM.png" - convert -size ${TILE_WIDTH}x${TILE_HEIGHT} xc:none "$TILE_CANVAS" - composite -compose Over -gravity northeast \ - "$TMP_DIR/00_title-$SEQNUM.png" "$TILE_CANVAS" \ - "$TMP_DIR/00_title-$SEQNUM.png" - - # Blank placeholder: no font decorations or color - DIMS=$(identify "$TMP_DIR/00_title-$SEQNUM.png" | grep -o -e " [0-9]\{1,\}x[0-9]\{1,\} " | tr -d ' ') - convert \ - -size $DIMS xc:none "$TMP_DIR/00_title-${SEQNUM}_placeholder.png" - fi -done - -# Finish DVD menu entries (all we have so far is text, no buttons!) -if test $RES = "dvd"; then - echo "Making the DVD buttons... " - - # Get the dimensions of the button - TILE_WIDTH=$(convert -format %w -size 720x200 xc:none -fill white -stroke $BTN_STROKE -strokewidth 1 -pointsize $TITLE_SIZE -font $BUTTON_FONT +antialias -weight bold -annotate +20+80 "$BUTTON_CHAR" -trim +repage info:) - BUTTON_HEIGHT=$(convert -format %w -size 720x200 xc:none -fill white -stroke $BTN_STROKE -strokewidth 1 -pointsize $TITLE_SIZE -font $BUTTON_FONT +antialias -weight bold -annotate +20+80 "$BUTTON_CHAR" -trim +repage info:) - # Find how much to pad the top of the button and make the pad - let "BUTTON_PADDING=(TILE_HEIGHT-BUTTON_HEIGHT-TITLE_BOTTOM_SPACE)/2" - convert -size ${TILE_WIDTH}x${BUTTON_PADDING} xc:none "$BUTTON_PAD" - - # Draw the buttons - convert -size 720x100 xc:none -font $BUTTON_FONT -stroke $BTN_STROKE -strokewidth 1 +antialias -weight bold -fill $HIGHLIGHT_COLOR -pointsize $TITLE_SIZE -annotate +20+80 "$BUTTON_CHAR" -trim +repage "$HIGHLIGHT_BUTTON" - convert -size 720x100 xc:none -font $BUTTON_FONT -stroke $BTN_STROKE -strokewidth 1 +antialias -weight bold -fill $SELECT_COLOR -pointsize $TITLE_SIZE -annotate +20+80 "$BUTTON_CHAR" -trim +repage "$SELECT_BUTTON" - - # Pad the buttons so that they line up with the font's baseline - convert -background none "$BUTTON_PAD" "$HIGHLIGHT_BUTTON" -append \ - "$HIGHLIGHT_BUTTON" - convert -background none "$BUTTON_PAD" "$SELECT_BUTTON" -append \ - "$SELECT_BUTTON" - - # Make a blank button tile according to measured dimensions - convert -size ${TILE_WIDTH}x${TILE_HEIGHT} xc:none "$TILE_CANVAS" - - # Put padded buttons on the blank tile - composite -compose Over -gravity north "$HIGHLIGHT_BUTTON" \ - "$TILE_CANVAS" "$HIGHLIGHT_BUTTON" - composite -compose Over -gravity north "$SELECT_BUTTON" \ - "$TILE_CANVAS" "$SELECT_BUTTON" - - # A placeholder to space the title text correctly - DIMS=$(identify "$HIGHLIGHT_BUTTON" | grep -o -e " [0-9]\{1,\}x[0-9]\{1,\} " | tr -d ' ') - convert -size $DIMS xc:none "$BUTTON_PLACEHOLDER" - - # Next, join the button tiles with the title tiles: - i=0 - while test $i -lt $NUM_TITLES; do - SEQNUM=$(printf "%02d" $i) - # Text entries - convert -background none "$BUTTON_PLACEHOLDER" \ - "$TMP_DIR/00_title-$SEQNUM.png" +append \ - "$TMP_DIR/01_entry-$SEQNUM.png" - # Highlight entries - convert -background none "$HIGHLIGHT_BUTTON" \ - "$TMP_DIR/00_title-${SEQNUM}_placeholder.png" \ - +append "$TMP_DIR/01_highlight_entry-$SEQNUM.png" - # Select entries - convert -background none "$SELECT_BUTTON" \ - "$TMP_DIR/00_title-${SEQNUM}_placeholder.png" \ - +append "$TMP_DIR/01_select_entry-$SEQNUM.png" - let "i=i+1" - done -fi - -# Stack all 01_entry-N.png lines -echo "Creating the text menu... " -convert -background none "$TMP_DIR/01_entry-*.png" -append "$MENU_TEXT" - -# Stack all DVD button lines -if test $RES = "dvd"; then -echo "Creating the DVD button overlays... " - convert -background none "$TMP_DIR/01_highlight_entry-*.png" -append \ - "$HIGHLIGHT_TEXT" - convert -background none "$TMP_DIR/01_select_entry-*.png" -append \ - "$SELECT_TEXT" -fi - -# If specified, add a menu title -if $MAKE_TITLE; then - echo "Adding the menu title..." - - # Default title font size = current text size + 4 - if test -z "$MENU_TITLE_SIZE"; then - let "MENU_TITLE_SIZE=TITLE_SIZE+8" - fi - - # Calculate number of \n characters in title, so menu title height - # will be set correctly - TITLE_LINES=$(echo "$MENU_TITLE" | sed 's/!//g;s/\\n/!/g;s/[^!]//g' | wc -c) - TITLE_HEIGHT=$((100 * $TITLE_LINES)) - - # Draw the menu title and pad the bottom with TILE_HEIGHT pixels - convert -size 720x$TITLE_HEIGHT xc:none -font $TITLE_FONT -antialias $FONT_DECO -fill $TEXT_COLOR -pointsize $MENU_TITLE_SIZE -annotate +20+80 "$MENU_TITLE" -trim +repage "$MENU_TITLE_TEXT" - - convert "$MENU_TITLE_TEXT" -gravity south -background none -splice 0x$TILE_HEIGHT "$MENU_TITLE_TEXT" - - # Put the menu title above the menu text (and buttons for DVDs) - convert -background none "$MENU_TITLE_TEXT" "$MENU_TEXT" -append \ - "$MENU_TEXT" - if test $RES = "dvd"; then - # DVD menus need an empty placeholder for the buttons - DIMS=$(identify "$MENU_TITLE_TEXT" | grep -o -e " [0-9]\{1,\}x[0-9]\{1,\} " | tr -d ' ') - convert -size $DIMS xc:none "$MENU_TITLE_PLACEHOLDER" - convert -background none "$MENU_TITLE_PLACEHOLDER" "$HIGHLIGHT_TEXT" \ - -append "$HIGHLIGHT_TEXT" - convert -background none "$MENU_TITLE_PLACEHOLDER" "$SELECT_TEXT" \ - -append "$SELECT_TEXT" - fi - -fi - -# Put the text menus inside the safety area -if $SAFE_AREA; then FRAME_TYPE="safe area"; else FRAME_TYPE="frame"; fi -echo "Placing text menu in the $FRAME_TYPE... " -convert -size ${FG_WIDTH}x${FG_HEIGHT} xc:none "$SAFETY_CANVAS" -composite -compose Over -gravity $TEXT_ALIGN \ - "$MENU_TEXT" "$SAFETY_CANVAS" "$ACTIVE_TEXT" - -# Same for DVD buttons: into the safety area -if test $RES = 'dvd'; then - echo "Placing DVD buttons in the $FRAME_TYPE... " - composite -compose Over -gravity $TEXT_ALIGN \ - "$HIGHLIGHT_TEXT" "$SAFETY_CANVAS" "$ACTIVE_HIGHLIGHT" - composite -compose Over -gravity $TEXT_ALIGN \ - "$SELECT_TEXT" "$SAFETY_CANVAS" "$ACTIVE_SELECT" -fi - -# Background image: -# If none was provided, create a default one (blue-black gradient) -if test -z "$BG_IMAGE"; then - BG_CMD="convert -size ${WIDTH}x${HEIGHT} gradient:blue-black \ - -gravity center -matte \"$BG_CANVAS\"" -# Otherwise, scale/crop the provided image -else - if test "$SCALECROP" = "crop"; then - SCALECROP="-resize ${WIDTH}x -resize \"x${HEIGHT}<\" -gravity center \ - -crop ${WIDTH}x${HEIGHT}+0+0" - else - SCALECROP="-resize ${WIDTH}x${HEIGHT}!" - fi - BG_CMD="convert \"$BG_IMAGE\" $SCALECROP -matte \"$BG_CANVAS\"" -fi -echo "Working on the background... " -$DEBUG && echo -e "\n\nBackground:\n$BG_CMD" >> $REDIR -eval $BG_CMD - -# Put menu text over the background image -MAGICK_CMD="composite -compose Over -gravity center \ - \"$ACTIVE_TEXT\" \"$BG_CANVAS\" -depth 8 \"$MENU_PPM\"" -echo "Centering the $FRAME_TYPE over the background... " -$DEBUG && echo -e "\n\nMenu Text:\n$MAGICK_CMD" >> $REDIR -eval $MAGICK_CMD - -# Same for DVDs -if test $RES = 'dvd'; then - echo "Positioning the DVD button overlays on the background... " - composite -compose Src -gravity center \ - "$ACTIVE_HIGHLIGHT" "$BG_CANVAS" "$HIGHLIGHT_PNG" - composite -compose Src -gravity center \ - "$ACTIVE_SELECT" "$BG_CANVAS" "$SELECT_PNG" -fi - - -# ======================================================================\ -# P R E V I E W & F I N I S H -# -# - -if ! $NOASK; then - echo "Generating preview..." - echo "Type 'q' to close the preview window." - if test "$RES" = vcd; then - display "$MENU_PPM" - else - composite -compose Over -gravity center "$HIGHLIGHT_PNG" \ - "$MENU_PPM" miff: | display - fi - wait - echo -n "Was the preview ok [y/N]? " - ANSWER="N" - read ANSWER - if ! ( test "$ANSWER" = "y" || test "$ANSWER" = "Y" ); then - echo "Preview was not OK, exiting..." - cleanup - echo - echo "Try: -font FONT -fontsize NUM -textcolor '#RGB'" - echo " -fontdeco 'ImageMagick instr' -align left|center|right" - echo " -background IMAGE -audio AUDIOFILE" - echo "to change the appearance. More in 'man tovid'" - exit 0 - else - echo "Preview was OK. Continuing..." - fi -fi - -# Background audio: -# If no background audio was provided, generate 4 seconds of silence -if test -z "$BG_AUDIO"; then - if test -z "$MENU_LENGTH"; then - MENU_LENGTH="-t 4" - fi - echo "Creating $(echo "$MENU_LENGTH" | cut -c 4-)-second silent $ASUF audio... " - AUDIO_CMD="ffmpeg -f s16le -i /dev/zero -ac 2 -ar $SAMPRATE -ab 224k \ - $MENU_LENGTH -acodec $ASUF -y \"$AUDIO_STREAM\"" - $DEBUG && echo -e "\n\nBG audio:\n$AUDIO_CMD" >> $REDIR - eval $AUDIO_CMD >> $REDIR 2>&1 -# Otherwise, convert provided audio to the target format -else - echo "Converting \"$BG_AUDIO\" to $ASUF... " - AUDIO_CMD="ffmpeg -i \"$BG_AUDIO\" -ac 2 -ar $SAMPRATE -ab 224k \ - $MENU_LENGTH -acodec $ASUF -y \"$AUDIO_STREAM\"" - $DEBUG && echo -e "\n\nBG audio:\n$AUDIO_CMD" >> $REDIR - eval $AUDIO_CMD >> $REDIR 2>&1 -fi - -# Calculate video length from length of audio -VID_LENGTH=$(mplayer -quiet -nomsgcolor -identify -frames 0 -vo null -ao null \ - "$AUDIO_STREAM" 2>&1 | grep '^ID_LENGTH' | awk -F '=' '{print $2}' | \ - sed -e "s/\.[0-9]*//g") -VID_LENGTH=$(expr "$VID_LENGTH" \* $FPS \/ 100) - -# Make sure VID_LENGTH is nonzero -if test "$VID_LENGTH" -eq 0 ; then - # Use 30 seconds as a sensible default - VID_LENGTH=$(expr 30 \* $FPS \/ 100) -fi - -# Make video of specified length from PPM background image -echo "Converting menu image to video. This may take a while... " -VIDEO_CMD="ppmtoy4m $PPM_OPTS -n $VID_LENGTH -r \"$MENU_PPM\" 2>>$REDIR | \ - mpeg2enc -a 2 $MPEG2ENC_FMT $MPEG2ENC_SYS -o \"$VIDEO_STREAM\" >> $REDIR 2>&1" -$DEBUG && echo -e "\n\nTo mpeg:\n$VIDEO_CMD" >> $REDIR -eval $VIDEO_CMD - -# Multiplex audio and video -echo "Multiplexing video and audio streams... " -MPLEX_CMD="mplex $MPLEX_OPTS $MPEG2ENC_FMT -o \"$MENU_MPEG\" \ - \"$VIDEO_STREAM\" \"$AUDIO_STREAM\" >> $REDIR 2>&1" -$DEBUG && echo -e "\n\nMux:\n$MPLEX_CMD" >> $REDIR -eval $MPLEX_CMD - -# For DVD, create spumux XML -if test "$RES" = "dvd"; then - -(cat << EOF -<subpictures> - <stream> - <spu force="yes" start="00:00:00.00" - highlight="$HIGHLIGHT_PNG" - select="$SELECT_PNG" - autooutline="infer"> - </spu> - </stream> -</subpictures> -EOF -) > "$SPUMUX_XML" - wait - SPUMUX_CMD="spumux \"$SPUMUX_XML\" < \"$MENU_MPEG\" > \"$OUT_FILENAME\" 2>>$REDIR" - echo "Adding the DVD buttons to menu... " - $DEBUG && echo -e "\n\nSpumux buttons:\n$SPUMUX_CMD" >> $REDIR - eval $SPUMUX_CMD - -# Rename the output menu for VCD and SVCD -else - mv "$MENU_MPEG" "$OUT_FILENAME" -fi - -cleanup - -echo $SEPARATOR -if test -s "$OUT_FILENAME"; then - if ! $QUIET; then - echo "Finished! Your menu should be in the file \"$OUT_FILENAME\"." - if test "$RES" = "vcd"; then - echo "You can use this menu on an SVCD or VCD disc with:" - echo - echo " tovid xml -vcd -menu \"$OUT_FILENAME\" <title 1> <title 2> ... \\" - echo " <output name>" - else - echo "You can use this menu on a DVD disc with:" - echo - echo " tovid xml -dvd -menu \"$OUT_FILENAME\" <title 1> <title 2> ... \\" - echo " -out <output name>" - fi - - echo - echo "where <title N> is an MPEG video file corresponding to title N as listed" - echo "on your menu. Run tovid xml' without any options for more usage information." - else - echo "Done!" - fi -else - echo "It looks like something went wrong, because there is no output file." - echo "Please submit a bug report to http://code.google.com/p/tovid/issues." - echo "Please add -debug to your command (tovid menu -debug ...) and post the" - echo "log file and terminal output. Sorry for the inconvenience." - exit 1 -fi - -$QUIET || echo $SEPARATOR -$QUIET || echo "Thanks for using makemenu!" -exit 0
View file
tovid-0.34.tar.bz2/src/makevcd
Deleted
@@ -1,230 +0,0 @@ -#!/usr/bin/env bash -ME="[makevcd]:" -. tovid-init 2>/dev/null || -{ echo -e "===============================================================\n" -echo -e "'tovid-init' not found. Was tovid improperly installed?" -echo -e "Or are you trying to run the script directly?" -echo -e "Please run makevcd as:\ntovid vcd OPTIONS" -exit 1 ; } - -# makevcd -# Part of the tovid suite -# ======================= -# A bash script for creating a VCD cue/bin set and burning it -# to a recordable CD. -# -# Project homepage: http://tovid.wikia.com -# -# Copyright (C) 2005-2010 -# -# 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 2 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, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Or see: -# -# http://www.gnu.org/licenses/gpl.txt - -SCRIPTNAME=`cat << EOF --------------------------------- -tovid vcd -Create cue/bin files for a (S)VCD and burn them to a CD -Version $TOVID_VERSION -$TOVID_HOME_PAGE --------------------------------- -EOF` - -USAGE=`cat << EOF -Usage: tovid vcd [OPTIONS] {VCDIMAGER.xml} - -Where OPTIONS may be any of the following: - - -overwrite Overwrite existing cue/bin image - -burn (default only make image) - -device DEVICE (default /dev/cdrw) - -speed NUM (default 12) - -force Add --force to cdrdao command (needed for short slides) - -And: - - VCDIMAGER.xml is the name of a file containing a VCDImager XML - description (For XML format, see http://www.vcdimager.org/). - If you use(d) 'makexml' to create the XML file, you can use - that as input here. - -See the tovid manual page ('man tovid') for additional documentation. - -EOF` - -SEPARATOR="==========================================" - -# Print script name, usage notes, and optional error message, then exit. -# Args: $1 == text string containing error message -usage_error () -{ - echo "$USAGE" - echo $SEPARATOR - echo "$@" - exit 1 -} - -# Print out a runtime error specified as an argument, and exit -runtime_error () -{ - killsubprocs - echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" - echo "makevcd encountered an error during the VCD creation process:" - echo $@ - echo "See if anything in the above output helps you diagnose the" - echo "problem, and please file a bug report containing the above" - echo "output to http://code.google.com/p/tovid/issues." - echo "Sorry for the inconvenience!" - echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" - exit 1 -} -# Defaults -QUIET=false -IMAGE=: -CDRW_DEVICE="/dev/cdrw" -BURN_SPEED=12 -OVERWRITE=false -BURN=false - -# ========================================================== -# EXECUTION BEGINS HERE -echo $"$SCRIPTNAME" - -assert_dep "$vcd" "You are missing dependencies required to image and burn (S)VCDs!" - -# check for valid CD burner. This may fail but at least we tried -OIFS=$IFS \ -IFS=$'\n' device=($(find -L /dev -type b -name 'cdrw*' 2>/dev/null )) IFS=$OIFS -CDRW_DEVICE=${device:-$CDRW_DEVICE} - -while test x"${1:0:1}" = "x-"; do - case "$1" in - "-quiet" ) QUIET=: ;; - "-overwrite" ) - OVERWRITE=: - ;; - "-burn" ) - BURN=: - ;; - "-device" ) - shift - CDRW_DEVICE="$1" - ;; - "-speed" ) - shift - BURN_SPEED=$1 - ;; - "-force" ) - FORCE="--force" - ;; - * ) - usage_error "Error: Unrecognized command-line option $1" - ;; - esac - - # Get next argument - shift -done - -if test $# -ne 1; then - usage_error "Please provide the name of a VCDimager XML file \ -containing the (S)VCD description." -else - # XML input is last argument - VCDIMAGER_XML="$1" -fi - -# Look for earlier attempts to image this VCD -for prev_try in "$VCDIMAGER_XML.cue" "$VCDIMAGER_XML.bin"; do - if test -f "$prev_try"; then - echo "Found a previous makevcd attempt: $prev_try!" - if $OVERWRITE; then - echo -n "Removing it... " - rm -fv "$prev_try" - elif $BURN; then - echo "Will use this for burning the disc." - IMAGE=false - else - echo "Use '-overwrite' to override and re-image; or" - echo "use '-burn' to write this existing image." - echo "Exiting..." - exit 1 - fi - fi -done - - -# Create the cue/bin image -if $IMAGE; then - # TODO: Warn if there isn't enough space to make cue/bin - VCDIMAGER_CMD="vcdxbuild -c \"$VCDIMAGER_XML.cue\" -b \ - \"$VCDIMAGER_XML.bin\" \"$VCDIMAGER_XML\"" - echo $SEPARATOR - echo "Creating cue/bin disc image with the following command:" - echo $VCDIMAGER_CMD - if eval $VCDIMAGER_CMD; then - echo "Done." - $QUIET || echo "Use 'tovid vcd -burn $VCDIMAGER_XML' to burn your VCD." - $QUIET || echo "Thanks for using tovid!" - else - runtime_error "Imaging failed, please see vcdxbuild output above." - fi -fi - -# Burn the VCD -if $BURN; then - # Sanity check: Make sure given device is valid (somehow) - # before creating the cue/bin. Give option to proceed anyway? - # (i.e., could there be any point to proceeding?) - # Here's a simple way: just quit - if test -b $CDRW_DEVICE; then : - else - echo "Couldn't find $CDRW_DEVICE! Stopping here." - exit 1 - fi - - # Remind user to insert a CD - $QUIET || echo "Please insert a blank CD-R(W) disc into your CD-recorder" - $QUIET || echo "($CDRW_DEVICE) if you have not already done so." - - # check for cdrw and blank if so - if cdrdao disk-info --device $CDRW_DEVICE --driver generic-mmc 2>&1 | - grep -q CD-RW.*yes; then - echo $SEPARATOR - echo "Found rewritable CD - starting to blank in 10 seconds - press ctrl-c to quit" - countdown 10 - cdrdao blank --driver generic-mmc $CDRW_DEVICE - fi - # Burn the disc - CDRDAO_CMD="cdrdao write --device $CDRW_DEVICE --driver generic-mmc \ - --speed $BURN_SPEED $FORCE \"$VCDIMAGER_XML.cue\"" - echo $SEPARATOR - echo "Burning cue/bin image to $CDRW_DEVICE with the following command:" - echo $CDRDAO_CMD - if eval $CDRDAO_CMD; then - if ! $QUIET; then - echo "Done. You should now have a working VCD or SVCD. Please report" - echo "any problems to http://code.google.com/p/tovid/issues." - echo "Thanks for using tovid!" - else - echo "Done." - fi - else - runtime_error "Could not burn the disc to $CDRW_DEVICE at speed $BURN_SPEED." - fi -fi - -exit 0
View file
tovid-0.34.tar.bz2/src/makexml
Deleted
@@ -1,829 +0,0 @@ -#!/usr/bin/env bash -ME="[makexml]:" -. tovid-init 2>/dev/null || -{ echo -e "===============================================================\n" -echo -e "'tovid-init' not found. Was tovid improperly installed?" -echo -e "Or are you trying to run the script directly?" -echo -e "Please run makexml as:\ntovid xml OPTIONS" -exit 1 ; } - -# makexml -# Part of the tovid suite -# ======================= -# This bash script generates XML output describing the structure of -# a VCD, SVCD, or DVD disc. The resulting output can be given as input -# to vcdxbuild or dvdauthor. Format, and a list of menus and -# video files in MPEG format, are specified on the command-line, and -# the resulting XML is written to the specified file. Currently -# supports an optional top-level menu, any number of optional sub-menus, -# and any number of videos reachable through those menus. -# -# Project homepage: http://tovid.wikia.com -# -# Copyright (C) 2005-2010 -# -# 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 2 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, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Or see: -# -# http://www.gnu.org/licenses/gpl.txt - -SCRIPTNAME=`cat << EOF --------------------------------- -tovid xml -Generate XML for authoring a VCD, SVCD, or DVD. -Version $TOVID_VERSION -$TOVID_HOME_PAGE --------------------------------- -EOF` - -USAGE=`cat << EOF -Usage: tovid xml [OPTIONS] {video1.mpg video2.mpg ...} -out OUT_PREFIX - -Common OPTIONS: - - -dvd | -vcd | -svcd Specify the target disc format - -overwrite Overwrite any existing output files - -Provide a list of .mpg video files, and they will be played back in -sequence. You may organize several lists of videos into menus by -providing the name of a menu .mpg: - - tovid xml -menu menu1.mpg \\\\ - video1.mpg video2.mpg video3.mpg \\\\ - -out mydisc - tovid xml -topmenu topmenu.mpg \\\\ - -menu submenu1.mpg vid1.mpg vid2.mpg vid3.mpg \\\\ - -menu submenu2.mpg vid4.mpg vid5.mpg vid6.mpg \\\\ - -out mydisc2 - -See the tovid manual page ('man tovid') for additional documentation. - -EOF` - -SEPARATOR="==========================================" - -# Print script name, usage notes, and optional error message, then exit. -# Args: $1 == text string containing error message -usage_error () -{ - echo "$USAGE" - echo $SEPARATOR - echo "$@" - exit 1 -} - -QUIET=false -# Currently-numbered titleset (must have at least 1 titleset) -CUR_TS=1 -# Currently-numbered video title under a titleset menu (0 for no titles) -CUR_TITLE=0 -# Do we have a top menu yet? -HAVE_TOP_MENU=false -# Do we have any menus yet? -HAVE_MENU=false -# Do not overwrite by default -OVERWRITE=false -# Use dvdauthor XML for DVD authoring -XML_FORMAT="dvd" -# No un-found files yet -FILE_NOT_FOUND=false -# Not doing still titles -STILL_TITLES=false -FIRST_TITLE=: -# Avoid some unbound variables -TOP_MENU_XML="" -TOP_MENU_BUTTONS="" -MENU_BUTTONS="" -TS_TITLES="" -ALL_MENU_XML="" -SEGMENT_ITEMS_XML="" -SEQUENCE_ITEMS_XML="" -PBC_XML="" -PLAYLIST_XML="" - -MAKE_GROUP=false -MAKE_CHAPTERS=: -FORCE_TITLESETS=false -CUR_VIDEO=0 -CHAPTER_INTERVAL=5 - -STANDARD=133 -WIDESCREEN=177 -NOPANSCAN='' -TV_FORMAT=ntsc -PAUSE=0 - -# ========================================================== -# Backslash-escape the given special character (and any EOLs) -# Usage: -# sedprep "$TEXT" / -# echo $TEXT | sed "s/PATTERN/$(sedprep "$REPLACEMENT" /)/" -function sedprep () -{ - delim=${2:-/} - echo "$1" |sed -e 's/[\&'"$delim"']/\\&/g' -e '$!s,$,\\,'; -} - -# ========================================================== -# Check for the existence of a file and print an error if it -# does not exist in the current directory -# Args: $1 = file to look for -function checkExistence () -{ - if test -e "$1"; then : - else - echo "The file "$1" was not found. Exiting." - FILE_NOT_FOUND=: - exit 1 - fi -} - -# ========================================================== -# Find a video's aspect ratio and set dvd behavior accordingly -# Args: $1 = video file to find aspect for -# Usage: noPanScan foo.avi -# Sets NOPANSCAN to either: widescreen="nopanscan" -# or: <null> -function noPanScan () -{ - ASPECT=$(idvid -fast -terse "$1" | grep "ASPECT" | awk -F '=' '{print $2}') - $QUIET || echo -n " $1 has aspect $ASPECT " - if test $ASPECT -eq $WIDESCREEN; then - NOPANSCAN='widescreen="nopanscan"' - $QUIET || echo "(widescreen)." - else - NOPANSCAN='' - $QUIET || echo "(standard)." - fi - -} - -function getFormat () -{ - # Set TV format - default is ntsc - VID_INFO=$(tovid id -fast -terse "$1") - grep -q PAL_DVD <<< "$VID_INFO" && TV_FORMAT=pal -} - -# ========================================================== -# Add a top-level VMGM menu to the DVD -# Args: $1 = video file to use for top menu -function addTopMenu () -{ - HAVE_TOP_MENU=: - echo "Adding top-level menu using file: $1" - - # -------------------------- - # For DVD - if test $XML_FORMAT = "dvd"; then - # Set NOPANSCAN - noPanScan "$1" - # Generate XML for the top menu, with a placeholder for - # the titleset menu buttons (to be replaced later by sed) - TOP_MENU_XML=`cat << EOF - <menus> - <video $NOPANSCAN /> - <pgc entry="title"> - <vob file="$1" /> -__TOP_MENU_BUTTONS__ - </pgc> - </menus> -EOF` - - # -------------------------- - # For (S)VCD - else - - # Generate XML for the segment-item - SEGMENT_ITEMS_XML=`cat << EOF -$SEGMENT_ITEMS_XML - <segment-item src="$1" id="seg-top-menu"/> -EOF` - - # Generate XML for the selection to go in pbc - TOP_MENU_XML=`cat << EOF - <selection id="select-top-menu"> - <bsn>1</bsn> - <loop jump-timing="immediate">0</loop> - <play-item ref="seg-top-menu"/> -__TOP_MENU_BUTTONS__ - </selection> -EOF` - - fi -} - -# ========================================================== -# Add a menu to the disc. -# Args: $1 = video file to use for the menu -function addMenu () -{ - # -------------------------- - # For DVD - if test $XML_FORMAT = "dvd"; then - echo "Adding a titleset-level menu using file: $1" - - # Generate XML for the button linking to this titleset menu from the top menu - TOP_MENU_BUTTONS=`cat << EOF - $TOP_MENU_BUTTONS - <button>jump titleset $CUR_TS menu;</button> -EOF` - - # Set NOPANSCAN - noPanScan "$1" - # Set TV_FORMAT - getFormat "$1" - - # Generate XML for the menu header, with a placeholder for - # the video segment buttons (to be replaced later by sed) - MENU_XML=`cat << EOF - <menus> - <video $NOPANSCAN format="$TV_FORMAT"/> - <pgc entry="root"> - <vob file="$1" /> -__MENU_BUTTONS__ - </pgc> - </menus> -EOF` - - # -------------------------- - # For (S)VCD - else - echo "Adding a menu using file: $1" - - # Generate XML for the button linking to this menu from the top menu - TOP_MENU_BUTTONS=`cat << EOF -$TOP_MENU_BUTTONS - <select ref="select-menu-$CUR_TS"/> -EOF` - - # Generate XML for the segment item - SEGMENT_ITEMS_XML=`cat << EOF -$SEGMENT_ITEMS_XML - <segment-item src="$1" id="seg-menu-$CUR_TS"/> -EOF` - - # Generate XML for the selection to go in pbc - # If there's a top menu, "return" goes back to it. - # Otherwise, don't use a "return" command. - if $HAVE_TOP_MENU; then - RETURN_CMD="<return ref=\"select-top-menu\"/>" - else - RETURN_CMD="" - fi - SELECTION_XML=`cat << EOF - <selection id="select-menu-$CUR_TS"> - <bsn>1</bsn> - $RETURN_CMD - <loop jump-timing="immediate">0</loop> - <play-item ref="seg-menu-$CUR_TS"/> -__MENU_BUTTONS__ - </selection> -EOF` - - fi -} - -# ========================================================== -# Add a video title to a titleset menu, or a still image to -# a slideshow -# Args: $1 = video file to use for the title -function addTitle () -{ - if $FORCE_TITLESETS && test $CUR_VIDEO -eq 0; then - closeTitleset - fi - # Increment the current title number - if ! $MAKE_GROUP; then - (( CUR_TITLE++ )) - else - # Grouping several videos within one title - if test $CUR_VIDEO -eq 0; then - (( CUR_TITLE++ )) - fi - (( CUR_VIDEO++ )) - fi - # -------------------------- - # For DVD - if test $XML_FORMAT = "dvd"; then - if ! $MAKE_GROUP; then - echo "Adding title: $1 as title number $CUR_TITLE of titleset $CUR_TS" - else - if test $CUR_VIDEO -eq 1; then - echo "Adding title number $CUR_TITLE of titleset $CUR_TS" - fi - echo "Adding $1 as video $CUR_VIDEO of title $CUR_TITLE" - fi - - # Set NOPANSCAN - noPanScan "$1" - - # Generate XML for the button linking to this title from the titleset menu - if ! $FORCE_TITLESETS; then - if test $CUR_VIDEO -lt 2; then - MENU_BUTTONS=`cat << EOF -$MENU_BUTTONS - <button>jump title $CUR_TITLE;</button> -EOF` - fi - else - # Add a button for the current titleset to the top menu - if test $CUR_VIDEO -le 1; then - TOP_MENU_BUTTONS=`cat << EOF -$TOP_MENU_BUTTONS - <button>jump titleset $CUR_TS menu;</button> -EOF` - fi - fi - - # Generate the chapters tag - # If file exists, get duration and add appropriate chapter breaks - if test -e "$1" && $MAKE_CHAPTERS; then - CMD="idvid -terse \"$1\"" - echo " Calculating the duration of the video with:" - echo " $CMD" - echo " This may take a few minutes, so please be patient..." - DURATION=$(eval $CMD | grep DURATION | awk -F '=' '{print $2}') - echo $DURATION | awk '{hh=int($1/3600);mm=int(($1-hh*3600)/60);ss=$1-hh*3600-mm*60;\ - printf " The duration of the video is %02d:%02d:%02d\n",hh,mm,ss}' - - CHAPTERS=$(make_chapters $DURATION $CHAPTER_INTERVAL) - # If file doesn't exist, or -nochapters was passed, use 0 chapters - else - CHAPTERS="0" - fi - - # Generate the XML for the title itself, appending to existing titles - if $MAKE_GROUP; then - if test $CUR_VIDEO -eq 1; then - TS_TITLES=`cat << EOF -$TS_TITLES - <pgc> -EOF` - fi - TS_TITLES=`cat << EOF - $TS_TITLES - <vob file="$1" chapters="$CHAPTERS" /> -EOF` - else - TS_TITLES=`cat << EOF -$TS_TITLES - <pgc> - <vob file="$1" chapters="$CHAPTERS" /> - __POST_CMD__ - </pgc> -EOF` - fi - - # -------------------------- - # For (S)VCD - else - - # If there's a menu, "return" goes back to it; if not, - # do not generate a "return" command - if $HAVE_MENU; then - RETURN_CMD="<return ref=\"select-menu-$CUR_TS\"/>" - else - RETURN_CMD="" - fi - # If this is the first title or slide in a series - if $FIRST_TITLE; then - # For the first titles, PREV stays on the current title - let "PREV_TITLE=$CUR_TITLE" - # For all other titles - else - # PREV goes to the previous slide - let "PREV_TITLE=$CUR_TITLE - 1" - fi - - # Fill in the NEXT command for the previous slide, if there was one - NEXT_TITLE="<next ref=\"play-title-$CUR_TITLE\"\/>" - SELECTION_XML=$( echo "$SELECTION_XML" | sed -e "s/__NEXT_TITLE__/$NEXT_TITLE/g" ) - PLAYLIST_XML=$( echo "$PLAYLIST_XML" | sed -e "s/__NEXT_TITLE__/$NEXT_TITLE/g" ) - - # -------------------------- - # If doing a still-image slideshow, use segment/selection - if $STILL_TITLES; then - echo "Adding title: $1 as number $CUR_TITLE in a slideshow" - - # Generate XML for the selection (menu) "buttons" that will - # jump to this slideshow. Only the first slide gets a button. - if $FIRST_TITLE; then - MENU_BUTTONS=`cat << EOF -$MENU_BUTTONS - <select ref="play-title-$CUR_TITLE"/> -EOF` - fi - - # Generate XML for the segment item - SEGMENT_ITEMS_XML=`cat << EOF -$SEGMENT_ITEMS_XML - <segment-item src="$1" id="seg-slide-$CUR_TITLE"/> -EOF` - - # Generate XML for the selection to go in pbc - # The slide will play indefinitely until NEXT, PREV, - # or RETURN is pressed. __NEXT_TITLE__ is a placeholder - # until we're sure there is a next slide; it will be - # filled in on the next addition if there is. - SELECTION_XML=`cat << EOF -$SELECTION_XML - <playlist id="play-title-$CUR_TITLE"> - <prev ref="play-title-$PREV_TITLE"/> - __NEXT_TITLE__ - $RETURN_CMD - <wait>-1</wait> - <play-item ref="seg-slide-$CUR_TITLE"/> - </playlist> -EOF` - - # -------------------------- - # If doing normal video titles, use select/playlist - else - - echo "Adding title: $1 as title number $CUR_TITLE" - - # Generate XML for the selection (menu) "buttons" that will - # jump to this playlist (title) - MENU_BUTTONS=`cat << EOF -$MENU_BUTTONS - <select ref="play-title-$CUR_TITLE"/> -EOF` - - # Generate XML for the sequence item - SEQUENCE_ITEMS_XML=`cat << EOF -$SEQUENCE_ITEMS_XML - <sequence-item src="$1" id="seq-title-$CUR_TITLE"/> -EOF` - - # Generate XML for the playlist for this title - PLAYLIST_XML=`cat << EOF -$PLAYLIST_XML - <playlist id="play-title-$CUR_TITLE"> - <prev ref="play-title-$PREV_TITLE"/> - __NEXT_TITLE__ - $RETURN_CMD - <wait>$PAUSE</wait> - <play-item ref="seq-title-$CUR_TITLE"/> - </playlist> -EOF` - - fi # (S)VCD slides or normal titles - - fi # DVD or (S)VCD - - FIRST_TITLE=false -} - -# ========================================================== -# Finalize the XML for a titleset, containing a menu and titles -function closeTitleset () -{ - # Proceed only if there are titles in this titleset - if (( $CUR_TITLE > 0 )); then - - # -------------------------- - # For DVD - if test $XML_FORMAT = "dvd"; then - echo "Closing titleset $CUR_TS with $CUR_TITLE title(s)." - - # Give each menu a button linking back to the top menu, if there is one - if $HAVE_TOP_MENU; then - MENU_BUTTONS=`cat << EOF -$MENU_BUTTONS - <button>jump vmgm menu;</button> - -EOF` - fi - - # Fill in titleset menu buttons - MENU_XML=$(echo "$MENU_XML" | \ - sed -e "s/__MENU_BUTTONS__/$(sedprep "$MENU_BUTTONS" /)/g") - - # Fill in the POST command. If there is a menu to jump back to, use that; - # otherwise, do not insert a POST command. - if $HAVE_MENU; then - POST_CMD="<post>call menu;<\/post>" - elif $FORCE_TITLESETS && $HAVE_TOP_MENU; then - POST_CMD="<post>call vmgm menu;<\/post>" - else - POST_CMD="" - fi - TS_TITLES=$( echo "$TS_TITLES" | sed -e "s/__POST_CMD__/$POST_CMD/g" ) - - # Append titleset info to ALL_MENU_XML - if ! $FORCE_TITLESETS || ! $HAVE_TOP_MENU; then - ALL_MENU_XML=`cat << EOF -$ALL_MENU_XML -<titleset> -$MENU_XML - <titles> - <video $NOPANSCAN format="$TV_FORMAT" /> -$TS_TITLES - </titles> -</titleset> -EOF` - else - # One titleset for each title -> add a dummy menu to the titleset - ALL_MENU_XML=`cat << EOF -$ALL_MENU_XML -<titleset> - <menus> - <pgc> - <post> - jump title 1; - </post> - </pgc> - </menus> - <titles> - <video $NOPANSCAN format="$TV_FORMAT"/> -$TS_TITLES - </titles> -</titleset> -EOF` - fi - # Clear existing XML to prepare for next titleset - MENU_XML="" - TS_TITLES="" - CUR_TITLE=0 - MENU_BUTTONS="" - - # -------------------------- - # For (S)VCD - else - - # Fill in menu title selections ("buttons") - # and remove any remaining __NEXT_TITLE__s - SELECTION_XML=$(echo "$SELECTION_XML" | \ - sed -e "s/__MENU_BUTTONS__/$(sedprep "$MENU_BUTTONS" /)/g" -e "s/__NEXT_TITLE__//g") - PLAYLIST_XML=$(echo "$PLAYLIST_XML" | sed -e "s/__NEXT_TITLE__//g") - - # Append new PBC menus/playlists to PBC_XML - PBC_XML=`cat << EOF -$PBC_XML -$SELECTION_XML -$PLAYLIST_XML - -EOF` - - # Clear existing XML to prepare for next menu/titles - SELECTION_XML="" - PLAYLIST_XML="" - MENU_BUTTONS="" - # Go back to doing normal video titles - STILL_TITLES=false - fi - - # Increment the current titleset number - (( CUR_TS++ )) - - fi # End if there are titles -} - -# ========================================================== -# EXECUTION BEGINS HERE -echo "$SCRIPTNAME" - -if test $# -lt 1; then - usage_error "Please provide at least one video to author, and the name of an output file to use." -fi - -while test $# -gt 0; do - case "$1" in - "-quiet" ) - QUIET=: - ;; - "-out" ) - shift - OUT_PREFIX="$1" - ;; - "-pause" ) - shift - PAUSE="$1" - ;; - # Format and overwriting options - "-dvd" ) XML_FORMAT="dvd" ;; - "-vcd" ) XML_FORMAT="vcd" ;; - "-svcd" ) XML_FORMAT="svcd" ;; - "-overwrite" ) OVERWRITE=: ;; - # Menus and video titles - "-topmenu" ) - shift - if ! $HAVE_TOP_MENU; then - checkExistence "$1" - addTopMenu "$1" - else - usage_error "Please specify only one -topmenu option. If you would like to have multiple menus, please use the -menu option." - fi - ;; - "-menu" ) - if $FORCE_TITLESETS; then - usage_error "You can not use -titlesets with -menu. Please use -topmenu instead." - fi - shift - HAVE_MENU=: - FIRST_TITLE=: - checkExistence "$1" - closeTitleset - addMenu "$1" - ;; - "-slides" ) - STILL_TITLES=: - FIRST_TITLE=: - ;; - "-group" ) - MAKE_GROUP=: - CUR_VIDEO=0 - ;; - "-endgroup" ) - if $MAKE_GROUP; then - TS_TITLES=`cat << EOF - $TS_TITLES - __POST_CMD__ - </pgc> -EOF` - fi - MAKE_GROUP=false - CUR_VIDEO=0 - ;; - "-chapter-points" ) - # Space-separated list of comma-separated chapter points - MAKE_CHAPTERS=: - shift - IFS=""; while test $# -gt 0 && test ${1:0:1} != "-"; do - CHAPTER_POINTS=("${CHAPTER_POINTS[@]}" "$1") - shift - done - if test $# -gt 0 && test ${1:0:1} = "-"; then - DO_SHIFT=false; - fi - unset IFS - ;; - "-chapters" ) - # Fixed chapter intervals - MAKE_CHAPTERS=: - shift - CHAPTER_INTERVAL=$1 - if test "$CHAPTER_INTERVAL" -lt "0" || \ - test "$CHAPTER_INTERVAL" -gt "9999"; - then - usage_error "Please use a -chapters interval between 0 and 9999." - fi - ;; - "-nochapters" ) - MAKE_CHAPTERS=false - ;; - "-titlesets" ) - if $HAVE_MENU; then - usage_error "You can not use -titlesets with -menu. Please use -topmenu instead." - fi - FORCE_TITLESETS=: - echo "Creation of titlesets forced ..." - ;; - * ) - checkExistence "$1" - addTitle "$1" - ;; - esac - # Get the next argument - shift -done - -# Last argument should be the name of the output file -if test -z "$OUT_PREFIX"; then - usage_error "Please provide an output filename with -out." -fi - -# See if selected output file exists. If so, confirm for overwrite. -if test -e "$OUT_PREFIX.xml"; then - echo $SEPARATOR - echo "*** The output file you specified: $OUT_PREFIX.xml already exists." - if $OVERWRITE; then - echo "Overwriting existing file." - else - echo "Please re-run the script with the -overwrite option to overwrite." - exit 1 - fi - echo $SEPARATOR -fi - - -# Close current titleset -closeTitleset - -# Fill in top menu buttons -TOP_MENU_XML=$(echo "$TOP_MENU_XML" | \ - sed -e "s/__TOP_MENU_BUTTONS__/$(sedprep "$TOP_MENU_BUTTONS" /)/g") - -# If there is a top menu with no other menus, print an error and -# a suggestion that user specify -menu instead of -topmenu -if $HAVE_TOP_MENU && ! $HAVE_MENU && ! $FORCE_TITLESETS; then - echo "You have specified a top menu without any other menus. If you only want to have one menu, please use the -menu option instead of -topmenu." - echo "Exiting without writing XML file." - exit 1 -fi - -# Assemble the final XML file - -# dvdauthor format for a DVD -if test $XML_FORMAT = "dvd" ; then -FINAL_DISC_XML=`cat << EOF -<dvdauthor dest="$OUT_PREFIX"> -<!-- makexml $TOVID_VERSION --> -<vmgm> -$TOP_MENU_XML -</vmgm> -$ALL_MENU_XML -</dvdauthor> -EOF` - -# vcdxbuild (vcdimager) format for a VCD or SVCD -else - # Determine what version number to use - if test $XML_FORMAT = "vcd" ; then - VCD_VERSION="2.0" - OPTION_LINE='' - # Use 1.0 for SVCD - else - VCD_VERSION="1.0" - OPTION_LINE='<option name="update scan offsets" value="true" />' - fi - - # Make sure there are segment-items and sequence-items - if test -n "$SEGMENT_ITEMS_XML" ; then - SEGMENT_ITEMS_XML=`cat << EOF -<segment-items> -$SEGMENT_ITEMS_XML -</segment-items> -EOF` - fi - if test -n "$SEQUENCE_ITEMS_XML" ; then - SEQUENCE_ITEMS_XML=`cat << EOF -<sequence-items> -$SEQUENCE_ITEMS_XML -</sequence-items> -EOF` - fi - -FINAL_DISC_XML=`cat << EOF -<?xml version="1.0"?> -<!DOCTYPE videocd PUBLIC "-//GNU/DTD VideoCD//EN" - "http://www.gnu.org/software/vcdimager/videocd.dtd"> -<videocd xmlns="http://www.gnu.org/software/vcdimager/1.0/" - class="$XML_FORMAT" version="$VCD_VERSION"> -$OPTION_LINE -<info> - <album-id>VIDEO_DISC</album-id> - <volume-count>1</volume-count> - <volume-number>1</volume-number> - <restriction>0</restriction> -</info> - -<pvd> - <volume-id>VIDEO_DISC</volume-id> - <system-id>CD-RTOS CD-BRIDGE</system-id> -</pvd> - -$SEGMENT_ITEMS_XML - -$SEQUENCE_ITEMS_XML - -<pbc> -$TOP_MENU_XML - -$PBC_XML -</pbc> -</videocd> -EOF` -fi - -# Remove blank lines and write final result to output file -echo "$FINAL_DISC_XML" | sed -e '/^ *$/d' > "$OUT_PREFIX.xml" - -echo "Done. The resulting XML was written to $OUT_PREFIX.xml." - -if ! $QUIET; then - if test $XML_FORMAT = "dvd" ; then - echo "You can now author, image and/or burn the disc by running:" - echo " tovid dvd \"$OUT_PREFIX.xml\"" - else - echo "You can create the (S)VCD .bin and .cue files by running the command:" - echo " tovid vcd \"$OUT_PREFIX.xml\"" - fi - echo "Thanks for using makexml!" -fi - -exit 0 -
View file
tovid-0.34.tar.bz2/src/postproc
Deleted
@@ -1,296 +0,0 @@ -#!/usr/bin/env bash -ME="[postproc]:" -. tovid-init 2>/dev/null || -{ echo -e "===============================================================\n" -echo -e "'tovid-init' not found. Was tovid improperly installed?" -echo -e "Or are you trying to run the script directly?" -echo -e "Please run postproc as:\ntovid postproc OPTIONS" -exit 1 ; } - -# postproc -# Part of the tovid suite -# ======================= -# A bash script for doing post-encoding processing on -# MPEG video files. Can requantize (shrink) video and -# adjust A/V sync. -# -# Project homepage: http://tovid.wikia.com -# -# Copyright (C) 2005-2010 -# -# 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 2 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, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Or see: -# -# http://www.gnu.org/licenses/gpl.txt - -SCRIPT_NAME=`cat << EOF --------------------------------- -tovid postproc -Post-process video files -Version $TOVID_VERSION -$TOVID_HOME_PAGE --------------------------------- -EOF` - -USAGE=`cat << EOF -Usage: tovid postproc [OPTIONS] {input file} {output file} - -Where OPTIONS may be any of the following: - - -audiodelay NUM Delay audio by NUM milliseconds - -normalize Normalize the audio - -amplitudeNUM[dB] Apply a gain of NUM (0 - 1.0, add dB for decibel gain) - -shrink NUM Shrink video by factor NUM (1.0 - 2.0) - -parallel Run all processes in parallel (can save time) - -debug Keep a log of actions and output - -See the tovid manual page ('man tovid') for additional documentation. - -EOF` - -SEPARATOR="=========================================================" - -# Default values -TMP_FILE="postproc.fileinfo.$PPID" -AUDIO_DELAY="" -SHRINK_FACTOR="" -DO_NORM=false -AUDIO_AMPLITUDE="" -DO_SHRINK=false -MUX_OPTS="" -DEBUG=false -# File to use for saving postprocessing statistics -STAT_DIR=$HOME/.tovid -STAT_FILE="$STAT_DIR/stats.postproc" -SHRINK_PERCENT="0" -PARALLEL=false -# Video format in use -VIDEO_FORMAT="DVD" -BACKGR="" - -# Print script name, usage notes, and optional error message, then exit. -# Args: $1 == text string containing error message -usage_error () -{ - echo "$USAGE" - echo "$SEPARATOR" - echo "$@" - exit 1 -} - -# Remove temporary files -cleanup () -{ - echo "Cleaning up..." - rm -fv video_shrink video_dump audio_dump normed_audio - -} - - -# *********************************** -# EXECUTION BEGINS HERE -# *********************************** - -echo "$SCRIPT_NAME" - -# Make sure there are at least two arguments (infile and outfile) -if test $# -lt 2; then - usage_error "Error: Please provide an input filename and an output filename." -fi - -while test ${1:0:1} = "-"; do - case "$1" in - "-audiodelay" ) - shift - AUDIO_DELAY="-O ${1}ms" - ;; - "-shrink" ) - shift - DO_SHRINK=: - SHRINK_FACTOR="$1" - assert_dep "$transcode" "You are missing dependencies required for shrinking video!" - ;; - "-parallel" ) - PARALLEL=: - cleanup - mkfifo video_dump - mkfifo audio_dump - mkfifo video_shrink - BACKGR="&" - ;; - "-normalize" ) - DO_NORM=: - ;; - "-amplitude" ) - shift - AUDIO_AMPLITUDE="--amplitude=$1" - DO_NORM=: - ;; - "-debug" ) - DEBUG=: - ;; - esac - - # Get next argument - shift -done - - -IN_FILE="$1" -shift -OUT_FILE="$1" - -echo $SEPARATOR - -$DO_NORM && assert_dep "sox" "You are missing dependancies necessarily for processing audio wav's" -if $DO_NORM && $PARALLEL; then - echo "Cannot normalize audio in parallel mode! Turning off -parallel." - PARALLEL=false - cleanup -fi - -# Figure out what format it is. 44.1khz audio can be VCD or SVCD, -# 48khz audio is DVD. -echo "Gathering file information. This may take a while." -if eval $(idvid -terse "$IN_FILE"); then :; else - echo "Could not identify source video: $IN_FILE" - exit 1 -fi -video_format=$(tr A-Z a-z <<< $ID_VIDEO_FORMAT)video - -if test $ID_AUDIO_RATE -eq "48000"; then - MUX_OPTS="-V -f 8" - VIDEO_FORMAT="DVD" -elif test $ID_AUDIO_RATE -eq "44100"; then - # VCD is 352 wide, SVCD is 480 wide - if test $ID_VIDEO_WIDTH -eq "352"; then - MUX_OPTS="-f 1" - VIDEO_FORMAT="VCD" - elif test $ID_VIDEO_WIDTH -eq "480"; then - MUX_OPTS="-V -f 4" - VIDEO_FORMAT="SVCD" - fi -fi - -echo "Dumping audio and video streams with the following commands:" - -# Dump audio and video -if $DO_NORM; then - AUDIO_DUMP="ffmpeg -i \"$IN_FILE\" -vn -f wav -y audio_dump" -else - #AUDIO_DUMP="mplayer \"$IN_FILE\" -quiet -dumpaudio -dumpfile audio_dump" - AUDIO_DUMP="ffmpeg -i \"$IN_FILE\" -vn -f $ID_AUDIO_CODEC -acodec copy -y audio_dump" -fi -VIDEO_DUMP="ffmpeg -i \"$IN_FILE\" -an -f $video_format -vcodec copy -y video_dump" -VID_STREAM="video_dump" - -echo "$AUDIO_DUMP" -echo "$VIDEO_DUMP" -# Should always be safe to put audio decode in the background -eval $AUDIO_DUMP > $TMP_FILE 2>&1 & -eval $VIDEO_DUMP >> $TMP_FILE 2>&1 $BACKGR - -# Let the audio process finish if not in parallel mode (should always finish -# before video, so this is just precautionary) -$PARALLEL || wait - -# Normalize/gain -if $DO_NORM; then - AUDIO_NORM="$NORMALIZE $AUDIO_AMPLITUDE audio_dump" - - echo "Normalizing audio/applying gain with the following command:" - echo "$AUDIO_NORM" - eval $AUDIO_NORM - - # Re-encode audio - mv -v audio_dump normed_audio - AUDIO_BITRATE=$(expr $ID_AUDIO_BITRATE / 1000) - AUDIO_ENC="ffmpeg -i normed_audio -vn -ab ${AUDIO_BITRATE}k -ar $ID_AUDIO_RATE" - AUDIO_ENC="$AUDIO_ENC -ac $ID_AUDIO_NCH -acodec $ID_AUDIO_CODEC" - AUDIO_ENC="$AUDIO_ENC -y audio_dump.$ID_AUDIO_CODEC" - - echo "Encoding the normalized/gained audio stream with the following command:" - echo "$AUDIO_ENC" - eval $AUDIO_ENC - - mv -v audio_dump.$ID_AUDIO_CODEC audio_dump -fi - -# Shrink, if requested -if $DO_SHRINK; then - # Can't shrink VCD - if test $VIDEO_FORMAT = "VCD"; then - echo $SEPARATOR - echo "This file appears to be in VCD format. Unfortunately, the" - echo "VCD specification does not allow shrinking (requantization)." - echo "Shrinking will be skipped." - echo $SEPARATOR - else - START_SIZE=$( ls -l video_dump | awk '{print $5}' ) - echo $SEPARATOR - echo "Shrinking video stream by a factor of $SHRINK_FACTOR" - SHRINK_CMD="tcrequant -i video_dump -o video_shrink -f $SHRINK_FACTOR" - echo "$SHRINK_CMD" - eval $SHRINK_CMD $BACKGR - VID_STREAM="video_shrink" - if $PARALLEL; then - : - else - wait - SHRINK_SIZE=$( ls -l video_shrink | awk '{print $5}' ) - SHRINK_PERCENT=$(expr 100 \- \( 100 \* $SHRINK_SIZE \/ $START_SIZE \)) - echo "Video stream was shrunk by $SHRINK_PERCENT%" - fi - fi -fi - -echo $SEPARATOR - -# Multiplex audio and video back together -echo "Multiplexing audio and video streams with the following command:" -MPLEX_CMD="mplex $VID_STREAM audio_dump -o \"$OUT_FILE\" $MUX_OPTS $AUDIO_DELAY" -echo "$MPLEX_CMD" -eval $MPLEX_CMD >> $TMP_FILE 2>&1 - -# For parallel, compare infile and outfile sizes -if $PARALLEL; then - START_SIZE=$( ls -l "$IN_FILE" | awk '{print $5}' ) - SHRINK_SIZE=$( ls -l "$OUT_FILE" | awk '{print $5}' ) - SHRINK_PERCENT=$(expr 100 \- \( 100 \* $SHRINK_SIZE \/ $START_SIZE \)) - echo "Video stream was shrunk by $SHRINK_PERCENT%" -fi - -echo $SEPARATOR - -cleanup - -# Create stats directory and save video statistics -mkdir -p $STAT_DIR -FINAL_STATS=`cat << EOF -postproc $TOVID_VERSION -File: $OUT_FILE -Shrink factor: $SHRINK_FACTOR -Shrunk by: $SHRINK_PERCENT% -EOF` -echo $"$FINAL_STATS" >> $STAT_FILE - -# If doing debugging, keep log and print message -if $DEBUG; then - echo "All output has been saved in the file: $TMP_FILE." -else - rm $TMP_FILE -fi - -echo "Done. Thanks for using postproc!"
View file
tovid-0.34.tar.bz2/src/tovid-batch
Deleted
@@ -1,96 +0,0 @@ -#!/usr/bin/env bash -ME="[tovid-batch]:" -. tovid-init 2>/dev/null || -{ echo -e "===============================================================\n" -echo -e "'tovid-init' not found. Was tovid improperly installed?" -echo -e "Or are you trying to run the script directly?" -echo -e "Please run tovid-batch as:\ntovid batch OPTIONS" -exit 1 ; } - -# tovid-batch -# Part of the tovid suite -# ======================= -# A bash script for batch video conversion. -# -# Project homepage: http://tovid.wikia.com -# -# Copyright (C) 2005-2010 -# -# 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 2 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, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Or see: -# -# http://www.gnu.org/licenses/gpl.txt - -SCRIPT_NAME=`cat << EOF --------------------------------- -tovid-batch -A batch conversion script using tovid -Part of the tovid suite, version $TOVID_VERSION -$TOVID_HOME_PAGE --------------------------------- -EOF` - -USAGE=`cat << EOF -Usage: tovid batch [OPTIONS] -infiles <input files> - -OPTIONS may be any options that tovid accepts. See 'man tovid'. - -EOF` - -SEPARATOR="==============================================================================" - -# No tovid arguments to start with -TOVID_ARGS="" - -# *********************************** -# EXECUTION BEGINS HERE -# *********************************** - -precho "$SCRIPT_NAME" - -# Get all arguments up to -infiles -while test $# -gt 0; do - if test "$1" = "-infiles"; then - shift - break - else - TOVID_ARGS="$TOVID_ARGS $1" - fi - - # Get next argument - shift -done - -# If no infiles, print usage notes -if test $# -le 0; then - precho "$USAGE" - echo "$SEPARATOR" - echo "Please provide a list of files to encode using -infiles" - exit 1 -fi - -# For every input filename provided, run tovid with the given options -for FILE in "$@"; do - echo $SEPARATOR - if test -e "$FILE"; then - EXT=$(echo "$FILE" | awk -F '.' '{ print $NF }') - FILENAME=$(basename "$FILE" ."$EXT") - TOVID_CMD="tovid mpg -noask $TOVID_ARGS -in \"$FILE\" -out \"$FILENAME.tovid_encoded\"" - precho $TOVID_CMD - eval $TOVID_CMD - else - echo "Couldn't find file \"$FILE\", not encoding it." - fi -done
View file
tovid-0.34.tar.bz2/src/tovid-interactive
Deleted
@@ -1,181 +0,0 @@ -#!/usr/bin/env bash -ME="[tovid-interactive]:" -. tovid-init 2>/dev/null || -{ echo -e "===============================================================\n" -echo -e "'tovid-init' not found. Was tovid improperly installed?" -echo -e "Or are you trying to run the script directly?" -echo -e "Please run tovid-interactive as:\ntovid interactive OPTIONS" -exit 1 ; } - -# tovid-interactive -# Part of the tovid suite -# ======================= -# A bash script with an interactive frontend to the tovid -# script. This script prompts the user for all options, and -# then runs the tovid script with the selected options. -# -# Project homepage: http://tovid.wikia.com -# -# Copyright (C) 2005-2010 -# -# 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 2 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, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Or see: -# -# http://www.gnu.org/licenses/gpl.txt - -WELCOME=`cat << EOF --------------------------------- -tovid-interactive -Interactive CLI front-end to tovid -Part of the tovid suite, version $TOVID_VERSION -$TOVID_HOME_PAGE --------------------------------- - -Welcome to the tovid-interactive script. This script is an interactive front-end for the tovid video conversion script. I will ask you several questions about the video you want to encode, and then run the tovid script with the options you choose. - -EOF` - -SEPARATOR="===============================================================================" - -precho $"$WELCOME" -echo $SEPARATOR - -# Make sure tovid is in the path -if ! test -x $(which tovid); then - precho "Oops! I can't find tovid in your path. Before you use this script, please install the tovid suite by running the 'configure' script from the directory where you unzipped tovid." - exit 1 -fi - -# 7 Get the file to encode -echo "Step 1 of 7:" -if test $# -eq 1; then - INFILE="$1" - echo "Encoding the filename provided on the command-line:" - echo "$1" - echo $SEPARATOR -else - INFILE="" - if test $# -gt 1; then - echo "I found more than one command line paramter! Please give only one" - echo "video to encode. You gave me $#:" - echo "$@" - fi - precho "What video file do you want to encode? Please use the full path name if the file is not in the current directory. Hint: if you don't know the full name of the file, you can press [control]-C now, and run tovid-interactive followed by the name of the file." - while ! test -e "$INFILE"; do - echo -n "filename: " - read INFILE - if ! test -e "$INFILE"; then - echo "Cannot find \"$INFILE\"! Please try again." - fi - done - echo $SEPARATOR -fi - -# 6 Ask for format -echo "Step 2 of 7:" -echo "You can encode this video to one of the following formats:" -echo "For burning onto DVD:" -echo " dvd DVD format 720x480 NTSC, 720x576 PAL" -echo " half-dvd Half-DVD format 352x480 NTSC, 352x576 PAL" -echo " dvd-vcd VCD-on-DVD format 352x240 NTSC, 352x288 PAL" -echo "For burning onto CD:" -echo " vcd Video CD format 352x240 NTSC, 352x288 PAL" -echo " svcd Super Video CD format 480x480 NTSC, 480x576 PAL" - -VIDFORMAT="none" -until $(verify $VIDFORMAT set "dvd half-dvd dvd-vcd vcd svcd") -do - echo "Please enter one of the formats listed (dvd, half-dvd, dvd-vcd, vcd, svcd)." - echo -n "format: " - read VIDFORMAT -done - echo $SEPARATOR - -# 5 Ask for NTSC or PAL -echo "Step 3 of 7:" -precho "Do you want the video to be NTSC or PAL? If you live in the Americas or Japan, you probably want NTSC; if you live in Europe, Australia, or New Zealand, you probably want PAL." - -TVSYS="none" -until $(verify $TVSYS set "ntsc pal") -do - echo "Please use lowercase (ntsc, pal)." - echo -n "ntsc or pal: " - read TVSYS -done -echo $SEPARATOR - -# 4 Ask for aspect ratio -echo "Step 4 of 7:" -echo "You can encode to three different screen formats:" -echo " full If your video is full-screen (4:3 aspect ratio)" -echo " wide If your video is wide-screen (16:9 aspect ratio)" -echo " panavision If your video is theatrical wide-screen (2.35:1 aspect ratio)" -precho "If you choose wide or panavision, the video will be 'letterboxed' to fit a standard TV screen. Most TV programs are 'full'; many movies are 'wide', and some movies are 'panavision' (if they look very wide and skinny)." - -ASPECT="none" -until $(verify $ASPECT set "full wide panavision") -do -echo "Please enter one of the screen formats listed (full, wide, panavision)." -echo -n "screen format: " -read ASPECT -done -echo $SEPARATOR - -# 3 Normalize audio? -echo "Step 5 of 7:" -precho "In some videos, the volume may be too quiet or too loud. You can fix this by normalizing the audio." - -NORMALIZE="none" -until $(verify $NORMALIZE set "n N y Y yes Yes") -do -echo -n "normalize audio (default yes) [y/n]? " -read NORMALIZE -done -if test "x$NORMALIZE" = "xn" || test "x$NORMALIZE" = "xN"; then - NORMALIZE="" -else - NORMALIZE="-normalize" -fi -echo $SEPARATOR - -# 2 Any custom options? -echo "Step 6 of 7:" -precho "Would you like to pass other options to tovid? (see man tovid for more) Add any other options you want as if you were calling tovid. For example, if you wanted to add subtitles, you would type '-subtitles <file>'. Type [enter] for no custom options." -echo -n "custom tovid options: " -read CUSTOM_OPTIONS -echo $SEPARATOR - -# 1 Get output prefix -echo "Step 7 of 7:" -precho "You are almost ready to encode your video. All I need now is the name you want to use for the output file. You don't need to give a filename extension (like .mpg); just type a name like 'MyVideo1'." -echo -n "output name: " -read OUT_PREFIX -echo $SEPARATOR - -# Print last message and call tovid -echo "Great! I will now start tovid with the options you chose. Here is the" -echo "command that will be executed:" -TOVID_CMD="tovid $NORMALIZE -$VIDFORMAT -$TVSYS -$ASPECT $CUSTOM_OPTIONS -in \"$INFILE\" -out \"$OUT_PREFIX\"" -echo $SEPARATOR -precho "$TOVID_CMD" -echo $SEPARATOR -echo "Starting tovid in 5 seconds..." -for COUNTER in 5 4 3 2 1; do - sleep 1s - echo -n "$COUNTER " -done -echo "Here goes!" -eval $TOVID_CMD -exit 0
View file
tovid-0.34.tar.bz2/INSTALL -> tovid-0.35.tar.gz/INSTALL
Changed
@@ -6,13 +6,6 @@ This file contains configuration and installation instructions for tovid. -!!!! -NOTE: Prior releases of tovid used autoconf and automake, but these will -be discontinued in a future release. As of tovid-0.33, setup.py is the -recommended installation method. -!!!! - - ===================================================== INSTALLING FROM DISTRIBUTED SOURCE (*.tar.gz) ===================================================== @@ -25,6 +18,16 @@ or $ sudo ./setup.py install +If you want to install to somewhere other than /usr/local, you can use: + $ su -c './setup.py install --prefix=/opt' for example. +Note: with some versions of python's distutils this will by default install +modules to .../site-packages rather than .../dist-packages even if that is +where your system's python looks for them. See: +https://bugs.launchpad.net/ubuntu/+source/python2.6/+bug/362570 +As a workaround, if you are using --prefix you can add: + --install-layout=deb . + + If you want to uninstall tovid, do this: $ su -c './setup.py uninstall'
View file
tovid-0.34.tar.bz2/PKG-INFO -> tovid-0.35.tar.gz/PKG-INFO
Changed
@@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: tovid -Version: 0.34 +Version: 0.35 Summary: UNKNOWN Home-page: http://tovid.wikia.com/ Author: Eric Pierce
View file
tovid-0.34.tar.bz2/docs/man/tovid.1 -> tovid-0.35.tar.gz/docs/man/tovid.1
Changed
@@ -1,10 +1,13 @@ .TH "tovid manual" 1 "" "" + .SH Name + .P tovid: Make DVDs from video files .SH Description + .P \fBtovid\fR is a command\-line tool for creating DVDs. It can encode your video files to DVD\-compliant MPEG format, generate simple or complex DVD menus, @@ -12,12 +15,17 @@ graphical interface is also provided to make the process even easier. .P -\fBNOTE\fR: As of tovid 0.32, this is the only manual page provided by tovid. -There is now a single executable frontend to all functionality in the suite, so -if you were expecting to find manpages for \fBtodisc\fR, \fBidvid\fR, \fBmakemenu\fR -and their kin, they can all be found in the \fBtovid\fR manpage you are reading now. +\fBNOTE\fR: As of tovid 0.35, the legacy scripts \fBmakemenu\fR and \fBmakexml\fR +have been removed and no longer appear in this manpage. +All of their functions and more can be done with the 'tovid disc' command, +(todisc script). See \fBCommand:disc\fR and the wiki (http://tovid.wikia.com) +for more info. .P +Also note that as of tovid 0.32, this is the only manual page provided by tovid. +There is now a single executable frontend to all functionality in the suite, so +if you were expecting to find manpages for \fBtodisc\fR, \fBidvid\fR, \fBmakempg\fR +and their kin, they can all be found in the \fBtovid\fR manpage you are reading now. And yes, this makes for a pretty large manual page. If you are viewing this manpage from the command\-line \fBman\fR utility, which normally pages through the \fBless\fR utility, you can skip to a section by searching with the \fB/\fR key, @@ -26,104 +34,152 @@ to navigate. .SH Usage + .P \fBtovid\fR \fICOMMAND\fR [\fIOPTIONS\fR] .P Where \fICOMMAND\fR is one of the following: +.P + Main Commands + +.TP +\fBdisc\fR +Encode, make menus, author, burn. (was \fBtodisc\fR. See \fBCommand:disc\fR) .TP \fBgui\fR Start the tovid GUI (was \fBtodiscgui\fR. See \fBCommand:gui\fR) .TP \fBtitlesets\fR -A tovid GUI wizard for multiple titlesets. (new: See \fBCommand:titlesets\fR) -.TP -\fBdisc\fR -Create a DVD with menus (was \fBtodisc\fR. See \fBCommand:disc\fR) +A GUI wizard for multiple titlesets. (new: See \fBCommand:titlesets\fR) + +.P + Helper Commands + .TP \fBmpg\fR Encode videos to MPEG format (was \fBtovid\fR. See \fBCommand:mpg\fR) .TP -\fBid\fR -Identify one or more video files (was \fBidvid\fR. See \fBCommand:id\fR) -.TP -\fBmenu\fR -Create an MPEG menu (was \fBmakemenu\fR. See \fBCommand:menu\fR) -.TP -\fBxml\fR -Create (S)VCD or DVD .xml file (was \fBmakexml\fR. See \fBCommand:xml\fR) -.TP \fBdvd\fR Author and/or burn a DVD (was \fBmakedvd\fR. See \fBCommand:dvd\fR) .TP -\fBvcd\fR -Author and/or burn a VCD (was \fBmakevcd\fR. See \fBCommand:vcd\fR) -.TP -\fBpostproc\fR -Post\-process an MPEG video file (was \fBpostproc\fR. See \fBCommand:postproc\fR) +\fBid\fR +Identify one or more video files (was \fBidvid\fR. See \fBCommand:id\fR) .TP \fBchapters\fR A GUI using mplayer for setting chapter points. It will return a string of -chapter points in a format recognized by 'tovid disc' (todisc) or -by 'tovid gui', for the \fB\-chapters\fR option. +chapter points to the terminal, in a format recognized by 'tovid disc' +(todisc) or by 'tovid gui', for the \fB\-chapters\fR option. .P The \fIOPTIONS\fR differ for each command; run \fBtovid <command>\fR with no further arguments to get help on a command, and what options it expects. .SH Configuration + .P Two configuration files are created the first time you run tovid: .TP \fB~/.tovid/preferences\fR Defines working directory for all scripts. -In addition you can define the output directory for makempg here. +You can define the output directory for makempg here. +The 'ffmpeg' executable can be set here: ffmpeg or avconv (TOVID_FFMPEG) .TP \fB~/.tovid/tovid.ini\fR Includes command\-line options that should be passed to the various -\fBtovid\fR sub\-commands. +\fBtovid\fR sub\-commands. Note: each sub\-command has its own section, +starting with the line [sub\-command], for example: +.nf + [disc] + ; -no-warn + -static + -no-ask +.fi + + +.P Edit these files if you wish to change your configuration. +.P The following environment variables are also honoured: -TOVID_WORKING_DIR (working directory for all scripts). -TOVID_OUTPUT_DIR (output directory for the makempg script). + +.nf + TOVID_HOME (directory containing preferences: ~/.tovid) + TOVID_WORKING_DIR (working directory for all scripts). + TOVID_OUTPUT_DIR (output directory for the makempg script). + TOVID_FFMPEG_CMD (the 'ffmpeg' executable to use: ffmpeg or avconv) +.fi + + +.P +These will override 'TOVID_HOME', 'WORKING_DIR', 'OUTPUT_DIR', +and 'TOVID_FFMPEG' if set in ~/.tovid/preferences. .SH Command:gui + +.SH Usage + +.P +\fBtovid gui\fR [\fIOPTIONS\fR] + .P \fBtovid gui\fR starts the graphical user interface (GUI) for tovid. This is -the easiest way to start creating DVDs with tovid. At this time, there are no -additional command\-line options; the GUI controls take care of everything, -and all help is integrated in the form of tooltips. You can also see -**Command:disc ** for more detail about the options. Note: if you wish to -make multiple titlesets on the same DVD use 'tovid titlesets', which is a wizard -that uses the the tovid GUI. Chapter submenus can be made with 'tovid gui' -however. +the easiest way to start creating DVDs with tovid. The optional arguments +\fIOPTIONS\fR are any option used by todisc ('tovid disc') which will save +entering it manually, OR the full path to a saved script from the GUI. +You can also combine these, but the script must be the FIRST option +directly after \fBtovid gui\fR . (This option to save the contents of your +project allows you to use it as a bash script later, or to reload the +project to continue working with it at another time.) + +.P +\fBtovid gui\fR will also take the option \fB\-\-position\fR, which denotes the +screen position that the GUI will start at, in the form '+X+Y', similar to +this part of the Xorg \-geometry string. + +.P +All help is integrated in the form of tooltips. You can also see +**Command:disc ** for more detail about the options. Note: if you wish to use +a GUI to make multiple titlesets on the same DVD use \fB*tovid titlesets*\fR, +which is a wizard that uses the the 'tovid gui. See \fB*Command:titlesets*\fR. + +.P +Please note that although the interface may seem complex with so many options, +you can create a fully functional DVD with only a few options on the opening +tab of the GUI (select video files and an output name). .SH Command:titlesets + .P \fBtovid titlesets\fR will assist in making a DVD with multiple titlesets. It can be started without any options, or you can feed it the path to a saved titleset -script as an option. +script as an option. The option to save a script is also useful as the resulting +script can be run later from a terminal. .SH Command:disc + .P -\fBtovid disc\fR creates a DVD file\-system with menus, from a list of multimedia -video files and their titles. As this is a low level script it is the easiest -command line program for creating a DVD from start to finish, including -automatically converting non\-compliant videos and prompting to burn at -completion. It does animated menus, static thumbnail menus and text only -menus. In addition, it can do slideshows, using images as input, and combine -slideshows with videos. It supports sub\-menus for chapter breaks, configurable -menu style, animated backgrounds and transparency effects. +\fBtovid disc\fR creates a DVD file\-system with optional menus, from a list of +multimedia video files and their titles. As todisc can function as a master +script, calling other scripts as it needs them, it is the easiest command line +program for creating a DVD from start to finish, including automatically +converting non\-compliant videos and prompting to burn at completion. It can do +animated menus, static thumbnail menus, text\-only menus, or author with no menu. +In addition, it can do slideshows, using images as input, and even combine +slideshows with videos. It supports sub\-menus for chapter breaks, +configurable menu style, animated backgrounds and transparency effects. +From simple (no menu) to complex (switched menus and titlesets), you should +be able to do what you want with 'tovid disc'. .SS Usage + .nf - tovid disc [OPTIONS] \e - -files <file list> -titles <title list> - -out OUT_PREFIX + tovid disc [OPTIONS] \e + -files <file list> -titles <title list> + -out mydvd .fi @@ -131,9 +187,9 @@ For example: .nf - $ tovid disc -files File1.mpg File2.mpg File3.mpg \e - -titles "Episode 1" "Episode 2" "Episode 3" \e - -out Season_one + $ tovid disc -files File1.mpg File2.mpg File3.mpg \e + -titles "Episode 1" "Episode 2" "Episode 3" \e + -out Season_one .fi @@ -143,12 +199,15 @@ as titles. If you are doing a slideshow or multiple slideshows, use \fB\-slides\fR rather than \fB\-files\fR for passing in the images. You may use \-files and \-slides more than once to create an ordering in a mixed -slideshows/videos menu. See SLIDESHOWS part of Usage section, below. +slideshows/videos menu. See Slideshows part of Usage section, below. .P If the input files are not mpeg, you will have the option to auto\-encode them. .P +General Options + +.P \fBAt present there are 2 display arrangements or "templates":\fR .TP @@ -184,19 +243,40 @@ sub\-menus, which can display longer titles, for example: .nf - $ tovid disc -submenus \e - -files file1.mpg file2.mpg ... \e - -titles "Short 1" "Short 2" \e - -submenu-titles "Long Title One" "Long Title Two" \e - -out foo - + $ tovid disc -submenus \e + -files file1.mpg file2.mpg ... \e + -titles "Short 1" "Short 2" \e + -submenus \e + -submenu-titles "Long Title One" "Long Title Two" \e + -out foo + .fi .P The \fB\-align\fR argument will position both titles and thumbs either south, north east, west, southwest, northwest, southeast, northeast, subject to -certain constraints of each arrangement. +certain constraints of each arrangement. For example a showcase style with +a showcase thumb can only do north|south|center. + +.P +More Examples: + +.P +A text\-only menu: + +.nf + $ tovid disc -textmenu ... +.fi + + +.P +No menu: + +.nf + $ tovid -nomenu -files file1.mpg file2.mp4 "file 3.avi" -out mydvd +.fi + .P \fBTitlesets\fR @@ -216,9 +296,9 @@ .P Any options outside the \fB\-titleset\fR \fB\-end\-titleset\fR and \fB\-vmgm\fR -\fB\-end\-vmgm\fR areas will be general options applying to every titleset. -If a general option is duplicated inside a \fB\-titleset\fR or \fB\-vmgm\fR area, the -general option will be overridden. +\fB\-end\-vmgm\fR areas will be global options applying to every titleset. +If a global option is duplicated inside a \fB\-titleset\fR or \fB\-vmgm\fR area, the +global option will be overridden. .P Note: you do not need titlesets for a single menu with chapter break menus, for @@ -228,24 +308,26 @@ Example of using \fBtovid disc\fR with titlesets: .nf - $ tovid disc -static -out MY_DVD \e - \e - -titleset -files 1.mpg 2.mpg 3.mpg \e - -titles "Title One" "Title Two" "Title Three" \e - -end-titleset \e - \e - -titleset -files 4.mpg 5.mpg \e - -titles "Title Four" "Title Five" \e - -background foo.jpg \e - -showcase bar.png \e - -end-titleset \e - \e - -vmgm \e - -titles "Season One" "Season Two" \e - -background bg.jpg \e - -bgaudio foo.mp3 \e - -titles-fontsize 20 \e - -end-vmgm + $ tovid disc -static -out MY_DVD \e + \e + -titleset \e + -files 1.mpg 2.mpg 3.mpg \e + -titles "Title One" "Title Two" "Title Three" \e + -end-titleset \e + \e + -titleset \e + -files 4.mpg 5.mpg \e + -titles "Title Four" "Title Five" \e + -background foo.jpg \e + -showcase bar.png \e + -end-titleset \e + \e + -vmgm \e + -titles "Season One" "Season Two" \e + -background bg.jpg \e + -bgaudio foo.mp3 \e + -titles-fontsize 20 \e + -end-vmgm .fi @@ -285,42 +367,44 @@ Example of a single slideshow with an animated menu with transitions: .nf - $ tovid disc -menu-title "Autumn in Toronto" -slides images/*.jpg \e - -menu-slide-total 20 -slide-transition crossfade -bgaudio slideshow.wav \e - -out myslideshow + $ tovid disc -menu-title "Autumn in Toronto" -slides images/*.jpg \e + -menu-slide-total 20 -slide-transition crossfade -bgaudio slideshow.wav \e + -out myslideshow .fi + .P Example of multiple slideshows on one menu: .nf - $ tovid disc -menu-title "Autumn in Toronto" \e - -slides photos/september/*.jpg \e - -slides photos/october/*.jpg \e - -slides photos/november/*.jpg \e - -tile3x1 -rotate -5 5 -5 -align center \e - -bgaudio background.wav \e - -out myslideshow + $ tovid disc -menu-title "Autumn in Toronto" \e + -slides photos/september/*.jpg \e + -slides photos/october/*.jpg \e + -slides photos/november/*.jpg \e + -tile3x1 -rotate -5 5 -5 -align center \e + -bgaudio background.wav \e + -out myslideshow .fi + .P Example of mixed videos and slideshows: .nf - $ tovid disc -menu-title "Autumn in Toronto" \e - -files fall_fair.mov \e - -slides photos/september/*.jpg \e - -files harvest.mpg \e - -slides photos/october/*.jpg \e - -titles "Fall Fair" "September" "Harvest" "October" \e - -background autumn.png \e - -bgaudio bg.mp3 \e - -out myslideshow + $ tovid disc -menu-title "Autumn in Toronto" \e + -files fall_fair.mov \e + -slides photos/september/*.jpg \e + -files harvest.mpg \e + -slides photos/october/*.jpg \e + -titles "Fall Fair" "September" "Harvest" "October" \e + -background autumn.png \e + -bgaudio bg.mp3 \e + -out myslideshow .fi .P -See the other slideshow options in the SLIDESHOWS options section. +See the other slideshow options in the Slideshows options section. .P \fBEncoding Options\fR @@ -336,16 +420,47 @@ \fB\-vbitrate\fR, \fB\-quality\fR, \fB\-safe\fR, \fB\-crop\fR, \fB\-filters\fR, \fB\-abitrate\fR, \fB\-priority\fR, \fB\-deinterlace\fR, \fB\-progressive\fR, \fB\-interlaced\fR, \fB\-interlaced_bf\fR, \fB\-type\fR, \fB\-fit\fR, \fB\-discsize\fR, - \fB\-parallel\fR, \fB\-mkvsub\fR, \fB\-autosubs\fR, \fB\-subtitles\fR, \fB\-update\fR, \e + \fB\-parallel\fR, \fB\-mkvsub\fR, \fB\-autosubs\fR, \fB\-subtitles\fR, \fB\-update\fR, \fB\-mplayeropts\fR, \fB\-audiotrack\fR, \fB\-downmix\fR, \fB\-ffmpeg\fR, \fB\-nofifo\fR, \fB\-from\-gui\fR, \fB\-slice\fR, \fB\-quiet\fR, \fB\-fake\fR, \fB\-keepfiles\fR -.SS Options +.SS General Options + .TP \fB\-keep\-files\fR, \fB\-keepfiles\fR Keep all intermediate/temporary files (helps with debugging) .TP +\fB\-no\-ask\fR | \fB\-noask\fR +Skip all interactive questions. No preview, automatic re\-encoding with +tovid if needed, no interactive option to use background video for bgaudio. +.TP +\fB\-no\-warn\fR, \fB\-nowarn\fR +Don't pause after outputting warning or info messages +.TP +\fB\-jobs\fR +By default, \fBtovid disc\fR starts a parallel job for each processor +detected. With this option you can manually set the number of jobs. For +example if you have a computer with 2 CPUs you can set "\-jobs 1" to keep +one processor free for other things. At present this applies to the time +consuming imagemagick loops: you will notice a substantial speedup now if +you have a multi\-cpu system. +.TP +\fB\-grid\fR +Show a second preview image with a grid and numbers that will help in finding +coordinates for options that might use them, like \fB\-text\-start\fR +.TP +\fB\-no\-confirm\-backup\fR +This option is for when your DVD contains images for a slideshow. +Slideshows are an experimental (but well tested) feature. Todisc is +unlikely to overwrite your personal files, but you should take precautions +and backup your images, as you would with any beta software. Todisc +will prompt you to backup your files normally. If you have already backed +up your images, use this option to disable the prompt. + +==Options== + +.TP \fB\-ntsc\fR 720x480 output, compatible with NTSC standard (default) .TP @@ -362,21 +477,31 @@ \fB\-no\-menu | \-nomenu\fR With this option todisc will just create a DVD file system, ready for burning, with NO MENU, just the supplied video files. These do not need -to be compliant, as non\-compliant files will be encoded as usual. Each -video will be a chapter unless \fB\-chapters\fR OPTION is passed. The -\fB\-chapters\fR option is a number indicating the chapter interval in -minutes, or a HH:MM:SS string indicating chapter points. See \fB\-chapters\fR +to be compliant, as non\-compliant files will be encoded as usual. The +\fB\-out\fR option is not required. Each video will be a chapter unless +\fB\-chapters\fR OPTION is passed. The \fB\-chapters\fR option is a number +indicating the chapter interval in minutes, or a HH:MM:SS string +indicating chapter points. See \fB\-chapters\fR +.TP +\fB\-encode\-only\fR +This option was originally meant for the GUI, to allow it to be used for +just encoding rather than making a DVD structure. But it works well from +the command line as well as it has the added advantage that you can input +a list of files. Remember any makempg ('tovid mpg') options you use will +be passed on to the makempg script when encoding. .SS Menu style + .TP \fB\-showcase\fR IMAGE|VIDEO If used without an argument, use showcase style without a central thumb. This is a different arrangement of images for the menu: small thumbnails go at left (and right) side of screen, with a larger image in the centre. Maximum of 10 videos. If the provided argument is a video file, the -central thumb will be animated. Only 4:3 or 16:9 videos and images are -accepted for the showcase file: if not one of these todisc will assume it -is the same ratio as the videos in the titleset. +central thumb will be animated (regardless of whether \fB\-static\fR is part +of the command line). Only 4:3 or 16:9 videos and images are accepted for +for the showcase file: if not one of these todisc will assume it is the +aspect ratio as the videos in the titleset. .TP \fB\-textmenu\fR, \fB\-text\-menu\fR NUM If used without an argument, create a textmenu out of the supplied titles @@ -384,9 +509,9 @@ i.e. giving 4 titles and using "\-textmenu 2" would make 2 columns of 2 titles. The default is to put all titles up to 13 in the first column before starting a second column. Maximum: 2 columns and 26 titles. -Note that column 2 titles are aligned to the right. -If no video files for either \fB\-background\fR or \fB\-showcase\fR are supplied, -the menu will be static. +Note that column 2 titles are justified to the left unless you add +\fB\-edge\-justify\fR to the command line. The menu will be static if no video +files are supplied with either \fB\-background\fR or \fB\-showcase\fR options. .TP \fB\-quick\-menu\fR If you are using ffmpeg 0.8 or newer you can use this option. This will @@ -397,21 +522,22 @@ text\-menu style of menu, with no video thumbs, and a central showcase IMAGE(static) | VIDEO(animated). (i) see \fB\-bg\-color\fR if you are not using a \fB\-background\fR and want to -change the default black ) -(ii) Note: todisc will still work with vhooks if you have an old ffmpeg with -vhooks compiled in. +change the default. (default is dark blue for \-quick\-menu arrangements). ) +(ii) Note: todisc will still work with 'vhooks' if you have an old ffmpeg +with vhooks compiled in. Specifying the IMAGE|VIDEO argument to \fB\-showcase\fR is mandatory for this style of menu, unless used in conjunction with \fB\-switched\-menus\fR in which case the videos passed with \fB\-files\fR automatically become the -showcase videos. If this is used in combination with \fB\-switched\-menus\fR -it can really speed up an otherwise time consuming process. +showcase videos. If \fB\-quick\-menu\fR is used in combination with +\fB\-switched\-menus\fR it really speeds up an otherwise time consuming process. Example: .nf - -quick-menu -showcase /home/robert/showcase.mpg + -quick-menu -showcase /home/grepper/showcase.mpg .fi + See \fB\-switched\-menus\fR for example of making switched menus with \fB\-quick\-menu\fR @@ -420,7 +546,8 @@ The color to use for the menu background. (default: ntsc\-safe black) Note: use a color a great deal darker than you want, as it appears quite a bit lighter in the video version. You can use hexadecimal ('#ffac5f') -or named colors notation. +notation or named colors ('Lime'). convert \-list color will show them. +See colors (http://www.imagemagick.org/script/color.php) for more details. .TP \fB\-submenu\-bg\-color\fR, \fB\-submenu\-bg\-colour\fR The color to use as background for the submenu(s). @@ -432,7 +559,7 @@ a 'moving' menu, in spite of the static buttons. This option also does double duty for the \fB\-switched\-menus\fR option, and will create static "switched" images. -See also \fB\-switched\-menu\fR +See also \fB\-switched\-menus\fR .TP \fB\-background\fR IMAGE|VIDEO Menu background. This can be a image file or an video file. If it is a @@ -448,25 +575,26 @@ \fB\-menu\-title\fR Title for the root menu \- may be longer than thumbnail labels Also if you use \en in the title, you can use multi line titles, but you -would need to adjust \fB\-menu\-fontsize\fR to something smaller than default +would need to adjust \fB\-title\-fontsize\fR to something smaller than default for example: .nf - $ tovid disc ... -menu-title "A\enMultilined\enTitle" -menu-fontsize 24 + $ tovid disc ... -menu-title "A\enMultilined\enTitle" -title-fontsize 24 .fi + .TP -\fB\-menu\-font\fR FONT +\fB\-title\-font\fR, \fB\-menu\-font\fR FONT Font to use for titles, either by ImageMagick font name (ex., "Arial") or explicit pathname (ex., "/full/path/to/arial.ttf"). To see a complete list of acceptable ImageMagick font names, run \fBconvert \-list type\fR, and refer to the leftmost column .TP -\fB\-menu\-fontsize\fR +\fB\-title\-fontsize\fR, \fB\-menu\-fontsize\fR Font size for main menu \- best to \-preview if you use this .TP \fB\-submenu\-font\fR -Font to use for the sub\-menu main titles. See \fB\-menu\-font\fR +Font to use for the sub\-menu main titles. See \fB\-title\-font\fR .TP \fB\-submenu\-fontsize\fR Font size for the sub\-menu main titles @@ -525,7 +653,7 @@ \fB\-skip\-vmgm\fR Start DVD from the first titleset instead of the VMGM ( root ) menu. .TP -\fB\-switched\-menus\fR +\fB\-switched\-menus\fR, \fB\-switched\-menu\fR This will make a "switched menu": there will be a central image where the showcase image would go, and text menu titles along the menu edge where textmenu titles go. As you select a video title with the down or up arrow @@ -543,11 +671,19 @@ Example for using with \fB\-quick\-menu\fR: .nf - -switched-menus -quick-menu + -switched-menus -quick-menu .fi + .SS Thumbnail style + +.TP +\fB\-titles\-font\fR FONT +Display thumbnail or textmenu titles in the given font +.TP +\fB\-titles\-fontsize\fR POINTS +Font size to use for thumbnail or textmenu titles .TP \fB\-thumb\-shape\fR normal|oval|vignette|plectrum|arch|spiral|blob|star|flare @@ -573,14 +709,9 @@ \fB\-3d\-thumbs\fR, \fB\-3dthumbs\fR This will give an illusion of 3D to the thumbnails: dynamic lighting on rounded thumbs, and a raised effect on rectangular thumbs. Try it ! -.TP -\fB\-titles\-font\fR FONT -Display thumbnail or textmenu titles in the given font -.TP -\fB\-titles\-fontsize\fR POINTS -Font size to use for thumbnail or textmenu titles .SS Slideshows + .TP \fB\-slides\fR IMAGES Use \fB\-slides\fR IMAGES to pass in images for a slideshow. The default is @@ -682,7 +813,7 @@ be static. If you used with a mixed menu of videos and slideshows, then the video thumbs WILL be animated, so you may wish to use \-static or \-textmenu with the option in that case. If you want to use the -**\-switched\-menus option with a mixed menu leave this option out. +**\-switched\-menus option with a mixed menu leave this option out. .TP \fB\-background\-slideshow\fR, \fB\-bg\-slideshow\fR @@ -697,6 +828,7 @@ and backup your images, as you would with any beta software. Todisc will prompt you to backup your files normally. If you have already backed up your images, use this option to disable the prompt. +See \fBGeneral Options\fR .TP \fB\-use\-dvd\-slideshow\fR CONFIG (FILE) @@ -709,6 +841,7 @@ override many of the above options for slideshows. .SS Burning the disc + .TP \fB\-burn\fR Prompt to burn the DVD directory on completion. @@ -721,8 +854,10 @@ \fB\-speed\fR The speed to use for burning the disc. -.SS ADVANCED USAGE +.SS Advanced usage + .SS Options + .TP \fB\-menu\-length\fR The desired animated main menu length in seconds @@ -733,13 +868,13 @@ The default is to use 10 seconds of audio for static menus. .TP \fB\-submenu\-stroke\fR COLOR -The color for the sub\-menu font outline (stroke) +The color for the sub\-menu font shadow .TP \fB\-submenu\-title\-color\fR, \fB\-submenu\-title\-colour\fR The fill color used for sub\-menu title fonts .TP \fB\-submenu\-titles\fR -You can supple a list of titles here for sub\-menus without the length +You can supply a list of titles here for sub\-menus without the length restrictions found in thumb titles. Must equal number of videos .TP \fB\-chapters\fR [ NUM | CHAPTER POINTS in HH:MM:SS ] @@ -776,26 +911,29 @@ Example for passing just number of chapters ( 4 videos ): .nf - -chapters 5 2 4 8 + -chapters 5 2 4 8 .fi + Example of passing chapter points ( 4 videos ): .nf - -chapters 00:00:00,00:05:34.41,00:12:54,00:20:45 \e - 00:00:00,00:04:25.623,00:09:12,00:15:51 \e - 00:00:00,00:05:10,00:13:41,00:18:13.033 \e - 00:00:00,00:15:23.342,00:26:42.523 + -chapters 00:00:00,00:05:34.41,00:12:54,00:20:45 \e + 00:00:00,00:04:25.623,00:09:12,00:15:51 \e + 00:00:00,00:05:10,00:13:41,00:18:13.033 \e + 00:00:00,00:15:23.342,00:26:42.523 .fi + Example of passing grouped chapters using the '+' separator: .nf - -chapters 00:00:00,00:05:34.41,00:12:54,00:20:45+00:04:23,00:09:35 \e - 00:00:00... etc. + -chapters 00:00:00,00:05:34.41,00:12:54,00:20:45+00:04:23,00:09:35 \e + 00:00:00... etc. .fi + .TP \fB\-chapter\-titles\fR LIST If you are using submenus, you can pass a list of titles for the @@ -819,7 +957,7 @@ The color for the chapters font. .TP \fB\-chapter\-stroke\fR COLOR -The color for the chapters font outline (stroke) +The color for the chapters font shadow .TP \fB\-seek\fR NUM | "NUM1 NUM2 NUM3 . . ." @@ -859,43 +997,27 @@ video. Example: .nf - -group 2 2.mpg 3.mpg 4.mpg + -group 2 2.mpg 3.mpg 4.mpg .fi + will group these 3 videos with the 2nd video given with \fB\-files\fR, so that they will play sequentially as one title. Only one thumbnail and/or title will appear on the menu for the group: it will be made from the 1st video in the group. In the above example if you passed: .nf - -files foo.mpg bar.mpg baz.mpg -group 2 2.mpg 3.mpg 4.mpg + -files foo.mpg bar.mpg baz.mpg -group 2 2.mpg 3.mpg 4.mpg .fi + then the group will consist of bar.mpg 2.mpg, 3.mpg and 4.mpg, and only the title and/or thumbnail for bar.mpg will appear in the menu. You can use \fB\-group\fR more than once for multiple groups. Be sure to quote video filenames if they contain spaces. -.TP -\fB\-jobs\fR -By default, \fBtovid disc\fR starts a parallel job for each processor -detected. With this option you can manually set the number of jobs. For -example if you have a computer with 2 CPUs you can set "\-jobs 1" to keep -one processor free for other things. At present this applies to the time -consuming imagemagick loops: you will notice a substantial speedup now if -you have a multi\-cpu system. -.TP -\fB\-no\-ask\fR, \fB\-noask\fR -Skip all interactive questions. No preview, automatic re\-encoding with -tovid if needed, no interactive option to use background video for bgaudio. -.TP -\fB\-no\-warn\fR, \fB\-nowarn\fR -Don't pause after outputting warning or info messages -.TP -\fB\-grid\fR -Show a second preview image with a grid and numbers that will help in finding -coordinates for options that might use them, like \fB\-text\-start\fR .SS Menu Style + .TP \fB\-menu\-title\-geo\fR north|south|east|west|center [south] The position of the menu title. You may need to use \-align as well if @@ -907,11 +1029,11 @@ may need to use \-align as well if you don't want your title covering other parts of your menu. See \fB\-align\fR .TP -\fB\-button\-style\fR rect|text|line|text\-rect +\fB\-button\-style\fR line|rect|text|text\-rect [line] The style of button that you will see when you play the DVD. -"rect" draws a rectangle around the thumb when you select it -in the DVD player. "text" highlights the video title text, "line" -underlines the title, and "text\-rect" draws a rectangle around the title +"line" style underlines the title, "rect" draws a rectangle around the +thumb when you select it in the DVD player, "text" highlights the video +title text, and "text\-rect" draws a rectangle around the title text. .TP \fB\-title\-color\fR, \fB\-title\-colour\fR COLOR @@ -920,12 +1042,27 @@ http://www.imagemagick.org/script/color.php .TP \fB\-title\-stroke\fR COLOR -Outline color for the main menu's title font. Use "none" for transparent -outline (see title\-color) +Shadow color for the main menu's title font. Use "none" for transparent +outline (see title\-color). Note: this is not a \-stroke in the sense that +imagemagick uses the term, but a shadow (the font is drawn twice). To get +a true imagemagick stroke see \fB\-title\-font\-deco\fR +.TP +\fB\-title\-font\-deco\fR, \fB\-title\-fontdeco\fR "IMAGEMAGICK STRING" +Sets the font decoration method to FONTDECORATION. It is used by the 'convert' +ImageMagick command to draw the menu text. You can add colored text +outlines, gradient fills, and many others. See \fBUsage notes\fR .TP \fB\-titles\-stroke\fR COLOR -Outline color for the thumb or textmenu video titles font. Use "none" for -transparent outline (see \fB\-titles\-color\fR). +Shadow color for the thumb or textmenu video titles font. Use "none" for +transparent outline (see \fB\-titles\-color\fR). Note: this is not a \-stroke +in the sense that imagemagick uses the term, but a shadow +(the font is drawn twice). To get a true imagemagick stroke, +see \fB\-titles\-font\-deco\fR +.TP +\fB\-titles\-font\-deco\fR, \fB\-titles\-fontdeco\fR "IMAGEMAGICK STRING" +Sets the font decoration method to FONTDECORATION. It is used by the 'convert' +ImageMagick command to draw the menu text. You can add colored text +outlines, gradient fills, and others. See \fBUsage notes\fR for more info. .TP \fB\-highlight\-color\fR, \fB\-highlight\-colour\fR Color to use for the menu buttons that your DVD remote uses to navigate. @@ -968,7 +1105,8 @@ At present it must be a DVD compatible video at the correct resolution etc. Only 4:3 aspect is supported: 16:9 will give unexpected results. -.SS Menu Style options specific to showcase and textmenu arrangements +.SS Style options specific to showcase/textmenu arrangements + .TP \fB\-text\-start\fR N This option is for \fB\-textmenu\fR menus. The titles will start at the Nth @@ -984,7 +1122,8 @@ this will not turn a portait image into a landscape image! .TP \fB\-showcase\-geo\fR GEOMETRY -The position of the showcase image. ( XxY position ) +The position of the showcase image. ( +X+Y position ) +For example: \fB\-showcase\-geo\fR +300+200 .TP \fB\-wave\fR default|GEOMETRY Wave effect for showcase image|video. Alters thumbs along a sine wave using @@ -1025,12 +1164,14 @@ rounded thumbs, and a raised effect on rectangular thumbs. Try it ! .SS Thumbnail Style + .TP -\fB\-user\-thumbs\fR IMAGE +\fB\-user\-thumbs\fR IMAGE(S) Supply your own images for menu buttons, rather than relying on todisc to generate them from the video. They must be the same aspect ratio as the videos in the titleset (4:3 or 16:9), as todisc will resize them without -checking and cropping. +checking and cropping. There must be on image for each thumb that will be +displayed on the menu (ie. one thumb for each video in a titleset). .TP \fB\-opacity\fR [0\-100] (default 100) Opacity of thumbnail videos as a percentage (no percent sign). @@ -1048,10 +1189,27 @@ values between 0.1 and 2.0. This option has no effect on \fB\-3d\-showcase\fR. See \fB\-thumb\-blur\fR for more info. .TP -\fB\-align\fR north|south -This will align thumbs/titles north or south. +\fB\-align\fR DIRECTION +This will align thumbs/titles in DIRECTION, which is a compass direction +as used by imagemagick: ie. north|south|east|west|northeast|northwest etc. If \fB\-align\fR south then menu title will align north, unless you manually set one or both of \fB\-menu\-title\-geo\fR or \fB\-menu\-title\-offset\fR. +Only \fB\-align\fR north|south|center has any effect on showcase with thumb, +or with the default montage arrangement of central thumbs. The most +apparent changes with be with textmenu, though with 2 column arrangements +only the north* and south* changes will show an effect. + +Diagram: +.TP + . northwest north northeast . +.TP + . . +.TP + . west center east . +.TP + . . +.TP + . southwest south souteast . .TP \fB\-thumb\-mist\fR [COLOR] Use a mist behind thumbnails. The optional argument is the color of the @@ -1099,12 +1257,14 @@ showcase template the titles will remain the same size. Example: .nf - -rotate-thumbs -10 10 -10 10 -10 (for 5 files) + -rotate-thumbs -10 10 -10 10 -10 (for 5 files) .fi + **Note: this option will not turn a portrait image into a landscape image! .SS Dvdauthor options + .TP \fB\-loop\fR PAUSE Pause in seconds at end of menu. Use "inf" if you wish indefinite pause. @@ -1118,7 +1278,7 @@ the \fB\-vmgm\fR ... \fB\-end\-vmgm\fR options to allow playing ALL titlesets. (If you want also to have a playall button in each titleset you could use this option between each \fB\-titleset\fR ... \fB\-end\-titleset\fR option or put -it outside of the vmgm and titlset options as a general option. +it outside of the vmgm and titlset options as a global option. .TP \fB\-videos\-are\-chapters\fR A button will be made on the main menu for each video, which you can use as @@ -1153,9 +1313,10 @@ xml file. It will affect all videos in the titleset. Example: .nf - -aspect 16:9 + -aspect 16:9 .fi + .TP \fB\-widescreen\fR nopanscan|noletterbox [nopanscan] This will output a <video widescreen=nopanscan /> tag (for example) @@ -1164,9 +1325,10 @@ Example: .nf - -aspect 16:9 -widescreen + -aspect 16:9 -widescreen .fi + .TP \fB\-quick\-nav\fR This option will allow navigation of a menu with more than one titleset by @@ -1194,13 +1356,42 @@ for the last video in the group. If providing a list of values they must equal the number of grouped videos. +.SS Usage notes + +.P +The argument given to various *\-font options that set the font to use must be +one of the fonts listed by the command 'convert \-list type'. Please note that +many of your installed fonts may not be available; if you want to maximize the +number of fonts available to todisc, download and run +Anthony Thyssen's (http://www.cit.gu.edu.au/~anthony/anthony.html) +imagick_type_gen (http://www.imagemagick.org/Usage/scripts/imagick_type_gen) +script and run it like this: +imagick_type_gen > ~/.magick/type.xml. +If that doesn't work, try imagick_type_gen > ~/.magick/type.mgk. + +.P +Or you can specify a ttf font file directly to the *\-font options if you don't +want to install fonts to ImageMagick. + +.P +The *\-stroke options in todisc are not a stroke in the sense that ImageMagick +uses the term, but rather a font shadow (the text is drawn twice) To get a +truer Imagemagick \-stroke try something like: +\-title\-font\-deco "\-stroke black" (or \-titles\-font\-deco "\-stroke black"). The +\fB\-fontdeco\fR option is quite flexible and takes a lot of ImageMagick's +\fIconvert\fR options. Please refer to the tovid +wiki (http://tovid.wikia.com/wiki/Making_a_DVD_with_text_menus) and Anthony +Thyssen's guide [http://www.imagemagick.org/Usage] for further explanation and examples. + .SH Command:mpg + .P \fBtovid mpg\fR converts arbitrary video files into (S)VCD/DVD\-compliant MPEG format, suitable for burning to CD/DVD\-R for playback on a standalone DVD player. .SS Usage + .P \fBtovid mpg\fR [\fIOPTIONS\fR] \fB\-in\fR \fIINFILE\fR \fB\-out\fR \fIOUTPREFIX\fR @@ -1226,6 +1417,7 @@ Convert 'foo.avi' to PAL VCD format, saving to 'foo_encoded.mpg'. .SS Basic options + .TP \fB\-v\fR, \fB\-version\fR Print tovid version number only, then exit. @@ -1245,6 +1437,7 @@ \fB\-subtitles\fR or \fB\-filters\fR. .SS Television standards + .TP \fB\-ntsc\fR NTSC format video (USA, Americas) (default) @@ -1256,6 +1449,7 @@ PAL format video (Europe and others) .SS Formats + .P Standard formats, should be playable in most DVD players: @@ -1302,7 +1496,9 @@ format. .SS Advanced options + .SS Aspect ratios + .P tovid automatically determines aspect ratio of the input video by playing it in mplayer. If your video plays with correct aspect in mplayer, you should not @@ -1332,6 +1528,7 @@ for a widescreen monitor or TV. .SS Video stream options + .TP \fB\-quality\fR \fINUM\fR (default 6) Desired output quality, on a scale of 1 to 10, with 10 giving the best @@ -1438,6 +1635,7 @@ \fB\-bdvd\fR), for optimal viewing on a widescreen monitor or TV. .SS Audio stream options + .TP \fB\-normalize\fR Analyze the audio stream and then normalize the volume of the audio. @@ -1479,6 +1677,7 @@ will revert to the default behavior of using the original channels. .SS Other options + .TP \fB\-config\fR \fIFILE\fR Read configuration from \fIFILE\fR, containing 'tovid' alone on the first @@ -1535,7 +1734,7 @@ seconds. .TP -\fB\-mplayeropts\fR \fB"\fR\fIOPTIONS\fR\fB"\fR +\fB\-mplayeropts\fR \fIOPTIONS\fR Append \fIOPTIONS\fR to the mplayer command run during video encoding. Use this if you want to add specific video filters (documented in the mplayer manual page). Overriding some options will cause encoding to fail, so use @@ -1570,12 +1769,14 @@ answers. .SH Command:id + .P \fBtovid id\fR identifies each multimedia video file in a list, and reports its compliance with video disc standards such as VCD, SVCD, and DVD. .SS Usage + .P \fBtovid id\fR [\fIOPTIONS\fR] \fIVIDEO_FILE(s)\fR @@ -1588,6 +1789,7 @@ tovid id \-tabluar videos/*.mpg .SS Options + .TP \fB\-terse\fR Print raw video characteristics, no formatting. Helpful when @@ -1614,6 +1816,10 @@ when identifying multiple video files. .TP +\fB\-keepfiles\fR +Keep temporary directory for debugging. + +.TP \fB\-isformat\fR [\fIpal\-dvd\fR|\fIntsc\-dvd\fR] (same syntax for vcd and svcd) Check \fIVIDEO_FILE\fR for compliance with the given disc format. If \fIVIDEO_FILE\fR matches the given format, then \fBtovid id\fR reports "true" @@ -1622,6 +1828,7 @@ and pal/ntsc. .SS Examples + .TP tovid id \-verbose homevideo.avi Report everything mplayer, ffmpeg, and transcode can determine about @@ -1631,390 +1838,19 @@ tovid id \-isformat dvd homevideo.mpg Check to see if homevideo.mpg is compliant with the DVD standard. -.SH Command:menu -.P -\fBtovid menu\fR generates textual (S)VCD\- or DVD\-compliant MPEG videos for use -as navigational menus, given a list of text strings to use for title names. You -can customize the menu by providing an optional background image or audio clip, -or by using custom font and font color. - -.SS Usage -.P -\fBtovid menu\fR [\fIOPTIONS\fR] \fITITLES\fR \fB\-out\fR \fIOUT_PREFIX\fR - -.P -For example: - -.TP -tovid menu "Season One" "Season Two" "Featurettes" \-out MainMenu - -.SS Options -.TP -\fB\-ntsc\fR (default) -Generate an NTSC\-format menu -.TP -\fB\-ntscfilm\fR -Generate an NTSC\-format menu (24000/1001fps) -.TP -\fB\-pal\fR -Generate a PAL\-format menu -.TP -\fB\-dvd\fR (default) -Generate a DVD\-format menu, with highlighted text included -as a multiplexed subtitle stream. -.TP -\fB\-vcd\fR -.TP -\fB\-svcd\fR -Generate a VCD/SVCD menu; each menu option will have a -number associated with it. You can have up to nine menu -options per menu. - -.P -Menu background/audio options: - -.TP -\fB\-background\fR \fIIMAGE\fR -Use \fIIMAGE\fR (in most any graphic format) as a background. If image is not -the correct aspect ratio (4:3), it will be scaled and/or cropped, -depending on the \fB\-crop\fR and \fB\-scale\fR options. If no background is -supplied, a default background will be created. - -.TP -\fB\-crop\fR (default) -If provided background image is not 4:3 aspect ratio, crop edges -to make it so. Image will be scaled up if it is too small. Cropping -keeps the center area of image. If you want to do cropping/scaling -yourself in another program, provide an image of 768x576 pixels. - -.TP -\fB\-scale\fR -If provided background image is not 4:3 aspect ratio, scale/stretch -it to make it fit. May cause visible distortion! - -.TP -\fB\-audio\fR \fIAUDIOFILE\fR -Use \fIAUDIOFILE\fR (in most any audio format) for background music. The -menu will play for long enough to hear the whole audio clip. If -one is not provided, 4 seconds of silence will be used. - -.TP -\fB\-length\fR \fINUM\fR -Make the menu \fINUM\fR seconds long. Useful for menus with \fB\-audio\fR: -if you don't want the entire \fIAUDIOFILE\fR in the menu, then you can trim -the length of the menu with \fB\-length\fR. - -.P -Menu text options: - -.TP -\fB\-menu\-title\fR \fB"\fR\fIMENU TITLE TEXT\fR\fB"\fR -Add \fIMENU TITLE TEXT\fR as a title/header to the menu. - -.TP -\fB\-font\fR \fIFONTNAME\fR (default Helvetica) -Use \fIFONTNAME\fR for the menu text. Run 'convert \-list type' to see a -list of the fonts that you can use; choose a font name from the -leftmost column that is displayed. Or you can specify a ttf font file instead. -E.g., '\-font /path/to/myfont.ttf'. - -.TP -\fB\-fontsize\fR \fINUM\fR (default 24) -Sets the size for the font to \fINUM\fR pixels. - -.TP -\fB\-menu\-title\-fontsize\fR \fINUM\fR (default \fB\-fontsize\fR + 8) -Sets the size of the menu title. - -.TP -\fB\-fontdeco\fR \fB'\fR\fIFONTDECORATION\fR\fB'\fR -Sets the font decoration method to \fIFONTDECORATION\fR. It is used by the -'convert' ImageMagick command to draw the menu text. You can add colored -text outlines, gradient fills, and many others. See \fBUsage notes\fR. - -.TP -\fB\-align\fR {\fBleft\fR|\fBcenter\fR|\fBmiddle\fR|\fBright\fR} -Align the text at the top left, top center, very middle, or top right -side of the screen. You may also substitute any "gravity" keyword -allowed by ImageMagick (north|south|east|west|northeast|southwest|...). - -.TP -\fB\-textcolor\fR {\fB#\fR\fIRRGGBB\fR|\fB#\fR\fIRGB\fR|\fICOLORNAME\fR} -Use specified color for menu text. #\fIRRGGBB\fR and #\fIRGB\fR are -hexadecimal triplets (e.g., #FF8035). \fICOLORNAME\fR may be any of -several hundred named colors; run 'convert \-list color' to see them. -White (#FFF) is the default color. - -.P -DVD\-only options: - -.TP -\fB\-button\fR \fIBUTTON\fR (default '>') -Specify the button used for menu selection. Specify either a _single_ -character or one of the shortcuts: -.RS -.IP \(bu 3 -\fBplay\fR \-\- Use a button shaped like 'Play' on many A/V electronics: -a triangle pointing to the right. (uses the font Webdings) -.IP \(bu 3 -\fBmovie\fR \-\- Use a button shaped like an old movie projector. -(uses the font Webdings) -.IP \(bu 3 -\fButf8\fR \-\- Use your own non\-keyboard character as a button. Provide -only the four hex digits: eg '\-button utf8 00b7'. Beware that -ImageMagick's utf8 characters aren't the same as those drawn in -character browsers like gucharmap. -.RE - -.TP -\fB\-highlightcolor\fR {\fB#\fR\fIRRGGBB\fR|\fB#\fR\fIRGB\fR|\fICOLORNAME\fR} -Use the specified color for button highlighting. Yellow (#FF0) is the -default color. - -.TP -\fB\-selectcolor\fR {\fB#\fR\fIRRGGBB\fR|\fB#\fR\fIRGB\fR|\fICOLORNAME\fR} -Use the specified color for button selections (when a menu item is played -or activated). Red (#F00) is the default color. - -.TP -\fB\-button\-outline\fR {\fB#\fR\fIRRGGBB\fR|\fB#\fR\fIRGB\fR|\fICOLORNAME\fR} -Outline buttons with the specified color. 'none' is the default. - -.TP -\fB\-button\-font\fR \fIFONTNAME\fR -Specify a differnt font to use for the buttons. By default, the button -font will be inherited from the title font (see \fB\-font\fR). Use this -option to use a different font for the buttons. The button font size is -inherited from \fB\-fontsize\fR and cannot be changed. - -.P -Other options: - -.TP -\fB\-debug\fR -Print extra debugging information to the log file. Useful in -diagnosing problems if they occur. This option also leaves -the log file (with a .log extension) in the directory after -encoding finishes as well as all the temporary files created. - -.TP -\fB\-nosafearea\fR -Do not attempt to put text inside a TV\-safe viewing area. Most -television sets cut off about 10% of the image border, so the script -automatically leaves a substantial margin. This option turns that -behavior off, leaving only a tiny margin. Use at your own risk. - -.TP -\fB\-overwrite\fR -Overwrite any existing output menu. - -.TP -\fB\-noask\fR -Don't ask interactive questions, and assume answers that will -continue making the menu until completion. - -.TP -\fB\-quiet\fR -Limit output to essential messages. - -.P -If the word "\fBback\fR" is given as an episode title, a "back" button for -returning to a higher\-level menu will be added at the end of the list -of titles. "\fBBack\fR" \fImust be the last title listed\fR. - -.SS Examples -.P -Make an NTSC VCD menu with white Helvetica text containing three centered -selections: Episode 1, Episode 2, and Episode 3. The finished menu will be -called Season\-1.mpg: - -.nf - tovid menu -ntsc -vcd \e - -align center -textcolor white -font "Helvetica" \e - "Episode 1" "Episode 2" "Episode 3" \e - -out "Season-1" -.fi - - -.P -Make an NTSC DVD menu with white Kirsty text containing three lower\-left -aligned selections: Episode 1, Episode 2, and Episode 3. Items under the cursor -will be highlighted a pale blue, and selected items will be a pale orange -(before going to the selected title). The finished menu will be called -Main\-menu.mpg: - -.nf - tovid menu -ntsc -dvd \e - -align southwest \e - -textcolor white \e - -highlightcolor "#5f65ff" \e - -selectcolor "#ffac5f" \e - -font "Kirsty" \e - "Episode 1" "Episode 2" "Episode 3" \e - -out "Main_menu" -.fi - - -.SS Usage notes -.P -The argument given to \fB\-font\fR must be one of the fonts listed -by the command 'convert \-list type'. Please note that many of -your installed fonts may not be available; if you want to maximize the -number of fonts available, download and run -Anthony Thyssen's (http://www.cit.gu.edu.au/~anthony/anthony.html) -imagick_type_gen.pl (http://www.cit.gu.edu.au/~anthony/software/imagick_type_gen.pl) -script and run it like this: -imagick_type_gen.pl > ~/.magick/type.xml. -If that doesn't work, try -imagick_type_gen.pl > ~/.magick/type.mgk. - -.P -Or you can specify a ttf font file directly to the \fB\-font\fR options if you -don't want to install fonts to ImageMagick. - -.P -The \fB\-fontdeco\fR option is quite flexible and takes a lot of ImageMagick's -\fIconvert\fR options. Please refer to the tovid -wiki (http://tovid.wikia.com/wiki/Making_a_DVD_with_text_menus) -and Anthony Thyssen's guide for further explanation and examples. - -.SH Command:xml -.P -\fBtovid xml\fR generates XML output describing an (S)VCD -or DVD file structure and navigation hierarchy in the format expected by -dvdauthor (http://dvdauthor.sourceforge.net/) or -vcdxbuild (http://www.vcdimager.org/). - -.SS Usage -.P -\fBtovid xml\fR [\fIOPTIONS\fR] \fIVIDEOS\fR \-out \fIOUTFILE\fR - -.P -For example: - -.nf - $ tovid xml -menu MainMenu.mpg \e - Season1.mpg Season2.mpg Featurettes.mpg \e - -out MyDisc -.fi - - -.SS Options -.TP -\fB\-dvd\fR (default) -Generate the XML for a DVD disc, to be used with dvdauthor or \fBtovid dvd\fR. -.TP -\fB\-vcd\fR -Generate the XML for a VCD disc, to be used with vcdxbuild or \fBtovid vcd\fR. -.TP -\fB\-svcd\fR -Generate the XML for an SVCD disc, to be used with vcdxbuild or \fBtovid vcd\fR. -.TP -\fB\-overwrite\fR -Overwrite any existing output files. -.TP -\fB\-quiet\fR -Limit output to essential messages. - -.P -\fIVIDEOS\fR may be any of the following: - -.TP -\fI<file list>\fR -List of one or more video files to include, separated by spaces. At -minimum, a DVD must have one video file. You can use shell wildcards -(i.e., "*.mpg") to include multiple files easily. Put filenames in -quotes if they have spaces in them. - -.TP -\fB\-menu\fR \fIVIDEO\fR \fI<file list>\fR -Use video file \fIVIDEO\fR as a menu from which you can jump to each of -the listed video files. If you have multiple menus, include a -top menu so they are reachable. - -.TP -\fB\-slides\fR \fI<file list>\fR -Create a slide\-show of still images - -.P -DVD\-only options - -.TP -\fB\-group\fR \fI<file list>\fR \fB\-endgroup\fR -(DVD only) List of video files to include as one single title. This is useful -if you have split a movie into several video files. - -.TP -\fB\-topmenu\fR \fIVIDEO\fR [\fB\-menu\fR \fIVIDEO\fR \fI<file list>\fR] [\fB\-menu\fR \fIVIDEO\fR \fI<file list>\fR]... -(DVD only) Use video file \fIVIDEO\fR for the top\-level (VMGM) menu. The -top menu will jump to each of the subsequent [\-menu...] videos listed. -Use this only if you have multiple sub\-menus to jump to. You can only -have one top menu. - -.TP -\fB\-titlesets\fR -(DVD only) Forces the creation of a separate titleset per title. This -is useful if the titles of a DVD have different video formats, -e.g. PAL + NTSC or 4:3 + 16:9. If used with menus, there must be a -\fB\-topmenu\fR option that specifies a menu file with an entry for each of the -titlesets. - -.TP -\fB\-chapters\fR \fIINTERVAL\fR -(DVD only) Creates a chapter every \fIINTERVAL\fR minutes (default 5 minutes: -without \fB\-chapters\fR, each movie will be divided into 5\-minute chapters). -This option can be put at any position in a \fI<file list>\fR and is valid -for all subsequent titles until a new \fB\-chapters\fR option is encountered. -Using this option may take some time, since the duration of the video is -calculated. - -.TP -\fB\-nochapters\fR -(DVD only) Don't create chapters for the videos. - -.P -\fIOUT_PREFIX\fR is the file that will receive the resulting XML. - -.SS Usage notes -.P -The 'xml' command checks to make sure the video filenames you -give it exist, but it does not check whether they are valid for the -chosen disc format. MPEG videos of menus should have the specified -number of buttons for reaching each of the videos, and, if you're -using DVD, should be multiplexed with their corresponding subtitles -using spumux of the dvdauthor 0.6.0 package prior to -authoring using dvdauthor. If you use the 'tovid menu' -component to generate the menu, this should all be handled for you. - -.SS Examples -.TP -tovid xml \-dvd title\-1.mpg title\-2.mpg title\-3.mpg \-out My_DVD -Make a DVD without a menu. Title 1, 2, and 3 will play in sequence. - -.TP -tovid xml \-dvd \-group chapter\-1.mpg chapter\-2.mpg chapter\-3.mpg \-endgroup \-out My_DVD -Group the file chapter\-1|2|3.mpg into one title and make a DVD without a menu. - -.TP -tovid xml \-dvd \-menu main_menu.mpg \-chapters 3 movie\-1.mpg \-chapters 10 movie\-2.mpg \-out My_DVD -Make a DVD with a main menu that points to two movies, with movie\-1.mpg -divided into 3\-minute chapters, and movie\-2.mpg into 10\-minute chapters. - .SH Command:dvd + .P -\fBtovid dvd\fR takes a dvdauthor XML file (as generated by the \fBtovid xml\fR -command) and authors a DVD filesytem. This command can also burn a DVD disc -from either the XML file or from an existing DVD file\-system. +\fBtovid dvd\fR takes a DVD directory as generated by tovid with 'tovid disc' or +one of the GUI frontends like 'tovid gui' or 'tovid titlesets' and burns +it to appropriate media. This will also work if the DVD directory is +generated by the dvdauthor backend that tovid also uses. .P -To ensure that this script successfully executes, please run it from a -directory with plenty of free space. "Plenty" would be 10 GB for single\-layer -discs, and 20 GB for dual\-layer discs. Running this program may slow down your -other applications, due to intense disk activity. +Running this program may slow down your other applications, due to intense +disk activity. .SS Usage -.P -\fBtovid dvd\fR [\fIOPTIONS\fR] \fIFILE.xml\fR .P \fBtovid dvd\fR [\fIOPTIONS\fR] \fIDVD_DIR\fR @@ -2023,19 +1859,16 @@ For example: .TP -tovid dvd \-burn MyDisc.xml -.TP -tovid dvd \-burn /path/to/DVD/directory +tovid dvd /path/to/DVD/directory .SS Options -.TP -\fB\-author\fR -Author the DVD described by \fIFILE.xml\fR. Overwrites an existing -directory containing the dvdauthor output if already present. .TP \fB\-burn\fR Burn a DVD file\-system in \fIDVD_DIR\fR (must contain a VIDEO_TS folder). +This option is currently not necessary as the makedvd script ONLY burns +now that legacy scripts like makexml have been removed. Left for +compatibility only. .TP \fB\-eject\fR @@ -2068,147 +1901,39 @@ Don't ask interactive questions and assume answers that will continue execution. -.SS Examples -.TP -tovid dvd \-burn \-device /dev/dvdrw foo.xml -Author the dvd file\-system and burn to /dev/dvdrw. This will -automatically call dvdauthor to make the file\-system. \fB\-author\fR -is not explicitly needed. If there's an existing file\-system, it -will be burned. - -.TP -tovid dvd \-author foo.xml -Author the DVD file\-system and exit without burning. If the output -directory given in foo.xml already exists, then the contents are -removed before authoring. At this point, the DVD can be previewed -by calling \fI\fBxine\fR dvd:/path/to/output/directory\fR. - -.SH Command:vcd .P -\fBtovid vcd\fR takes an XML file (which may be generated by \fBtovid xml\fR) and -creates a cue/bin (S)VCD image. It can also burn (S)VCD discs. + After burning, the DVD can be previewed by calling: + \fI\fBxine\fR dvd:/path/to/output/directory\fR + or: + \fI\fBvlc\fR /path/to/output/directory\fR -.P -To ensure that this script successfully executes, please run it from a directory -with plenty of free space. "Plenty" would be about 1 GB. Running this program -may slow down your other applications, due to intense disk activity. +.SH Command:chapters -.SS Usage .P -\fBtovid vcd\fR [\fIOPTIONS\fR] \fIVCDIMAGER.xml\fR +\fBtovid chapters\fR will start a GUI using mplayer to set chapter points in a +video. If the video plays through and you want to add more chapters you can +press the play button again, but remember that new chapter points will be +appended (in correct sequential order). It will display the resulting chapter +points, and also output to a terminal (useful for scripts). As well it will +give the option of saving the chapters string to a text file. .P -For example: - -.TP -tovid vcd \-burn MyDisc.xml - -.SS Options -.TP -\fB\-overwrite\fR (default off \-\- nothing is overwritten) -Overwrite any existing cue/bin files matching \fIVCDIMAGER.xml\fR. Useful -if you modified the xml file and wish to re\-image or burn the new (S)VCD. - -.TP -\fB\-burn\fR (default off \-\- no images are burned) -Burn the (S)VCD described by \fIVCDIMAGER.xml\fR. - -.TP -\fB\-device\fR \fIDEVICE\fR (default /dev/cdrw) -Burn the disc image to \fIDEVICE\fR, the Linux device file\-system -name of your CD\-recorder. Common examples might be /dev/cdrw, -/dev/scd1, and /dev/hdc. - -.TP -\fB\-speed\fR \fINUM\fR (default 12) -Burn the disc at speed \fINUM\fR. - -.TP -\fB\-quiet\fR -Limit output to essential messages. +Note that the 'tovid gui' now features a similar widget when you press the +chapters button on the opening page. .SS Examples -.TP -tovid vcd \-burn \-device /dev/cdrw foo.xml -Create the (S)VCD image and burn it to /dev/cdrw. This will -automatically call vcdxbuild to make the image. If there is an existing -image, it will be burned. - -.TP -tovid vcd \-overwrite foo.xml -Create the (S)VCD image and exit without burning. If the image -already exists, then it is removed before re\-imaging. - -.SH Command:postproc -.P -\fBtovid postproc\fR is designed to do simple post\-processing on MPEG video files, such -as those generated by tovid. It can adjust audio/video sync, and re\-quantize -(shrink) without re\-encoding. - -.SS Usage -.P -\fBtovid postproc\fR [\fIOPTIONS\fR] \fIIN_FILE\fR \fIOUT_FILE\fR - -.SS Options -.TP -\fB\-audiodelay\fR \fINUM\fR -Delay the audio stream by \fINUM\fR milliseconds. Use this if -your final output has audio that is not synced with the -video. For example, if the audio comes 2 seconds sooner than -the video, use "\-audiodelay 2000". Use a negative number for -audio that comes later than the video. - -.TP -\fB\-normalize\fR -Analyze the audio stream and then normalize the volume of the audio. -This is useful if the audio is too quiet or too loud, or you want to -make volume consistent for a bunch of videos. Similar to running -normalize without any parameters. The default is \-12dB average level -with 0dB gain. - -.TP -\fB\-amplitude\fR \fINUM\fR[dB] -In addition to analyzing and normalizing, apply the gain to the audio -such that the 'average' (RMS) sound level is \fINUM\fR. Valid values -range 0.0 \- 1.0, with 0.0 being silent and 1.0 being full scale. Use -\fINUM\fRdB for a decibel gain below full scale (the default without -\-amplitude is \-12dB). - -.TP -\fB\-shrink\fR \fINUM\fR -Shrink the video stream by a factor of \fINUM\fR. May be a decimal -value. A value of 1.0 means the video will be the same size; -larger values cause more reduction in size. Beyond 2.0, the -returns are diminishing. .TP -\fB\-parallel\fR -Run all processes in parallel and pipe into multiplexer, should -increase speed significantly. - -.TP -\fB\-debug\fR -Save output in a temporary file, for later viewing if -something goes wrong. - -.SH Command:chapters -.P -\fBtovid chapters\fR will start a GUI using mplayer to set chapter points in a -video. Its only (mandatory) option is the path to a video file. - -.SS Examples -.TP tovid chapters foo.avi .TP -tovid chapters /home/grepper/videos/foo.avi +chapters=$(tovid chapters /home/grepper/videos/foo.avi) .SH CONTACT + .P For further assistance, contact information, forum and IRC links, please refer to the tovid homepage (http://tovid.wikia.com/). - -.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net) +.\" man code generated by txt2tags 2.6 (http://txt2tags.org) .\" cmdline: txt2tags -t man -i docs/src/en/tovid.t2t -o docs/man/tovid.1 -
View file
tovid-0.34.tar.bz2/docs/sphinx/conf.py -> tovid-0.35.tar.gz/docs/sphinx/conf.py
Changed
@@ -52,9 +52,9 @@ # built documents. # # The short X.Y version. -version = '0.33' +version = '0.34' # The full version, including alpha/beta/rc tags. -release = '0.33' +release = '0.34' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages.
View file
tovid-0.34.tar.bz2/docs/sphinx/man/tovid.rst -> tovid-0.35.tar.gz/docs/sphinx/man/tovid.rst
Changed
@@ -1,305 +1,358 @@ -=============================================================== -tovid manual -=============================================================== +Name +==== +tovid: Make DVDs from video files Description -=============================================================================== +=========== + +**tovid** is a command-line tool for creating DVDs. It can encode your +video files to DVD-compliant MPEG format, generate simple or complex DVD +menus, author and burn a ready-to-watch DVD, with just a few shell +commands. A graphical interface is also provided to make the process +even easier. + +**NOTE**: As of tovid 0.35, the legacy scripts **makemenu**, +**makexml**, **makevcd** have been deprecated and no longer appear in +this manpage. They are still included with tovid for now, and can be +used by doing: tovid menu|xml|vcd|postproc +as done in the previous 3 versions of tovid. + +Also note that as of tovid 0.32, this is the only manual page provided +by tovid. There is now a single executable frontend to all functionality +in the suite, so if you were expecting to find manpages for **todisc**, +**idvid**, **makempg** and their kin, they can all be found in the +**tovid** manpage you are reading now. + +And yes, this makes for a pretty large manual page. If you are viewing +this manpage from the command-line **man** utility, which normally pages +through the **less** utility, you can skip to a section by searching +with the **/** key, followed by a **^** to match the given section name. +For example, to skip to the **mpg** command, type **/^Command:mpg**. See +**man less** for more on how to navigate. -**tovid** is a command-line tool for creating DVDs. It can encode your video -files to DVD-compliant MPEG format, generate simple or complex DVD menus, -author and burn a ready-to-watch DVD, with just a few shell commands. A -graphical interface is also provided to make the process even easier. +Usage +===== -**NOTE**: As of tovid 0.32, this is the only manual page provided by tovid. -There is now a single executable frontend to all functionality in the suite, so -if you were expecting to find manpages for **todisc**, **idvid**, **makemenu** -and their kin, they can all be found in the **tovid** manpage you are reading now. +**tovid** *COMMAND* [*OPTIONS*] -And yes, this makes for a pretty large manual page. If you are viewing this -manpage from the command-line **man** utility, which normally pages through the -**less** utility, you can skip to a section by searching with the **/** key, -followed by a **^** to match the given section name. For example, to skip to -the **mpg** command, type **/^Command:mpg**. See :manpage:`less(1)` for more on how -to navigate. +Where *COMMAND* is one of the following: -Usage -=============================================================================== +Main Commands -:: +**disc** + Encode, make menus, author, burn. (was **todisc**. See + **Command:disc**) - tovid COMMAND [OPTIONS] +**gui** + Start the tovid GUI (was **todiscgui**. See **Command:gui**) -Where *COMMAND* is one of the following: +**titlesets** + A GUI wizard for multiple titlesets. (new: See + **Command:titlesets**) - gui - Start the tovid GUI (was **todiscgui**. See :ref:`command-gui`) - disc - Create a DVD with menus (was **todisc**. See :ref:`command-disc`) - mpg - Encode videos to MPEG format (was **tovid**. See :ref:`command-mpg`) - id - Identify one or more video files (was **idvid**. See :ref:`command-id`) - menu - Create an MPEG menu (was **makemenu**. See :ref:`command-menu`) - xml - Create (S)VCD or DVD .xml file (was **makexml**. See :ref:`command-xml`) - dvd - Author and/or burn a DVD (was **makedvd**. See :ref:`command-dvd`) - vcd - Author and/or burn a VCD (was **makevcd**. See :ref:`command-vcd`) - postproc - Post-process an MPEG video file (was **postproc**. See :ref:`command-postproc`) - -The *OPTIONS* differ for each command; run **tovid <command>** with no -further arguments to get help on a command, and what options it expects. +Helper Commands -Configuration -=============================================================================== +**mpg** + Encode videos to MPEG format (was **tovid**. See **Command:mpg**) -Two configuration files are created the first time you run tovid: +**dvd** + Author and/or burn a DVD (was **makedvd**. See **Command:dvd**) -``~/.tovid/preferences`` - Defines working directory for all scripts. - In addition you can define the output directory for makempg here. -``~/.tovid/tovid.config`` - Includes command-line options that should always be passed to - makempg. +**id** + Identify one or more video files (was **idvid**. See **Command:id**) - Edit these files if you wish to change your configuration. +**chapters** + A GUI using mplayer for setting chapter points. It will return a + string of chapter points to the terminal, in a format recognized by + ’tovid disc’ (todisc) or by ’tovid gui’, for the **-chapters** + option. -The following environment variables are also honoured: +The *OPTIONS* differ for each command; run **tovid +<command>** with no further arguments to get help on +a command, and what options it expects. -``TOVID_WORKING_DIR`` - working directory for all scripts -``TOVID_OUTPUT_DIR`` - output directory for the makempg script +Configuration +============= +Two configuration files are created the first time you run tovid: -.. _command-gui: +**~{**/.tovid/preferences} + Defines working directory for all scripts. In addition you can + define the output directory for makempg here. -Command:gui -=============================================================================== +**~{**/.tovid/tovid.ini} + Includes command-line options that should be passed to the various + **tovid** sub-commands. -**tovid gui** starts the graphical user interface (GUI) for tovid. This is -the easiest way to start creating DVDs with tovid. At this time, there are no -additional command-line options; the GUI controls take care of everything, -and all help is integrated in the form of tooltips. You can also see -:ref:`command-disc` for more detail about the options. Note: one limitation of -the gui at present is that it does not do multiple titlesets (though it will do -chapter menus). Use the **tovid disc** command (below) for titlesets. + Edit these files if you wish to change your configuration. + The following environment variables are also honoured: + TOVID\_WORKING\_DIR (working directory for all scripts). + TOVID\_OUTPUT\_DIR (output directory for the makempg script). -.. _command-disc: +Command:gui +=========== + +**tovid gui** starts the graphical user interface (GUI) for tovid. This +is the easiest way to start creating DVDs with tovid. The optional +arguments are any option used by todisc (’tovid disc’) which will save +entering it manually, OR the full path to a saved script from the GUI. +This option to save the contents of your project allows you to use it as +a bash script later, or to reload the project to continue working with +it at another time. Note: this feature is still in development so some +options may not load properly - make sure to check that your selections +were all loaded. + +All help is integrated in the form of tooltips. You can also see +\*\*Command:disc \*\* for more detail about the options. Note: if you +wish to use a GUI to make multiple titlesets on the same DVD use ’tovid +titlesets’, which is a wizard that uses the the ’tovid gui. + +Command:titlesets +================= + +**tovid titlesets** will assist in making a DVD with multiple titlesets. +It can be started without any options, or you can feed it the path to a +saved titleset script as an option. The option to save a script is also +useful as the resulting script can be run later from a terminal. Command:disc -=============================================================================== - -**tovid disc** creates a DVD file-system with menus, from a list of multimedia -video files and their titles. As this is a low level script it is the easiest -command line program for creating a DVD from start to finish, including -automatically converting non-compliant videos and prompting to burn at -completion. It does animated menus, static thumbnail menus and text only -menus. In addition, it can do slideshows, using images as input, and combine -slideshows with videos. It supports sub-menus for chapter breaks, configurable -menu style, animated backgrounds and transparency effects. +============ + +**tovid disc** creates a DVD file-system with optional menus, from a +list of multimedia video files and their titles. As todisc can function +as a master script, calling other scripts as it needs them, it is the +easiest command line program for creating a DVD from start to finish, +including automatically converting non-compliant videos and prompting to +burn at completion. It can do animated menus, static thumbnail menus, +text-only menus, or author with no menu. In addition, it can do +slideshows, using images as input, and even combine slideshows with +videos. It supports sub-menus for chapter breaks, configurable menu +style, animated backgrounds and transparency effects. From simple (no +menu) to complex (switched menus and titlesets), you should be able to +do what you want with ’tovid disc’. + +Please note that although the interface may seem complex with so many +options, you can create a fully functional DVD with only a few options +on the opening tab of the GUI (select video files and an output name). Usage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +----- :: - tovid disc [OPTIONS] \ - -files <file list> -titles <title list> - -out OUT_PREFIX - -For example:: + tovid disc [OPTIONS] \ + -files <file list> -titles <title list> + -out OUT_PREFIX - tovid disc -files File1.mpg File2.mpg File3.mpg \ - -titles "Episode 1" "Episode 2" "Episode 3" \ - -out Season_one +For example: -The number of **-files** and **-titles** must be equal, though if you do not -include any titles **tovid disc** will use the basename of the included files -as titles. If you are doing a slideshow or multiple slideshows, use -**-slides** rather than **-files** for passing in the images. You may use --files and -slides more than once to create an ordering in a mixed -slideshows/videos menu. See :ref:`usage-slideshows` under usage below. +:: -If the input files are not mpeg, you will have the option to auto-encode them. + $ tovid disc -files File1.mpg File2.mpg File3.mpg \ + -titles "Episode 1" "Episode 2" "Episode 3" \ + -out Season_one +The number of **-files** and **-titles** must be equal, though if you do +not include any titles **tovid disc** will use the basename of the +included files as titles. If you are doing a slideshow or multiple +slideshows, use **-slides** rather than **-files** for passing in the +images. You may use -files and -slides more than once to create an +ordering in a mixed slideshows/videos menu. See Slideshows part of Usage +section, below. -Display arrangements -------------------------------------------------------------------------------- +If the input files are not mpeg, you will have the option to auto-encode +them. -At present there are 2 display arrangements or "templates": +**At present there are 2 display arrangements or "templates":** A. (Default) Thumbs will be centred, and as large as space restraints allow. B. **-showcase** IMAGE|VIDEO - Produces an arrangement with small buttons on - the side and the showcase image/video in the centre. If no IMAGE or VIDEO - argument is supplied, the central thumb will be omitted. + Produces an arrangement with small buttons on the side and the + showcase image/video in the centre. If no IMAGE or VIDEO argument is + supplied, the central thumb will be omitted. + + Note: **-textmenu**, **-quick-menu** and **-switched-menus** are all + types of showcase style menus. See descriptions under **Menu style** + section. + +The **-titles** arguments should be double or single quoted, or have the +spaces backslash-escaped. Special characters (like ", !, \*, &, ?) may +need to be backslash-escaped. To include a quoted string within a title, +backslash-escape the quotes. These titles are used for labelling +thumbnails on the main menu, and for the submenu title for that video. ( +see also **-submenu-titles** ) + +The **-showcase** styles can use longer titles than the default +arrangement. With a showcase style, use: **-showcase-titles-align west** +to give more space for the title, or use **-showcase-titles-align east** +to allow titles of more than one line. + +The default style can only show about 16 characters (depending on the +number of thumbs, and what **-titles-font** and **-titles-fontsize** is +being used). If your titles are too long to fit in the label area, you +may try using sub-menus, which can display longer titles, for example: - Note: **-textmenu**, **-quick-menu** and **-switched-menus** are all types - of showcase style menus. See descriptions in the :ref:`menu-style` section. +:: -The **-titles** arguments should be double or single quoted, or have the spaces -backslash-escaped. Special characters (like ", !, \*, &, ?) may need to be -backslash-escaped. To include a quoted string within a title, backslash-escape -the quotes. These titles are used for labelling thumbnails on the main menu, -and for the submenu title for that video. ( see also **-submenu-titles** ) + $ tovid disc -submenus \ + -files file1.mpg file2.mpg ... \ + -titles "Short 1" "Short 2" \ + -submenus \ + -submenu-titles "Long Title One" "Long Title Two" \ + -out foo -The **-showcase** styles can use longer titles than the default arrangement. -With a showcase style, use: **-showcase-titles-align west** to give more space -for the title, or use **-showcase-titles-align east** to allow titles of more -than one line. +The **-align** argument will position both titles and thumbs either +south, north east, west, southwest, northwest, southeast, northeast, +subject to certain constraints of each arrangement. -The default style can only show about 16 characters (depending on the number -of thumbs, and what **-titles-font** and **-titles-fontsize** is being used). -If your titles are too long to fit in the label area, you may try using -sub-menus, which can display longer titles, for example:: +More Examples: - $ tovid disc -submenus \ - -files file1.mpg file2.mpg ... \ - -titles "Short 1" "Short 2" \ - -submenu-titles "Long Title One" "Long Title Two" \ - -out foo +A text-only menu: -The **-align** argument will position both titles and thumbs either south, -north east, west, southwest, northwest, southeast, northeast, subject to -certain constraints of each arrangement. +:: + $ tovid disc -textmenu ... -.. _usage-titlesets: +No menu: -Titlesets -------------------------------------------------------------------------------- +:: -A word should be mentioned here about titlesets, which is really just a -hierarchy of menus. You need to use titlesets, for example, if you have videos -of different resolutions, or otherwise want to arrange videos on separate menus. -If you want to have titlesets you need to put all the options for each titleset -menu you would like to have between **-titleset** and **-end-titleset** options. + $ tovid -nomenu -files file1.mpg [file2.mpg "file 3.mpg" ...] + +**Titlesets** -Additionally, for the main menu (the opening menu that will let you jump to -each titleset), you need to put options between **-vmgm** and **-end-vmgm**. -You do not use **-files** for the opening menu options (**-vmgm**), but you -will need as many TITLES after **-titles** as you have menus. +A word should be mentioned here about titlesets, which is really just a +hierarchy of menus. You need to use titlesets, for example, if you have +videos of different resolutions, or otherwise want to arrange videos on +separate menus. If you want to have titlesets you need to put all the +options for each titleset menu you would like to have between +**-titleset** and **-end-titleset** options. + +Additionally, for the main menu (the opening menu that will let you jump +to each titleset), you need to put options between **-vmgm** and +**-end-vmgm**. You do not use **-files** for the opening menu options +(**-vmgm**), but you will need as many TITLES after **-titles** as you +have menus. Any options outside the **-titleset** **-end-titleset** and **-vmgm** **-end-vmgm** areas will be general options applying to every titleset. -If a general option is duplicated inside a **-titleset** or **-vmgm** area, the -general option will be overridden. - -Note: you do not need titlesets for a single menu with chapter break menus, for -that just use **-submenus** or **-ani-submenus** - -Example of using **tovid disc** with titlesets:: - - $ tovid disc -static -out MY_DVD \ - \ - -titleset -files 1.mpg 2.mpg 3.mpg \ - -titles "Title One" "Title Two" "Title Three" \ - -end-titleset \ - \ - -titleset -files 4.mpg 5.mpg \ - -titles "Title Four" "Title Five" \ - -background foo.jpg \ - -showcase bar.png \ - -end-titleset \ - \ - -vmgm \ - -titles "Season One" "Season Two" \ - -background bg.jpg \ - -bgaudio foo.mp3 \ - -titles-fontsize 20 \ - -end-vmgm +If a general option is duplicated inside a **-titleset** or **-vmgm** +area, the general option will be overridden. + +Note: you do not need titlesets for a single menu with chapter break +menus, for that just use **-submenus** or **-ani-submenus** + +Example of using **tovid disc** with titlesets: + +:: + + $ tovid disc -static -out MY_DVD \ + \ + -titleset -files 1.mpg 2.mpg 3.mpg \ + -titles "Title One" "Title Two" "Title Three" \ + -end-titleset \ + \ + -titleset -files 4.mpg 5.mpg \ + -titles "Title Four" "Title Five" \ + -background foo.jpg \ + -showcase bar.png \ + -end-titleset \ + \ + -vmgm \ + -titles "Season One" "Season Two" \ + -background bg.jpg \ + -bgaudio foo.mp3 \ + -titles-fontsize 20 \ + -end-vmgm See also **-titleset** and **-vmgm** +**Slideshows** + +You can also use **tovid disc** to make slideshows. This can either be a +single slideshow, or multiple slideshows on the same menu. Remember to +use **-slides** rather than **-files** for passing in the images. Images +can be any filetype that imagemagick supports: for example JPEG, PNG, +GIF, TGA BMP etc. For a single slideshow do not use **-titles**: use +-menu-title to set the slideshow title. + +For a single slideshow the default is an animated menu that transitions +from slide to slide. The default transition type is ’crossfade’, which +fades each slide into the next and loops back to the first slide at the +end. If instead you use **-static**, then a static ’polaroid stack’ menu +of all the slides is created, with a single spumux’ed button for +navigating with the enter key. You may have to experiment to find out +which DVD remote button advances the slides. Try the ’next chapter’(skip +?) button and the play or enter buttons. If you want to limit the number +of slides in the menu to a subset of all files entered with **-slides**, +then use **-menu-slide-total** INT. Be sure to use a long enough audio +file for **-bgaudio** or set **-menu-length** so the menu is long enough +to support the slides plus transitions. + +You can also put multiple slideshows on one menu. To do this, use +**-slides IMAGES** for each slideshow desired. You can even mix videos +with slideshows by using **-files** **-slides** **-titles** multiple +times. + +Example of a single slideshow with an animated menu with transitions: -.. _usage-slideshows: +:: -Slideshows -------------------------------------------------------------------------------- - -You can also use **tovid disc** to make slideshows. This can either be a single -slideshow, or multiple slideshows on the same menu. -Remember to use **-slides** rather than **-files** for passing in the -images. Images can be any filetype that imagemagick supports: for example -JPEG, PNG, GIF, TGA BMP etc. For a single slideshow do not use **-titles**: -use -menu-title to set the slideshow title. - -For a single slideshow the default is an animated menu that transitions from -slide to slide. The default transition type is 'crossfade', which fades each -slide into the next and loops back to the first slide at the end. If instead -you use **-static**, then a static 'polaroid stack' menu of all the slides is -created, with a single spumux'ed button for navigating with the enter key. You -may have to experiment to find out which DVD remote button advances the slides. -Try the 'next chapter'(skip ?) button and the play or enter buttons. -If you want to limit the number of slides in the menu to a subset of all files -entered with **-slides**, then use **-menu-slide-total** INT. Be sure to use -a long enough audio file for **-bgaudio** or set **-menu-length** so the menu -is long enough to support the slides plus transitions. - -You can also put multiple slideshows on one menu. To do this, use -**-slides IMAGES** for each slideshow desired. You can even mix videos -with slideshows by using **-files** **-slides** **-titles** multiple times. - -Example of a single slideshow with an animated menu with transitions:: - - $ tovid disc -menu-title "Autumn in Toronto" -slides images/*.jpg \ - -menu-slide-total 20 -slide-transition crossfade -bgaudio slideshow.wav \ - -out myslideshow - -Example of multiple slideshows on one menu:: - - $ tovid disc -menu-title "Autumn in Toronto" \ - -slides photos/september/*.jpg \ - -slides photos/october/*.jpg \ - -slides photos/november/*.jpg \ - -tile3x1 -rotate -5 5 -5 -align center \ - -bgaudio background.wav \ - -out myslideshow - -Example of mixed videos and slideshows:: - - $ tovid disc -menu-title "Autumn in Toronto" \ - -files fall_fair.mov \ - -slides photos/september/*.jpg \ - -files harvest.mpg \ - -slides photos/october/*.jpg \ - -titles "Fall Fair" "September" "Harvest" "October" \ - -background autumn.png \ - -bgaudio bg.mp3 \ - -out myslideshow - -See the other slideshow options in the :ref:`usage-slideshows` options section. - -Encoding options -------------------------------------------------------------------------------- - -These are options for reencoding your non-compliant videos. They are passed -directly to the **tovid mpg** command which is invoked by **tovid disc** when -non-compliant files are found. For details, see the :ref:`command-mpg` section. -Here is a list of possible options you can pass: - -**-config**, **-ntscfilm**, **-dvd-vcd**, **-half-dvd**, **-kvcd**, -**-kvcdx3**, **-kvcdx3a**, **-kdvd**, **-bdvd**, **-704**, **-normalize**, -**-amplitude**, **-overwrite**, **-panavision**, **-force**, **-fps**, -**-vbitrate**, **-quality**, **-safe**, **-crop**, **-filters**, -**-abitrate**, **-priority**, **-deinterlace**, **-progressive**, -**-interlaced**, **-interlaced_bf**, **-type**, **-fit**, **-discsize**, -**-parallel**, **-mkvsub**, **-autosubs**, **-subtitles**, **-update**, \ -**-mplayeropts**, **-audiotrack**, **-downmix**, **-ffmpeg**, **-nofifo**, -**-from-gui**, **-slice**, **-async**, **-quiet**, -**-fake**, **-keepfiles** + $ tovid disc -menu-title "Autumn in Toronto" -slides images/*.jpg \ + -menu-slide-total 20 -slide-transition crossfade -bgaudio slideshow.wav \ + -out myslideshow +Example of multiple slideshows on one menu: -Basic options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:: + + $ tovid disc -menu-title "Autumn in Toronto" \ + -slides photos/september/*.jpg \ + -slides photos/october/*.jpg \ + -slides photos/november/*.jpg \ + -tile3x1 -rotate -5 5 -5 -align center \ + -bgaudio background.wav \ + -out myslideshow + +Example of mixed videos and slideshows: + +:: + + $ tovid disc -menu-title "Autumn in Toronto" \ + -files fall_fair.mov \ + -slides photos/september/*.jpg \ + -files harvest.mpg \ + -slides photos/october/*.jpg \ + -titles "Fall Fair" "September" "Harvest" "October" \ + -background autumn.png \ + -bgaudio bg.mp3 \ + -out myslideshow + +See the other slideshow options in the Slideshows options section. + +**Encoding Options** + +These are options for reencoding your non-compliant videos. They are +passed directly to the **tovid mpg** command which is invoked by **tovid +disc** when non-compliant files are found. For details, see the +**Command:mpg** section. Here is a list of possible options you can +pass: **-config**, **-ntscfilm**, **-dvd-vcd**, **-half-dvd**, +**-kvcd**, **-kvcdx3**, **-kvcdx3a**, **-kdvd**, **-bdvd**, **-704**, +**-normalize**, **-amplitude**, **-overwrite**, **-panavision**, +**-force**, **-fps**, **-vbitrate**, **-quality**, **-safe**, **-crop**, +**-filters**, **-abitrate**, **-priority**, **-deinterlace**, +**-progressive**, **-interlaced**, **-interlaced\_bf**, **-type**, +**-fit**, **-discsize**, **-parallel**, **-mkvsub**, **-autosubs**, +**-subtitles**, **-update**, **-mplayeropts**, +**-audiotrack**, **-downmix**, **-ffmpeg**, **-nofifo**, **-from-gui**, +**-slice**, **-quiet**, **-fake**, **-keepfiles** + +Options +------- **-keep-files**, **-keepfiles** Keep all intermediate/temporary files (helps with debugging) @@ -311,216 +364,242 @@ 720x576 output, compatible with PAL standard **-submenus** - Create a sub-menu with chapters for each video (default: no sub-menus) + Create a sub-menu with chapters for each video (default: no + sub-menus) **-ani-submenus** - Create an animated sub-menu with chapters for each video (default: not - animated) + Create an animated sub-menu with chapters for each video (default: + not animated) **-no-menu | -nomenu** - With this option todisc will just create a DVD file system, ready for - burning, with NO MENU, just the supplied video files. These do not need - to be compliant, as non-compliant files will be encoded as usual. Each - video will be a chapter unless **-chapters** OPTION is passed. The - **-chapters** option is a number indicating the chapter interval in - minutes, or a HH:MM:SS string indicating chapter points. See **-chapters** - - -.. _menu-style: - -Basic menu style options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + With this option todisc will just create a DVD file system, ready + for burning, with NO MENU, just the supplied video files. These do + not need to be compliant, as non-compliant files will be encoded as + usual. The **-out** option is not required. Each video will be a + chapter unless **-chapters** OPTION is passed. The **-chapters** + option is a number indicating the chapter interval in minutes, or a + HH:MM:SS string indicating chapter points. See **-chapters** + +**-encode-only** + This option was originally meant for the GUI, to allow it to be used + for just encoding rather than making a DVD structure. But it works + well from the command line as well as it has the added advantage + that you can input a list of files. Remember any makempg (’tovid + mpg’) options you use will be passed on to the the makempg script + when encoding. + +Menu style +---------- **-showcase** IMAGE|VIDEO - If used without an argument, use showcase style without a central thumb. - This is a different arrangement of images for the menu: small thumbnails - go at left (and right) side of screen, with a larger image in the centre. - Maximum of 10 videos. If the provided argument is a video file, the - central thumb will be animated. Pick a file of correct aspect ratio: - i.e. it should still look good when resized to 720x480 (PAL 720x576), - then resized to proper aspect ratio. + If used without an argument, use showcase style without a central + thumb. This is a different arrangement of images for the menu: small + thumbnails go at left (and right) side of screen, with a larger + image in the centre. Maximum of 10 videos. If the provided argument + is a video file, the central thumb will be animated. Only 4:3 or + 16:9 videos and images are accepted for the showcase file: if not + one of these todisc will assume it is the same ratio as the videos + in the titleset. **-textmenu**, **-text-menu** NUM - If used without an argument, create a textmenu out of the supplied titles - The optional argument specifies how many titles are in the 1st column, - i.e. giving 4 titles and using **-textmenu 2** would make 2 columns of 2 - titles. The default is to put all titles up to 13 in the first column - before starting a second column. Maximum: 2 columns and 26 titles. - Note that column 2 titles are aligned to the right. - If no video files for either **-background** or **-showcase** are supplied, - the menu will be static. + If used without an argument, create a textmenu out of the supplied + titles The optional argument specifies how many titles are in the + 1st column, i.e. giving 4 titles and using "-textmenu 2" would make + 2 columns of 2 titles. The default is to put all titles up to 13 in + the first column before starting a second column. Maximum: 2 columns + and 26 titles. Note that column 2 titles are aligned to the right. + If no video files for either **-background** or **-showcase** are + supplied, the menu will be static. **-quick-menu** - (Note: unfortunately ffmpeg's 'vhooks' have been removed, so this - option may not be available for you depending on your ffmpeg version) - This will make a very quick menu by using ffmpeg instead of imagemagick. - There are two choices: you can either use **-showcase IMAGE|VIDEO** or - **-background VIDEO**. There are no fancy effects like **-wave** - or **-rotate** available for it, but it is extremely fast. It will be a - text-menu style of menu, with no video thumbs, and a central showcase - IMAGE (static) | VIDEO (animated). See **-bg-color** if you are not using - a **-background** and want to change the default black. - - Specifying the IMAGE|VIDEO argument to **-showcase** is mandatory for this - style of menu, unless used in conjunction with **-switched-menus** - in which case the videos passed with **-files** automatically become the - showcase videos. If this is used in combination with **-switched-menus** - it can really speed up an otherwise time consuming process. - - Example:: - - -quick-menu -showcase /home/robert/showcase.mpg + If you are using ffmpeg 0.8 or newer you can use this option. This + will make a very quick menu by using ffmpeg instead of imagemagick. + There are two choices: you can either use ’-showcase + IMAGE|VIDEO or ’-background VIDEO’. There are no fancy + effects like **-wave** or **-rotate** available for it, but it is + extremely fast. It will be a text-menu style of menu, with no video + thumbs, and a central showcase IMAGE(static) | VIDEO(animated). + (i) see **-bg-color** if you are not using a **-background** and + want to change the default black ) (ii) Note: todisc will still work + with vhooks if you have an old ffmpeg with vhooks compiled in. + + Specifying the IMAGE|VIDEO argument to **-showcase** is + mandatory for this style of menu, unless used in conjunction with + **-switched-menus** in which case the videos passed with **-files** + automatically become the showcase videos. If this is used in + combination with **-switched-menus** it can really speed up an + otherwise time consuming process. + + Example: + + :: + + -quick-menu -showcase /home/robert/showcase.mpg See **-switched-menus** for example of making switched menus with **-quick-menu** -**-bg-color** | **-bg-colour** +**-bg-color**, **-bg-colour** The color to use for the menu background. (default: ntsc-safe black) - Note: use a color a great deal darker than you want, as it appears quite - a bit lighter in the video version. You can use hexadecimal ('#ffac5f') - or named colors notation. - -**-submenu-bg-color** | **-submenu-bg-colour** - The color to use as background for the submenu(s). - (default: ntsc-safe black) See **-bg-color** + Note: use a color a great deal darker than you want, as it appears + quite a bit lighter in the video version. You can use hexadecimal + (’#ffac5f’) or named colors notation. -**-use-makemenu** - This will use **tovid menu** to create a menu with the provided titles. +**-submenu-bg-color**, **-submenu-bg-colour** + The color to use as background for the submenu(s). (default: + ntsc-safe black) See **-bg-color** **-static** - Main menu will just be static thumbs (not animated) (default: animated) + Main menu will consist of static thumbnail links. (default: + animated) If you use a video for -showcase or -background then it + will still be a ’moving’ menu, in spite of the static buttons. This + option also does double duty for the **-switched-menus** option, and + will create static "switched" images. See also **-switched-menu** **-background** IMAGE|VIDEO - Menu background. This can be a image file or an video file. If it is a - video file the background will be animated. Pick a file of correct aspect - ratio: i.e. it should still look good when resized to 720x480 (PAL 720x576) + Menu background. This can be a image file or an video file. If it is + a video file the background will be animated. Pick a file of correct + aspect ratio: i.e. it should still look good when resized to 4:3 + aspect ratio. It will be resized to fill the entire background. **-submenu-background** IMAGE - Submenu background. This can be only be an image file. Pick a file of - correct aspect ratio: i.e. it should still look good when resized to - 720x480 (PAL 720x576) + Submenu background. This can be only be an image file. Pick a file + of correct aspect ratio: i.e. it should still look good when resized + to 4:3 aspect ratio. It will be resized to fill the entire + background. **-menu-title** - Title for the root menu - may be longer than thumbnail labels - Also if you use \n in the title, you can use multi line titles, but you - would need to adjust **-menu-fontsize** to something smaller than default - for example:: + Title for the root menu - may be longer than thumbnail labels Also if you + use \n in the title, you can use multi line titles, but you would need to + adjust **-menu-fontsize** to something smaller than default for example: - $ tovid disc ... -menu-title "A\nMultilined\nTitle" -menu-fontsize 24 + :: + + $ tovid disc ... -menu-title "A\nMultilined\nTitle" -menu-fontsize 24 **-menu-font** FONT - Font to use for titles, either by ImageMagick font name (ex., "Arial") or - explicit pathname (ex., "/full/path/to/arial.ttf"). To see a complete - list of acceptable ImageMagick font names, run **convert -list type**, and - refer to the leftmost column + Font to use for titles, either by ImageMagick font name (ex., + "Arial") or explicit pathname (ex., "/full/path/to/arial.ttf"). To + see a complete list of acceptable ImageMagick font names, run + **convert -list type**, and refer to the leftmost column **-menu-fontsize** - Font size for main menu - best to **-preview** if you use this + Font size for main menu - best to -preview if you use this **-submenu-font** - Font to use for the sub-menu main titles. See **-menu-font** + Font to use for the sub-menu main titles. See **-menu-font** **-submenu-fontsize** Font size for the sub-menu main titles -**-menu-fade** ['BACKGROUND DURATION'] - Fade the menu in and out The background will fade in first, then title (and - mist if called for), then the menu thumbs. The fadeout is in reverse - order. 'BACKGROUND DURATION' is an integer denoting the amount of time the - background will play before the menu begins to fade in. This can allow you - to do a 'transition' to the menu: if you supply a **-background VIDEO** it - will play for the indicated time before the menu fades in. Leave the - optional argument empty (just **-menu-fade**) to get the default behavior - of showing the background for 1 second before fading the menu in. To - disable the fadeout portion, use '**-loop** inf'. See also: +**-menu-fade** [’BACKGROUND DURATION’] + Fade the menu in and out The background will fade in first, then + title (and mist if called for), then the menu thumbs. The fadeout is + in reverse order. ’BACKGROUND DURATION’ is an integer denoting the + amount of time the background will play before the menu begins to + fade in. This can allow you to do a ’transition’ to the menu: if you + supply a -background VIDEO it will play for the indicated time + before the menu fades in. Leave the optional argument empty (just + **-menu-fade**) to get the default behavior of showing the + background for 1 second before fading the menu in. To disable the + fadeout portion, use ’**-loop** inf’. See also: **-transition-to-menu** and **-loop** **-transition-to-menu** This option goes with the **-menu-fade** option above, which must be - enabled for it to have effect. It is a convenience option for animated - backgrounds: the background will become static at the exact point the - thumbs finish fading in. This menu does not loop unless you pass - **-loop VALUE**. See also: **-loop** + enabled for it to have effect. It is a convenience option for + animated backgrounds: the background will become static at the exact + point the thumbs finish fading in. This menu does not loop unless + you pass **-loop** VALUE. See also: **-loop** -**-bgaudio**, **-bg-audio** FILE - An file containing audio for the main menu background. For static menus - the default is to use 20 seconds of audio. You can change this using the - **-menu-length** option. +**-bgaudio**, **-bg-audio\*** FILE + An file containing audio for the main menu background. For static + menus the default is to use 20 seconds of audio. You can change this + using the **-menu-length** option. **-submenu-audio** FILE(S) - List of files for sub-menu audio backgrounds. If one file is given, then - it will be used for all sub-menus. Otherwise the number given must equal - the number of submenus, though the keyword "none" in this list may be used for - silence. See also **-submenu-length** + List of files for sub-menu audio backgrounds. If one file is given, + then it will be used for all sub-menus. Otherwise the number given + must equal the number of submenus, though the keyword "none" in this + list may be used for silence. See also **-submenu-length** **-titleset** . . . **-end-titleset** - If you have more than one titleset, put options for each titleset between - **-titleset** and **-end-titleset**. A separate menu will be created that - can be accessed from the main menu (VMGM). You can create this main menu - using the **-vmgm** **-end-vmgm** options. See **-vmgm** below and - :ref:`usage-titlesets` under the **Usage** section. + If you have more than one titleset, put options for each titleset + between **-titleset** and **-end-titleset**. A separate menu will be + created that can be accessed from the main menu (VMGM). You can + create this main menu using the **-vmgm** **-end-vmgm** options. See + **-vmgm** below and TITLESET paragraph opening **Usage** section. **-vmgm** . . . **-end-vmgm** - The VMGM menu is the root menu when you use titlesets. - Put your VMGM menu options between **-vmgm** and **-end-vmgm**. - You only need **-titles** "Titleset One title" "Titleset Two title" - . . . , and not **-files**. - Any other options can be used, but the menu will be a textmenu style by - default. **Hint**: use **-showcase** IMAGE/VIDEO to create a fancier - VMGM menu. - -**-no-vmgm-menu** | **-no-vmgm** - This will skip the creation of a VMGM ( root menu ) for titlesets. The DVD - will start with the first titleset. You can not use this option unless also - using **-quick-nav** as you would not have a way to get to other titlesets. + The VMGM menu is the root menu when you use titlesets. Put your VMGM + menu options between **-vmgm** and **-end-vmgm**. You only need + **-titles** "Titleset One title" "Titleset Two title" . . . , and + not **-files**. Any other options can be used, but the menu will be + a textmenu style by default. **Hint**: use **-showcase** IMAGE/VIDEO + to create a fancier VMGM menu. + +**-no-vmgm-menu**, **-no-vmgm** + This will skip the creation of a VMGM ( root menu ) for titlesets. + The DVD will start with the first titleset. You can not use this + option unless also using **-quick-nav** as you would not have a way + to get to other titlesets. **-skip-vmgm** Start DVD from the first titleset instead of the VMGM ( root ) menu. **-switched-menus** - This will make a "switched menu": there will be a central image where the - showcase image would go, and text menu titles along the menu edge where - textmenu titles go. As you select a video title with the down or up arrow - on your DVD remote, the image in the centre will change to the image or - video made from that selected video. Do not use **-showcase** IMAGE/VIDEO - with this option. + This will make a "switched menu": there will be a central image + where the showcase image would go, and text menu titles along the + menu edge where textmenu titles go. As you select a video title with + the down or up arrow on your DVD remote, the image in the centre + will change to the image or video made from that selected video. Do + not use **-showcase** IMAGE/VIDEO with this option. + + This can be a time consuming process for making animated menus as + you need to make a separate menu for each video provided with + **-files**. The process can be greatly sped up by using + **-quick-menu** in conjunction with this, though you will lose fancy + options like **-rotate** and **-wave**. - This can be a time consuming process for making animated menus as you need - to make a separate menu for each video provided with **-files**. The - process can be greatly sped up by using **-quick-menu** in conjunction with - this, though you will lose fancy options like **-rotate** and **-wave**. + Note that if you want to just have a static rather than an + ’animated’ image, add **-static** to the command line. - Example for using with **-quick-menu**:: + Example for using with **-quick-menu**: - -switched-menus -quick-menu + :: + -switched-menus -quick-menu Thumbnail style -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -**-thumb-shape** normal|oval|vignette|plectrum|arch|spiral|blob|star|flare - Apply a shaped transparency mask to thumbnail videos. - These "feathered" shapes look best against a plain background (or used - in conjunction with **-thumb-mist** [COLOR]). For this rectangular - semi-transparent misted background for each thumb: see **-thumb-mist**. - Note: if you wish to make your own mask PNGS you can put them in - $PREFIX/lib/tovid/masks/ or $HOME/.tovid/masks/ and use them on the - command line using the filename minus the path and extension. - (i.e ~/.tovid/masks/tux.png becomes **-thumb-shape tux**) +--------------- + +**-thumb-shape** + normal|oval|vignette|plectrum|arch|spiral|blob|star|flare + Apply a shaped transparency mask to thumbnail videos. These + "feathered" shapes look best against a plain background (or used in + conjunction with **-thumb-mist** [COLOR]). For this rectangular + semi-transparent misted background for each thumb: see + **-thumb-mist**. Note: if you wish to make your own mask PNGS you + can put them in $PREFIX/lib/tovid/masks/ or $HOME/.tovid/masks/ and + use them on the command line using the filename minus the path and + extension. (i.e ~{}/.tovid/masks/tux.png becomes -thumb-shape tux) No frame is used for shaped thumbs. **-thumb-frame-size** INT - The size (thickness) of the thumb frames in pixels. This will also set the - thickness of the raised "frame" of thumbs when you use **-3d-thumbs**. - See also **-showcase-frame-size** and **-thumb-frame-color** + The size (thickness) of the thumb frames in pixels. This will also + set the thickness of the raised "frame" of thumbs when you use + **-3d-thumbs**. See also **-showcase-frame-size** and + **-thumb-frame-color** **-thumb-frame-color**, **-thumb-frame-colour** COLOR - The color of frames for video thumbnails. Use hexadecimal or named colors - notation. Remember to quote if using hexadecimal! ( '#ffac5f' ). + The color of frames for video thumbnails. Use hexadecimal or named + colors notation. Remember to quote if using hexadecimal! ( ’#ffac5f’ + ). **-3d-thumbs**, **-3dthumbs** - This will give an illusion of 3D to the thumbnails: dynamic lighting on - rounded thumbs, and a raised effect on rectangular thumbs. Try it ! + This will give an illusion of 3D to the thumbnails: dynamic lighting + on rounded thumbs, and a raised effect on rectangular thumbs. Try it + ! **-titles-font** FONT Display thumbnail or textmenu titles in the given font @@ -528,197 +607,233 @@ **-titles-fontsize** POINTS Font size to use for thumbnail or textmenu titles - Slideshows -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +---------- **-slides** IMAGES - Use **-slides** IMAGES to pass in images for a slideshow. The default is - to make an animated menu of the slides, moving from one slide to the - next. If you use **-static**, a 'polaroid stack' montage is created. This - composites the slides onto the background in 'random' locations with random - rotations. **-slides** IMAGES can be used multiple times if you wish to - make a menu with multiple slideshows. You can also make a menu - of mixed videos and slideshows by using **-slides** IMAGES, and **-files** - VIDEOS multiple times. For such a menu, the number of **-titles** - needs to match the number of **-files** passed in plus the number of - slideshows. (Each time you use **-slides** counts as one title.) To use - a transition between the slides, use **-slide-transition** - crossfade|fade. See **-slide-transition** **-menu-slide-total** + Use **-slides** IMAGES to pass in images for a slideshow. The + default is to make an animated menu of the slides, moving from one + slide to the next. If you use **-static**, a ’polaroid stack’ + montage is created. This composites the slides onto the background + in ’random’ locations with random rotations. **-slides** IMAGES can + be used multiple times if you wish to make a menu with multiple + slideshows. You can also make a menu of mixed videos and slideshows + by using **-slides** IMAGES, and **-files** VIDEOS multiple times. + For such a menu, the number of **-titles** needs to match the number + of **-files** passed in plus the number of slideshows. (Each time + you use **-slides** counts as one title.) To use a transition + between the slides, use **-slide-transition** + crossfade|fade. See **-slide-transition** **-menu-slide-total** **-menu-slide-total** INT - Use INT number of the slides that were passed in with **-slides** - to make the animated or static slide menu. The length of the menu is - determined by 1) **-menu-length** NUM if given, and by 2) the length - of the audio from **-bgaudio**. For submenu slideshows, it is determined - by 1) **-submenu-length** NUM if given, and by 2) the length of the - audio from **-submenu-audio** FILE(S). + Use INT number of the slides that were passed in with **-slides** to + make the animated or static slide menu. The length of the menu is + determined by 1) **-menu-length** NUM if given, and by 2) the length + of the audio from **-bgaudio**. For submenu slideshows, it is + determined by 1) **-submenu-length** NUM if given, and by 2) the + length of the audio from **-submenu-audio** FILE(S). **-submenu-slide-total** INT This option is the same as **-menu-slide-total** except that it is for submenu slideshows. **-slide-transition** crossfade|fade [crossfade] - The type of fade transition between slides in a animated slide menu. Be - sure the menu length is long enough to support the 1 second transitions - between the slides. The length is determined by 1) the length of the - **-bgaudio AUDIO** and 2) the length given with **-menu-length NUM**. For - submenu slideshows, it is determined by 1) **-submenu-length NUM** if - given, and by 2) the length of the audio from **-submenu-audio** FILE(S). + The type of fade transition between slides in a animated slide menu. + Be sure the menu length is long enough to support the 1 second + transitions between the slides. The length is determined by 1) the + length of the -bgaudio AUDIO 2) the length given with -menu-length + NUM. For submenu slideshows, it is determined by 1) + **-submenu-length** NUM if given, and by 2) the length of the audio + from **-submenu-audio** FILE(S). See **-menu-slide-total** , **-bgaudio** , **-menu-length** , **-submenu-length**, and **-submenu-audio**. - The 'crossfade' transition fades from one slide to another. The 'fade' - transition fades in and out from and to black. If you don't use this - option, the default is to use a 'crossfade' transition. + The ’crossfade’ transition fades from one slide to another. The + ’fade’ transition fades in and out from and to black. If you don’t + use this option, the default is to use a ’crossfade’ transition. **-slideshow-menu-thumbs** FILES Use the FILES instead of the 1st image in each slideshow as the - thumb that shows on the menu. This option is for multiple slideshows + thumb that shows on the menu. This option is for multiple slideshows or mixed slideshow/video menus only. **-slides-to-bin** FILES - FILES will be resized to 640x480 using a 'box' filter - this - is called 'binning'. It will reduce the 'signal to noise' ratio for the - image in the animated slide menu. Use this if you get some unwanted - effects for certain images, such as pixels shifting in what should be a - static image. See also **-slides-to-blur** and **-slide-border** + FILES will be resized to 640x480 using a ’box’ filter - this is + called ’binning’. It will reduce the ’signal to noise’ ratio for the + image in the animated slide menu. Use this if you get some unwanted + effects for certain images, such as pixels shifting in what should + be a static image. See also **-slides-to-blur** and + **-slide-border** **-slides-to-blur** FILES - FILES will be blurred a small amount - which will help on - slides that still have noise even after 'binning' with -slides-to-bin. - The default blur is 0x0.2 - you can increase this with - -slide-blur ARG. See also **-slides-to-bin** and **-slide-border** + FILES will be blurred a small amount - which will help on slides + that still have noise even after ’binning’ with -slides-to-bin. The + default blur is 0x0.2 - you can increase this with -slide-blur ARG. + See also **-slides-to-bin** and **-slide-border** **-slide-blur** VALUE or LIST of VALUES [0x0.2] - The argument to use for blurring files. It will be passed to - imagemagick: convert -blur ARG. The format of the arg is {radius}x{sigma} - and the default is 0x0.2. Using values between 0x0.1 and 0x0.9 is probably - the best range. Use a single value for all, or a list to have a different - blur for each file passed with **-slides-to-blur**. You must pass in - **-files-to-blur** FILES to use this option. Blurring can help 'noise' - problems in the video. See also **-slides-to-bin** and **-slide-border** + The argument to use for blurring files. It will be passed to + imagemagick: convert -blur ARG. The format of the arg is + {radius}x{sigma} and the default is 0x0.2. Using values between + 0x0.1 and 0x0.9 is probably the best range. Use a single value for + all, or a list to have a different blur for each file passed with + **-slides-to-blur**. You must pass in **-files-to-blur** FILES to + use this option. Blurring can help ’noise’ problems in the video. + See also **-slides-to-bin** and **-slide-border** **-slide-border** WIDTH [100] - Pad the slides with a border for the animated slide menu. The default - without using an argument is 100. Using this option can also solve some - noise/ringing effects if used alone or in conjunction with 'binning' - (**-slides-to-bin**) or blurring (**-slides-to-blur**). + Pad the slides with a border for the animated slide menu. The + default without using an argument is 100. Using this option can also + solve some noise/ringing effects if used alone or in conjunction + with ’binning’ (**-slides-to-bin**) or blurring + (**-slides-to-blur**). **-slide-frame** WIDTH [12] - Frame the slides for the animated slideshow menu. The default width - without using an argument is 12. See also **-slide-frame-color** + Frame the slides for the animated slideshow menu. The default width + without using an argument is 12. See also **-slide-frame-color** -**-slide-frame-color** | **-slide-frame-colour** - The color of the slide frame if passing **-slide-frame**. The default if - you don't use this option is a color-safe white: rgb(235,235,235). +**-slide-frame-color**, **-slide-frame-colour** + The color of the slide frame if passing **-slide-frame**. The + default if you don’t use this option is a color-safe white: + rgb(235,235,235). **-showcase-slideshow** - If doing multiple slideshows or mixed videos and slideshow(s), then use - the animated slideshow as a showcase video. It will be composed of slides - from each slideshow in the menu. The thumb for each slideshow button will - be static. If you used with a mixed menu of videos and slideshows, then - the video thumbs WILL be animated, so you may wish to use -static or - -textmenu with the option in that case. + If doing multiple slideshows or mixed videos and slideshow(s), then + use the animated slideshow as a showcase video. It will be composed + of slides from each slideshow in the menu. The thumb for each + slideshow button will be static. If you used with a mixed menu of + videos and slideshows, then the video thumbs WILL be animated, so + you may wish to use -static or -textmenu with the option in that + case. If you want to use the \*\*-switched-menus option with a mixed + menu leave this option out. **-background-slideshow**, **-bg-slideshow** - If doing multiple slideshows or mixed videos and slideshow(s), then use - the animated slideshow as a background video. See **-showcase-slideshow** - for additional details. + If doing multiple slideshows or mixed videos and slideshow(s), then + use the animated slideshow as a background video. See + **-showcase-slideshow** for additional details. **-no-confirm-backup** - Slideshows are an experimental (but well tested) feature. Todisc is - unlikely to overwrite your personal files, but you should take precautions - and backup your images, as you would with any beta software. Todisc - will prompt you to backup your files normally. If you have already backed - up your images, use this option to disable the prompt. - -**-use-dvd-slideshow** [FILE CONFIG] + Slideshows are an experimental (but well tested) feature. Todisc is + unlikely to overwrite your personal files, but you should take + precautions and backup your images, as you would with any beta + software. Todisc will prompt you to backup your files normally. If + you have already backed up your images, use this option to disable + the prompt. + +**-use-dvd-slideshow** {CONFIG} {FILE} If you pass this option without an argument, tovid will use the - dvd-slideshow program to create the animated slide menu, assuming you have - this program installed. The optional argument is the dvd-slideshow - configuration file - if you don't use this argument tovid will create it - for you. If you want to use the 'Ken Burns effect' - then the - configuration file argument is required. Note: the configuration file will - override many of the above options for slideshows. + dvd-slideshow program to create the animated slide menu, assuming + you have this program installed. The optional argument is the + dvd-slideshow configuration file - if you don’t use this argument + tovid will create it for you. If you want to use the ’Ken Burns + effect’ - then the configuration file argument is required. Note: + the configuration file will override many of the above options for + slideshows. + +Burning the disc +---------------- +**-burn** + Prompt to burn the DVD directory on completion. -Advanced Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**-device** + Device to use for the burning program [ /dev/dvdrw ] + +**-speed** + The speed to use for burning the disc. + +Advanced usage +-------------- + +Options +~~~~~~~ **-menu-length** The desired animated main menu length in seconds **-submenu-length** - The desired submenu length. This will also affect the length of submenu - audio for static submenus. (Assuming that -submenu-audio was passed in). - The default is to use 10 seconds of audio for static menus. + The desired submenu length. This will also affect the length of + submenu audio for static submenus. (Assuming that -submenu-audio was + passed in). The default is to use 10 seconds of audio for static + menus. **-submenu-stroke** COLOR - The color for the sub-menu font outline (stroke) + The color for the sub-menu font shadow **-submenu-title-color**, **-submenu-title-colour** The fill color used for sub-menu title fonts **-submenu-titles** - You can supple a list of titles here for sub-menus without the length - restrictions found in thumb titles. Must equal number of videos + You can supple a list of titles here for sub-menus without the + length restrictions found in thumb titles. Must equal number of + videos **-chapters** [ NUM | CHAPTER POINTS in HH:MM:SS ] - The number of chapters for each video (default: 6) OR - the actual chapter points in HH:MM:SS format. - Chapter points will be used for generating the submenu thumbs, and for - seeking with your DVD player. You can pass in just one value that will - be used for all videos, or supply a list of values (number of chapters) - or time code strings. + The number of chapters for each video (default: 6) OR the actual + chapter points in HH:MM:SS format. Chapter points will be used for + generating the submenu thumbs, and for seeking with your DVD player. + You can pass in just one value that will be used for all videos, or + supply a list of values (number of chapters) or time code strings. - If you just pass an integer for 'number of chapters', then tovid will - make the chapter points for you by dividing the video length by the number - you supply. If using the **-no-menu** option, the INT passed in will be - the chapter interval in minutes, rather than the above formula. + If you just pass an integer for ’number of chapters’, then tovid + will make the chapter points for you by dividing the video length by + the number you supply. If using the **-no-menu** option, the INT + passed in will be the chapter interval in minutes, rather than the + above formula. - If passing HH:MM:SS format you need to pass the string of chapter points for - each video and each string should have comma separated values. - Additionally, the first chapter should always start at 00:00:00 as - dvdauthor will add that if it is not there already. + If passing HH:MM:SS format you need to pass the string of chapter + points for each video and each string should have comma separated + values. Additionally, the first chapter should always start at + 00:00:00 as dvdauthor will add that if it is not there already. - To get your time codes, you can play your videos in mplayer and press 'o' - to see them on-screen. I have found these to be very accurate in my short - tests. For greater frame accuracy you could try loading the file in - avidemux and find the time codes for the frames you want. + To get your time codes, you can play your videos in mplayer and + press ’o’ to see them on-screen. I have found these to be very + accurate in my short tests. For greater frame accuracy you could try + loading the file in avidemux and find the time codes for the frames + you want. - If passing grouped chapters you need to join the chapters from all the - videos in a group with a '+' separator. If you want to skip creating - chapters for a video in the group use '0' for its chapters. + If passing grouped chapters you need to join the chapters from all + the videos in a group with a ’+’ separator. If you want to skip + creating chapters for a video in the group use ’0’ for its chapters. - Note: chapters for grouped videos should probably be passed in using the - above HH:MM:SS format. (Arbitrary chapters using just an INT for the # of - chapters is not guaranteed to work reliably in all cases for grouped videos - at the moment.) + Note: chapters for grouped videos should probably be passed in using + the above HH:MM:SS format. (Arbitrary chapters using just an INT for + the # of chapters is not guaranteed to work reliably in all cases + for grouped videos at the moment.) - Example for passing just number of chapters ( 4 videos ):: + Example for passing just number of chapters ( 4 videos ): - -chapters 5 2 4 8 + :: - Example of passing chapter points ( 4 videos ):: + -chapters 5 2 4 8 - -chapters 00:00:00,00:05:34.41,00:12:54,00:20:45 \ - 00:00:00,00:04:25.623,00:09:12,00:15:51 \ - 00:00:00,00:05:10,00:13:41,00:18:13.033 \ - 00:00:00,00:15:23.342,00:26:42.523 + Example of passing chapter points ( 4 videos ): - Example of passing grouped chapters using the '+' separator:: + :: - -chapters 00:00:00,00:05:34.41,00:12:54,00:20:45+00:04:23,00:09:35 \ - 00:00:00... etc. + -chapters 00:00:00,00:05:34.41,00:12:54,00:20:45 \ + 00:00:00,00:04:25.623,00:09:12,00:15:51 \ + 00:00:00,00:05:10,00:13:41,00:18:13.033 \ + 00:00:00,00:15:23.342,00:26:42.523 + + Example of passing grouped chapters using the ’+’ separator: + + :: + + -chapters 00:00:00,00:05:34.41,00:12:54,00:20:45+00:04:23,00:09:35 \ + 00:00:00... etc. **-chapter-titles** LIST If you are using submenus, you can pass a list of titles for the - chapters. Each title must be quoted, and the number of titles given - must equal the total number of chapters for all videos. In other words - if you use -chapters 4 6 8 , you must give 18 chapter titles, in the same - order that the videos were passed in. + chapters. Each title must be quoted, and the number of titles given + must equal the total number of chapters for all videos. In other + words if you use -chapters 4 6 8 , you must give 18 chapter titles, + in the same order that the videos were passed in. Note: if you are + passing in options on the command line to the ’tovid disc’ GUI, you + must repeat the option **-chapter-titles** for each video, + accompanied by its respective chapter titles. (you can also choose + to use this syntax for the todisc script.) **-chapter-font** FONT Use FONT as the font for submenu chapters. @@ -730,15 +845,26 @@ The color for the chapters font. **-chapter-stroke** COLOR - The color for the chapters font outline (stroke) + The color for the chapters font shadow **-seek** NUM | "NUM1 NUM2 NUM3 . . ." - Seek to NUM seconds before generating thumbnails (default: 2.0 seconds) - If a quoted string of values matching the number of videos is used, then - each video can use a different seek value - If using switched menus, the **-seek** value(s) will be used to generate - the showcase image that displays on switching to another video choice with - the up/down arrow keys. + Seek to NUM seconds before generating thumbnails (default: 2.0 + seconds) If a quoted string of values matching the number of videos + is used, then each video can use a different seek value If using + switched menus, the **-seek** value(s) will be used to generate the + showcase image that displays on switching to another video choice + with the up/down arrow keys. + +**-fast-seek** + Use faster seek method for ffmpeg. This is not as accurate as the + default method, and may produce grey frames. + +**-frame-safe** Instead of seeking and then outputting one frame for + previews and static menus, output 9 frames and choose the largest. + Not frame accurate (may be as much as 9 frames off), but safer. + Choose this if you are getting grey frames/thumbnails with some + videos. You can also use it to try to get the ’best’ frame. This + option has no effect on submenus at present. **-showcase-seek** NUM Seek to NUM seconds before generating thumbnails for showcase video @@ -748,96 +874,124 @@ Seek to NUM seconds before generating images for background video (default: 2.0 seconds) -**-bgaudio-seek**, **-bg-audio-seek** NUM - Seek to NUM seconds before generating audio for bgaudio - (default: 2.0 seconds) +**-bgaudio-seek**, \*\*-bg-audio-seek NUM + Seek to NUM seconds before generating audio for bgaudio (default: + 2.0 seconds) **-group** N VIDEO1 VIDEO2 . . . - Allow grouping videos in dvdauthor.xml, so they will play sequentially as - a group. The videos passed in after the 'N' will be grouped with the 'Nth' - video. Example:: + Allow grouping videos in dvdauthor.xml, so they will play + sequentially as a group. The videos passed in after the ’N’ will be + grouped with the ’Nth’ video. Example: - -group 2 2.mpg 3.mpg 4.mpg + :: - will group these 3 videos with the 2nd video given with **-files**, so that - they will play sequentially as one title. Only one thumbnail and/or title - will appear on the menu for the group: it will be made from the 1st video - in the group. In the above example if you passed:: + -group 2 2.mpg 3.mpg 4.mpg - -files foo.mpg bar.mpg baz.mpg -group 2 2.mpg 3.mpg 4.mpg + will group these 3 videos with the 2nd video given with **-files**, + so that they will play sequentially as one title. Only one thumbnail + and/or title will appear on the menu for the group: it will be made + from the 1st video in the group. In the above example if you passed: - then the group will consist of bar.mpg 2.mpg, 3.mpg and 4.mpg, and only the - title and/or thumbnail for bar.mpg will appear in the menu. You can use - **-group** more than once for multiple groups. Be sure to quote video - filenames if they contain spaces. + :: + + -files foo.mpg bar.mpg baz.mpg -group 2 2.mpg 3.mpg 4.mpg + + then the group will consist of bar.mpg 2.mpg, 3.mpg and 4.mpg, and + only the title and/or thumbnail for bar.mpg will appear in the menu. + You can use **-group** more than once for multiple groups. Be sure + to quote video filenames if they contain spaces. **-jobs** By default, **tovid disc** starts a parallel job for each processor - detected. With this option you can manually set the number of jobs. For - example if you have a computer with 2 CPUs you can set **-jobs 1** to keep - one processor free for other things. At present this applies to the time - consuming imagemagick loops: you will notice a substantial speedup now if - you have a multi-cpu system. + detected. With this option you can manually set the number of jobs. + For example if you have a computer with 2 CPUs you can set "-jobs 1" + to keep one processor free for other things. At present this applies + to the time consuming imagemagick loops: you will notice a + substantial speedup now if you have a multi-cpu system. -**-no-ask**, **-noask** - Skip all interactive questions. No preview, automatic re-encoding with - tovid if needed, no interactive option to use background video for bgaudio. +**-no-ask** | **-noask** + Skip all interactive questions. No preview, automatic re-encoding + with tovid if needed, no interactive option to use background video + for bgaudio. **-no-warn**, **-nowarn** - Don't pause after outputting warning or info messages + Don’t pause after outputting warning or info messages **-grid** - Show a second preview image with a grid and numbers that will help in finding - coordinates for options that might use them, like **-text-start** - + Show a second preview image with a grid and numbers that will help + in finding coordinates for options that might use them, like + **-text-start** Menu Style -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +---------- -**-menu-title-geo** north|south|east|west|center [south] - The position of the menu title. You may need to use **-align** as well if - you don't want your title covering other parts of your menu. See +**-menu-title-geo** +north|south|east|west|center|[south] + The position of the menu title. You may need to use -align as well + if you don’t want your title covering other parts of your menu. See **-align** **-menu-title-offset** OFFSET (+X+Y) - Move menu title by this offset from its N|S|E|W|Center position. You - may need to use **-align** as well if you don't want your title covering other - parts of your menu. See **-align** + Move menu title by this offset from its + N|S|E|W|Center position. You + may need to use -align as well if you don’t want your title covering + other parts of your menu. See **-align** **-button-style** rect|text|line|text-rect - The style of button that you will see when you play the DVD. "rect" draws - a rectangle around the thumb when you select it in the DVD player. "text" - highlights the video title text, "line" underlines the title, and - "text-rect" draws a rectangle around the title text. + The style of button that you will see when you play the DVD. "rect" + draws a rectangle around the thumb when you select it in the DVD + player. "text" highlights the video title text, "line" underlines + the title, and "text-rect" draws a rectangle around the title text. **-title-color**, **-title-colour** COLOR - Color to use for the main menu title. For list of supported colors do: - **convert -list** color. HTML notation may be used: "#ff0000". See: - http://www.imagemagick.org/script/color.php + Color to use for the main menu title. For list of supported colors + do: **convert -list** color. HTML notation may be used: "#ff0000". + See: {http://www.imagemagick.org/script/color.php} + {http://www.imagemagick.org/script/color.php} **-title-stroke** COLOR - Outline color for the main menu's title font. Use "none" for transparent - outline (see title-color) + Shadow color for the main menu’s title font. Use "none" for + transparent outline (see title-color). Note: this is not a -stroke + in the sense that imagemagick uses the term, but a shadow (the font + is drawn twice). To get a true imagemagick stroke see + **-title-font-deco** + +**-title-font-deco**, **-title-fontdeco** "IMAGEMAGICK STRING" + Sets the font decoration method to FONTDECORATION. It is used by the + ’convert’ ImageMagick command to draw the menu text. You can add + colored text outlines, gradient fills, and many others. See **Usage + notes** **-titles-stroke** COLOR - Outline color for the thumb or textmenu video titles font. Use "none" for - transparent outline (see **-titles-color**). + Shadow color for the thumb or textmenu video titles font. Use "none" + for transparent outline (see **-titles-color**). Note: this is not a + -stroke in the sense that imagemagick uses the term, but a shadow + (the font is drawn twice). To get a true imagemagick stroke, see + **-titles-font-deco** + +**-titles-font-deco**, **-titles-fontdeco** "IMAGEMAGICK STRING" + Sets the font decoration method to FONTDECORATION. It is used by the + ’convert’ ImageMagick command to draw the menu text. You can add + colored text outlines, gradient fills, and others. See **Usage + notes** for more info. **-highlight-color**, **-highlight-colour** - Color to use for the menu buttons that your DVD remote uses to navigate. + Color to use for the menu buttons that your DVD remote uses to + navigate. **-select-color**, **-select-colour** - Color to use for the menu buttons that your DVD remote uses to select. + Color to use for the menu buttons that your DVD remote uses to + select. **-text-mist** - Put a semi-transparent misted background behind the text for the menu's - title, just slightly larger than the text area. + Put a semi-transparent misted background behind the text for the + menu’s title, just slightly larger than the text area. **-text-mist-color**, **-text-mist-colour** COLOR - Color of the mist behind the menu's title (see title-color). + Color of the mist behind the menu’s title (see title-color). **-text-mist-opacity** - Opacity of the mist behind the menu's title - see **-opacity** + Opacity of the mist behind the menu’s title - see **-opacity** **-title-opacity** Opacity of the menu title text @@ -852,270 +1006,305 @@ Opacity of the text for submenu chapter titles **-menu-audio-fade** - Number of sec to fade given menu audio in and out (default: 1.0 seconds) - If you use **-menu-audio-fade** 0 then the audio will not be faded. + Number of sec to fade given menu audio in and out (default: 1.0 + seconds) If you use **-menu-audio-fade** 0 then the audio will not + be faded. **-submenu-audio-fade** - Number of secs to fade sub-menu audio in and out (default: 1.0 seconds). - See **-menu-audio-fade** + Number of secs to fade sub-menu audio in and out (default: 1.0 + seconds). See **-menu-audio-fade** **-intro** VIDEO - Use a introductory video that will play before the main menu. - At present it must be a DVD compatible video at the correct resolution etc. - Only 4:3 aspect is supported: 16:9 will give unexpected results. + Use a introductory video that will play before the main menu. At + present it must be a DVD compatible video at the correct resolution + etc. Only 4:3 aspect is supported: 16:9 will give unexpected + results. - -Showcase and textmenu -------------------------------------------------------------------------------- -The following menu style options are specific to showcase and textmenu arrangements: +Style options specific to showcase/textmenu arrangements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **-text-start** N - This option is for **-textmenu** menus. The titles will start at the Nth - pixel from the top of the menu ( Y axis ). + This option is for **-textmenu** menus. The titles will start at the + Nth pixel from the top of the menu ( Y axis ). **-title-gap** N - This option is for **-textmenu** menus. The gap is the space between + This option is for **-textmenu** menus. The gap is the space between titles vertically ( Y axis ). **-rotate** DEGREES Rotate the showcase image|video clockwise by DEGREES. - (default: if used without options, the rotate will be 5 degrees). Note: - this will not turn a portait image into a landscape image! + (default: if used without options, the rotate will be 5 degrees). + Note: this will not turn a portait image into a landscape image! **-showcase-geo** GEOMETRY - The position of the showcase image. ( XxY position ) + The position of the showcase image. ( XxY position ) **-wave** default|GEOMETRY - Wave effect for showcase image|video. Alters thumbs along a sine wave - using GEOMETRY. (default: no wave) "default" will produce a wave arg of - **-20x556**, which produces a gentle wave with a small amount of - distortion. See: http://www.imagemagick.org/Usage/distorts/#wave if you - want to try other values. - -**-showcase-shape** egg|oval|plectrum|arch|spiral|galaxy|flat-tube|normal - Apply a shaped transparency mask to showcase videos or images. - Note: if you wish to make your own mask PNGS you can put them in + Wave effect for showcase image|video. Alters thumbs along + a sine wave using GEOMETRY. (default: no wave) "default" will + produce a wave arg of -20x556, which produces a gentle wave with a + small amount of distortion. See: + {http://www.imagemagick.org/Usage/distorts/#wave} + {http://www.imagemagick.org/Usage/distorts/#wave} if you want to try + other values. + +**-showcase-shape** egg|oval|plectrum|arch|spiral|galaxy|flat-tube|normal + Apply a shaped transparency mask to showcase videos or images. Note: + if you wish to make your own mask PNGS you can put them in $PREFIX/lib/tovid/masks/ or $HOME/.tovid/masks/ and use them on the - command line using the filename minus the path and extension. - No frame is used for shaped thumbs. - -**-showcase-framestyle** none|glass - For **-showcase-** style template only - "none" will use the default frame method, using "convert -frame . . ." - "glass" will use mplayer to make frames, which gives an interesting - animated effect to the frames, and can be much faster ( especially if you - don't use **-rotate** or **-wave** as thumbs will not need to be processed - again after mplayer spits them out. Note: you need to be using either - **-showcase** IMAGE or **-showcase** VIDEO for this "frame style" to work. + command line using the filename minus the path and extension. No + frame is used for shaped thumbs. + +**-showcase-framestyle** none|glass + For -showcase-\* style template only "none" will use the default + frame method, using "convert -frame . . ." "glass" will use mplayer + to make frames, which gives an interesting animated effect to the + frames, and can be much faster ( especially if you don’t use + **-rotate** or **-wave** as thumbs will not need to be processed + again after mplayer spits them out. Note: you need to be using + either **-showcase** IMAGE or **-showcase** VIDEO for this "frame + style" to work. **-showcase-frame-size** PIXELS - The size of the showcase frame. This value will be used for both width and - height for the 'thickness' of the frame. This will also set the thickness - of the raised "frame" of the showcase thumb when you use **-3d-showcase**. - See also **-thumb-frame-size** and **-showcase-frame-color** + The size of the showcase frame. This value will be used for both + width and height for the ’thickness’ of the frame. This will also + set the thickness of the raised "frame" of the showcase thumb when + you use **-3d-showcase**. See also **-thumb-frame-size** and + **-showcase-frame-color** **-showcase-frame-color**, **-showcase-frame-colour** PIXELS - The color of the showcase frame. Use hexadecimal or named colors notation. - Remember to quote! ( '#ffac5f' ). + The color of the showcase frame. Use hexadecimal or named colors + notation. Remember to quote! ( ’#ffac5f’ ). **-3d-showcase**, **-3dshowcase** - This will give an illusion of 3D to the showcase thumb: dynamic lighting on - rounded thumbs, and a raised effect on rectangular thumbs. Try it ! + This will give an illusion of 3D to the showcase thumb: dynamic + lighting on rounded thumbs, and a raised effect on rectangular + thumbs. Try it ! +Thumbnail Style +--------------- -Thumbnail style -------------------------------------------------------------------------------- +**-user-thumbs** IMAGE + Supply your own images for menu buttons, rather than relying on + todisc to generate them from the video. They must be the same aspect + ratio as the videos in the titleset (4:3 or 16:9), as todisc will + resize them without checking and cropping. **-opacity** [0-100] (default 100) Opacity of thumbnail videos as a percentage (no percent sign). - Anything less than 100(%) is semi-transparent. Not recommended with dark - backgrounds. + Anything less than 100(%) is semi-transparent. Not recommended with + dark backgrounds. **-thumb-blur**, **-blur** NUM - The amount of feather blur to apply to the thumb-shape. The default is 1.0 - which will more or less keep the shape and produces transparency at the - edges. Choose float or integer values between 0.1 and 2.0. 3D thumbs are - set to a tiny blur, so this option doesn't affect the **-3dthumbs** option. + The amount of feather blur to apply to the thumb-shape. The default + is 1.0 which will more or less keep the shape and produces + transparency at the edges. Choose float or integer values between + 0.1 and 2.0. 3D thumbs are set to a tiny blur, so this option + doesn’t affect the **-3dthumbs** option. **-showcase-blur** NUM - The amount of 'feather' blur to apply to the showcase image/video. Choose - values between 0.1 and 2.0. This option has no effect on **-3d-showcase**. - See **-thumb-blur** for more info. + The amount of ’feather’ blur to apply to the showcase image/video. + Choose values between 0.1 and 2.0. This option has no effect on + **-3d-showcase**. See **-thumb-blur** for more info. **-align** north|south - This will align thumbs/titles north or south. - If **-align** south then menu title will align north, unless you manually - set one or both of **-menu-title-geo** or **-menu-title-offset**. + This will align thumbs/titles north or south. If **-align** south + then menu title will align north, unless you manually set one or + both of **-menu-title-geo** or **-menu-title-offset**. **-thumb-mist** [COLOR] - Use a mist behind thumbnails. The optional argument is the color of the - mist. This option helps with contrast. Be sure to set the font color - to an appropriate color if using a colored mist, and/or use a bold font. + Use a mist behind thumbnails. The optional argument is the color of + the mist. This option helps with contrast. Be sure to set the font + color to an appropriate color if using a colored mist, and/or use a + bold font. **-titles-color**, **-titles-colour** COLOR - Color to use for the thumb or textmenu titles. If your titles are not - clear enough or look washed out, try using a **-titles-stroke** that - is the same color as used with **-titles-color** (see **-title-color**) + Color to use for the thumb or textmenu titles. If your titles are + not clear enough or look washed out, try using a **-titles-stroke** + that is the same color as used with **-titles-color** (see + **-title-color**) **-showcase-titles-align** west|east (default: center [centre]) - The default is to center the text above the thumbnails. This option will - align the titles either to the left (west) or right (east). Aligning west - gives more space to the titles. Aligning east also does so, and as well - will facilitate using \n in your titles to achieve multi line titles. + The default is to center the text above the thumbnails. This option + will align the titles either to the left (west) or right (east). + Aligning west gives more space to the titles. Aligning east also + does so, and as well will facilitate using \n in + your titles to achieve multi line titles. **-tile-3x1**, **-tile3x1** - Use a montage tile of 3x1 instead of the usual 2x2 for 3 videos - ie.:: + Use a montage tile of 3x1 instead of the usual 2x2 for 3 videos ie. - [movie1] [movie2] [movie3] instead of: + [movie1] [movie2] [movie3] instead of: - [movie1] [movie2] + [movie1] [movie2] - [movie3] + [movie3] - This option only comes into play if the number of videos supplied equals 3 - Otherwise it will be silently ignored. Not used for **-showcase-\*** style. + This option only comes into play if the number of videos supplied + equals 3 Otherwise it will be silently ignored. Not used for + -showcase-\* style. **-tile-4x1**, **-tile4x1** - Same as **-tile-3x1** above, except use tile of 4x1. (one row of 4 videos) + Same as **-tile-3x1** above, except use tile of 4x1. (one row of 4 + videos) -**-thumb-columns** 3|4 - Same as **-tile-3x1** and **tile-4x1** above, except it accepts either '3' - (1 row of 3 thumbs), or '4' (one row of 4 thumbs) as an argument. This - alternative was added to help compact the gui layout. +\*\*-thumb-columns 3|4 + Same as **-tile-3x1** and tile-4x1\*\* above, except it accepts + either ’3’ (1 row of 3 thumbs), or ’4’ (one row of 4 thumbs) as an + argument. This alternative was added to help compact the gui layout. **-rotate-thumbs** DEGREE LIST ( list of degrees, one for each thumb ) - Rotate thumbs the given amount in degrees - can be positive or negative. - There must be one value for each file given with **-files**. - If the values are not the same distance from zero, the thumbs will be of - different sizes as images are necessarily resized *after* rotating. With - the default montage template - this will also resize the titles; with the - showcase template the titles will remain the same size. Example:: + Rotate thumbs the given amount in degrees - can be positive or + negative. There must be one value for each file given with + **-files**. If the values are not the same distance from zero, the + thumbs will be of different sizes as images are necessarily resized + \*after\* rotating. With the default montage template - this will + also resize the titles; with the showcase template the titles will + remain the same size. Example: - -rotate-thumbs -10 10 -10 10 -10 (for 5 files) + :: - **Note**: this option will not turn a portrait image into a landscape image! + -rotate-thumbs -10 10 -10 10 -10 (for 5 files) + \*\*Note: this option will not turn a portrait image into a + landscape image! Dvdauthor options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +----------------- **-loop** PAUSE - Pause in seconds at end of menu. Use "inf" if you wish indefinite pause. - Note: using "inf" with **-menu-fade** will disable the fadeout portion of - the fade. (default: "inf" for static menu, 10.0 seconds for animated.) + Pause in seconds at end of menu. Use "inf" if you wish indefinite + pause. Note: using "inf" with **-menu-fade** will disable the + fadeout portion of the fade. (default: "inf" for static menu, 10.0 + seconds for animated.) **-playall** - This option will create a button on the main menu that will allow going - right to the 1st title and playing all videos in succession before - returning to the main menu. If doing titlesets you can use this within - the **-vmgm** ... **-end-vmgm** options to allow playing ALL titlesets. - (If you want also to have a playall button in each titleset you could use - this option between each **-titleset** ... **-end-titleset** option or put - it outside of the vmgm and titlset options as a general option. + This option will create a button on the main menu that will allow + going right to the 1st title and playing all videos in succession + before returning to the main menu. If doing titlesets you can use + this within the **-vmgm** ... **-end-vmgm** options to allow playing + ALL titlesets. (If you want also to have a playall button in each + titleset you could use this option between each **-titleset** ... + **-end-titleset** option or put it outside of the vmgm and titlset + options as a general option. **-videos-are-chapters** - A button will be made on the main menu for each video, which you can use as - a chapter button. Selecting any video will play them all in order - starting with the selected one. + A button will be made on the main menu for each video, which you can + use as a chapter button. Selecting any video will play them all in + order starting with the selected one. **-chain-videos** NUM | N1-NN Without options this will chain all videos together so they play - sequentially without returning to the main menu, except for the last, which - will return. You can also specify which videos you want to behave this way - by number or by a range. ( ie. **-chain-videos** 1 2 4-6 ). + sequentially without returning to the main menu, except for the + last, which will return. You can also specify which videos you want + to behave this way by number or by a range. ( ie. **-chain-videos** + 1 2 4-6 ). **-subtitle-lang** "lang1 lang2 . . ." - This allows selectable subtitles in the DVD, assuming you have optional - subtitles muxed into your videos. Use 2 character language codes. - -**-audio-channel** "Video1_track Video2_track Video3_track . . ." - "VideoN_track" is the track number to use in a multi-track (multi-language) - mpeg: usually something like **-audio-channel** "1 0 1". The 1st track is - 0, 2nd is 1 . . . etc. If the tracks are 0. English 1.French, then the - above would make French the audio language on Video1 and Video3, and - English the audio language on Video2. You can check the mpeg with - "mplayer -v . . .". + This allows selectable subtitles in the DVD, assuming you have + optional subtitles muxed into your videos. Use 2 character language + codes. + +**-audio-channel** "Video1\_track Video2\_track Video3\_track . . ." + "VideoN\_track" is the track number to use in a multi-track + (multi-language) mpeg: usually something like **-audio-channel** "1 + 0 1". The 1st track is 0, 2nd is 1 . . . etc. If the tracks are 0. + English 1.French, then the above would make French the audio + language on Video1 and Video3, and English the audio language on + Video2. You can check the mpeg with "mplayer -v . . .". **-audio-lang** LANGUAGE CODES - Identify the audio tracks on the DVD. These language codes are used for - each video in the titleset. When you use the audio button on your DVD - remote the language name is displayed. Example: **-audio-lang** en fr + Identify the audio tracks on the DVD. These language codes are used + for each video in the titleset. When you use the audio button on + your DVD remote the language name is displayed. Example: + **-audio-lang** en fr **-aspect** 4:3|16:9 - This will output a <video aspect WIDTH:HEIGHT /> tag for the dvdauthor - xml file. It will affect all videos in the titleset. Example:: + This will output a <video aspect WIDTH:HEIGHT /> + tag for the dvdauthor xml file. It will affect all videos in the + titleset. Example: + + :: - -aspect 16:9 + -aspect 16:9 **-widescreen** nopanscan|noletterbox [nopanscan] - This will output a <video widescreen=nopanscan /> tag (for example) - for the dvdauthor xml file. It will affect all videos in the titleset. Use - in conjunction with **-aspect** if your dvd player is cropping your videos. - Example:: + This will output a <video widescreen=nopanscan + /> tag (for example) for the dvdauthor xml file. It will + affect all videos in the titleset. Use in conjunction with + **-aspect** if your dvd player is cropping your videos. Example: + + :: - -aspect 16:9 -widescreen + -aspect 16:9 -widescreen **-quick-nav** - This option will allow navigation of a menu with more than one titleset by - using the left and right arrow keys of your DVD remote. When you press - this key the highlight will go the next or previous title. If you are at - the end of a titleset the right key will go to the next titleset. If you - are at the beginning of a titleset, the left key will go to the previous - titleset. If no next or previous titleset it will cycle to the end or - beginning of the titlesets. + This option will allow navigation of a menu with more than one + titleset by using the left and right arrow keys of your DVD remote. + When you press this key the highlight will go the next or previous + title. If you are at the end of a titleset the right key will go to + the next titleset. If you are at the beginning of a titleset, the + left key will go to the previous titleset. If no next or previous + titleset it will cycle to the end or beginning of the titlesets. **-outlinewidth**, **-outline-width** WIDTH - For spumux outlinewidth variable. If there is a large gap between words in - a text button, this option may help. + For spumux outlinewidth variable. If there is a large gap between + words in a text button, this option may help. **-video-pause** PAUSE (single value or list) - The pause in seconds after playing a video title. This is useful for - slideshows: the 'slide' will remain on the screen for this length of time. - If you have grouped videos you should probably not pause the videos that - have a grouped title after it, but instead see **-grouped-video-pause**. - Note: if you provide a list of values they must be one for each video. + The pause in seconds after playing a video title. This is useful for + slideshows: the ’slide’ will remain on the screen for this length of + time. If you have grouped videos you should probably not pause the + videos that have a grouped title after it, but instead see + **-grouped-video-pause**. Note: if you provide a list of values they + must be one for each video. **-group-video-pause** PAUSE (single value or list) - The pause in seconds after a grouped video plays. If you wish to pause - after the whole group finishes, then only use a value greater than zero - for the last video in the group. If providing a list of values they must - equal the number of grouped videos. + The pause in seconds after a grouped video plays. If you wish to + pause after the whole group finishes, then only use a value greater + than zero for the last video in the group. If providing a list of + values they must equal the number of grouped videos. - -Burning the disc -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -**-burn** - Prompt to burn the DVD directory on completion. - -**-device** DEVICE [/dev/dvdrw] - Device to use for the burning program. - -**-speed** N - The speed to use for burning the disc. - - - -.. _command-mpg: +Usage notes +----------- + +The argument given to various \*-font options that set the font to use +must be one of the fonts listed by the command ’convert -list type’. +Please note that many of your installed fonts may not be available; if +you want to maximize the number of fonts available to todisc, download +and run {Anthony Thyssen’s} +{http://www.cit.gu.edu.au/~{}anthony/anthony.html} {imagick\_type\_gen} +{http://www.imagemagick.org/Usage/scripts/imagick\_type\_gen} script and +run it like this: imagick\_type\_gen > ~{}/.magick/type.xml. +If that doesn’t work, try imagick\_type\_gen > ~{}/.magick/type.mgk. + +Or you can specify a ttf font file directly to the \*-font options if +you don’t want to install fonts to ImageMagick. + +The \*-stroke options in todisc are not a stroke in the sense that +ImageMagick uses the term, but rather a font shadow (the text is drawn +twice) To get a truer Imagemagick -stroke try something like: +-title-font-deco "-stroke black" (or -titles-font-deco "-stroke black"). +The **-fontdeco** option is quite flexible and takes a lot of +ImageMagick’s *convert* options. Please refer to the tovid {wiki} +{http://tovid.wikia.com/wiki/Making\_a\_DVD\_with\_text\_menus} and +Anthony Thyssen’s guide for further explanation and examples. Command:mpg -=============================================================================== +----------- **tovid mpg** converts arbitrary video files into (S)VCD/DVD-compliant MPEG format, suitable for burning to CD/DVD-R for playback on a standalone DVD player. Usage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: +----- - tovid mpg [OPTIONS] -in INFILE -out OUTPREFIX +**tovid mpg** [*OPTIONS*] **-in** *INFILE* **-out** *OUTPREFIX* -Where *INFILE* is any multimedia video file, and *OUTPREFIX* is what -you want to call the output file, minus the file extension. *OPTIONS* -are additional customizations, described below. +Where *INFILE* is any multimedia video file, and *OUTPREFIX* is what you +want to call the output file, minus the file extension. *OPTIONS* are +additional customizations, described below. By default, you will (hopefully) end up with an NTSC DVD-compliant MPEG-2 video file; if you burn this file to a DVD-R, it should be @@ -1123,14 +1312,14 @@ For example: -``tovid mpg -in foo.avi -out foo_encoded`` - Convert 'foo.avi' to NTSC DVD format, saving to 'foo_encoded.mpg'. +{tovid mpg -in foo.avi -out foo\_encoded} + Convert ’foo.avi’ to NTSC DVD format, saving to ’foo\_encoded.mpg’. -``tovid mpg -pal -vcd foo.avi -out foo_encoded`` - Convert 'foo.avi' to PAL VCD format, saving to 'foo_encoded.mpg'. +{tovid mpg -pal -vcd foo.avi -out foo\_encoded} + Convert ’foo.avi’ to PAL VCD format, saving to ’foo\_encoded.mpg’. Basic options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +------------- **-v**, **-version** Print tovid version number only, then exit. @@ -1139,18 +1328,18 @@ Reduce output to the console. **-fake** - Do not actually encode; only print the commands (mplayer, mpeg2enc etc.) - that would be executed. Useful in debugging; have tovid give you the - commands, and run them manually. + Do not actually encode; only print the commands (mplayer, mpeg2enc + etc.) that would be executed. Useful in debugging; have tovid give + you the commands, and run them manually. **-ffmpeg** - Use ffmpeg for video encoding, instead of mplayer/mpeg2enc. Try this if - you have any problems with the default encoding method. Using this option, - encoding will be considerably faster. Currently does not work with - **-subtitles** or **-filters**. + Use ffmpeg for video encoding, instead of mplayer/mpeg2enc. Try this + if you have any problems with the default encoding method. Using + this option, encoding will be considerably faster. Currently does + not work with **-subtitles** or **-filters**. Television standards -------------------------------------------------------------------------------- +~~~~~~~~~~~~~~~~~~~~ **-ntsc** NTSC format video (USA, Americas) (default) @@ -1162,7 +1351,7 @@ PAL format video (Europe and others) Formats -------------------------------------------------------------------------------- +~~~~~~~ Standard formats, should be playable in most DVD players: @@ -1198,27 +1387,24 @@ **-bdvd** (720x480 NTSC, 720x576 PAL) BVCD-enhanced long-playing DVD -See kvcd.net (http://kvcd.net/) for details on the KVCD specification. Please -note that KVCD ("K Video Compression Dynamics") is the name of a compression -scheme that can be applied to any MPEG-1 or MPEG-2 video, and has little to -do with VCD ("Video Compact Disc"), which is the name of a standard video disc -format. +See {kvcd.net} {http://kvcd.net/} for details on the KVCD specification. +Please note that KVCD ("K Video Compression Dynamics") is the name of a +compression scheme that can be applied to any MPEG-1 or MPEG-2 video, +and has little to do with VCD ("Video Compact Disc"), which is the name +of a standard video disc format. Advanced options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +---------------- Aspect ratios -------------------------------------------------------------------------------- +~~~~~~~~~~~~~ -tovid automatically determines aspect ratio of the input video by playing it in -mplayer. If your video plays with correct aspect in mplayer, you should not -need to override the default tovid behavior. +tovid automatically determines aspect ratio of the input video by +playing it in mplayer. If your video plays with correct aspect in +mplayer, you should not need to override the default tovid behavior. -If mplayer does not play your video with correct aspect, you may provide an -explicit aspect ratio in one of several ways: - -**-aspect** *WIDTH*:*HEIGHT* - Custom aspect, where *WIDTH* and *HEIGHT* are integers. +If mplayer does not play your video with correct aspect, you may provide +an explicit aspect ratio in one of several ways: **-full** Same as **-aspect 4:3** @@ -1229,107 +1415,117 @@ **-panavision** Same as **-aspect 235:100** -The above are the intended INPUT aspect ratio. tovid chooses an optimal output -aspect ratio for the selected disc format (VCD, DVD, etc.) and does the -appropriate letterboxing or anamorphic scaling. Use **-widetv** to encode -for a widescreen monitor or TV. +**-aspect** *WIDTH***:***HEIGHT* + Custom aspect, where *WIDTH* and *HEIGHT* are integers. +The above are the intended INPUT aspect ratio. tovid chooses an optimal +output aspect ratio for the selected disc format (VCD, DVD, etc.) and +does the appropriate letterboxing or anamorphic scaling. Use **-widetv** +to encode for a widescreen monitor or TV. Video stream options -------------------------------------------------------------------------------- +~~~~~~~~~~~~~~~~~~~~ **-quality** *NUM* (default 6) - Desired output quality, on a scale of 1 to 10, with 10 giving the best - quality at the expense of a larger output file. Default is 6. Output size - can vary by approximately a factor of 4 (that is, **-quality 1** output - can be 1/4 the size of **-quality 10** output). Your results may vary. - WARNING: With **-quality 10**, the output bitrate may be too high for - your hardware DVD player to handle. Stick with 9 or lower unless you - have phenomenally good eyesight. - - At present, this option affects both output bitrate and quantization (but - may, in the future, affect other quality/size-related attributes). Use - **-vbitrate** if you want to explicitly provide a maximum bitrate. + Desired output quality, on a scale of 1 to 10, with 10 giving the + best quality at the expense of a larger output file. Default is 6. + Output size can vary by approximately a factor of 4 (that is, + **-quality 1** output can be 1/4 the size of **-quality 10** + output). Your results may vary. WARNING: With **-quality 10**, the + output bitrate may be too high for your hardware DVD player to + handle. Stick with 9 or lower unless you have phenomenally good + eyesight. + + At present, this option affects both output bitrate and quantization + (but may, in the future, affect other quality/size-related + attributes). Use **-vbitrate** if you want to explicitly provide a + maximum bitrate. **-vbitrate** *NUM* - Maximum bitrate to use for video (in kbits/sec). Must be within allowable - limits for the given format. Overrides default values. Ignored for VCD, - which must be constant bitrate. + Maximum bitrate to use for video (in kbits/sec). Must be within + allowable limits for the given format. Overrides default values. + Ignored for VCD, which must be constant bitrate. **-interlaced** - Do interlaced encoding of the input video (top fields first). Use this - option if your video is interlaced, and you want to preserve as much - picture quality as possible. This option is ignored for VCD, which - doesn't support it. + Do interlaced encoding of the input video (top fields first). Use + this option if your video is interlaced, and you want to preserve as + much picture quality as possible. This option is ignored for VCD, + which doesn’t support it. - You can tell your source video is interlaced by playing it, and pausing - during a scene with horizontal motion; if you see a "comb" effect at the - edges of objects in the scene, you have interlaced video. Use this option - to encode it properly. + You can tell your source video is interlaced by playing it, and + pausing during a scene with horizontal motion; if you see a "comb" + effect at the edges of objects in the scene, you have interlaced + video. Use this option to encode it properly. If you would prefer to have output in progressive format, use - **-progressive**. If you have a DV camera, use **-interlaced_bf** since - DV footage is generally bottom fields first. + **-progressive**. If you have a DV camera, use **-interlaced\_bf** + since DV footage is generally bottom fields first. -**-interlaced_bf** +**-interlaced\_bf** Do interlaced encoding of the input video (bottom fields first). -**-deinterlace** | **-progressive** - Convert interlaced source video into progressive output video. Because - deinterlacing works by averaging fields together, some picture quality is - invariably lost. Uses an adaptive kernel deinterlacer (kerndeint), or, - if that's not available, the libavcodec deinterlacer (lavcdeint). +**-deinterlace**, **-progressive** + Convert interlaced source video into progressive output video. + Because deinterlacing works by averaging fields together, some + picture quality is invariably lost. Uses an adaptive kernel + deinterlacer (kerndeint), or, if that’s not available, the + libavcodec deinterlacer (lavcdeint). **-mkvsub** *LANG* (EXPERIMENTAL) - Attempt to encode an integrated subtitle stream (such as may be found in - Matroska .mkv files) in the given language code (eng, jpn, etc.) May work - for other formats. + Attempt to encode an integrated subtitle stream (such as may be + found in Matroska .mkv files) in the given language code (eng, jpn, + etc.) May work for other formats. **-autosubs** - Automatically include subtitle files with the same name as the input video. + Automatically include subtitle files with the same name as the input + video. **-subtitles** *FILE* - Get subtitles from *FILE* and encode them into the video. WARNING: This - hard-codes the subtitles into the video, and you cannot turn them off while - viewing the video. By default, no subtitles are loaded. If your video is - already compliant with the chosen output format, it will be re-encoded to - include the subtitles. + Get subtitles from *FILE* and encode them into the video. WARNING: + This hard-codes the subtitles into the video, and you cannot turn + them off while viewing the video. By default, no subtitles are + loaded. If your video is already compliant with the chosen output + format, it will be re-encoded to include the subtitles. **-type** {live|animation|bw} - Optimize video encoding for different kinds of video. Use 'live' (default) - for live-action video, use 'animation' for cartoons or anime, and 'bw' for - black-and-white video. This option currently only has an effect with - KVCD/KSVCD output formats; other formats may support this in the future. + Optimize video encoding for different kinds of video. Use ’live’ + (default) for live-action video, use ’animation’ for cartoons or + anime, and ’bw’ for black-and-white video. This option currently + only has an effect with KVCD/KSVCD output formats; other formats may + support this in the future. **-safe** *PERCENT* Fit the video within a safe area defined by *PERCENT*. For example, - **-safe 90%** will scale the video to 90% of the width/height of the output - resolution, and pad the edges with a black border. Use this if some of the - picture is cut off when played on your TV. The percent sign is optional. + **-safe 90%** will scale the video to 90% of the width/height of the + output resolution, and pad the edges with a black border. Use this + if some of the picture is cut off when played on your TV. The + percent sign is optional. **-filters** {none,denoise,deblock,contrast,all} (default none) - Apply post-processing filters to enhance the video. If your input video is - very high quality, use 'none'. If your input video is grainy, use 'denoise'; - if it looks washed out or faded, use 'contrast'. You can use multiple - filters separated by commas. To apply all filters, use 'all'. + Apply post-processing filters to enhance the video. If your input + video is very high quality, use ’none’. If your input video is + grainy, use ’denoise’; if it looks washed out or faded, use + ’contrast’. You can use multiple filters separated by commas. To + apply all filters, use ’all’. **-fps** *RATIO* - Force input video to be interpreted as *RATIO* frames per second. May be - necessary for some ASF, MOV, or other videos. *RATIO* should be an - integer ratio such as "24000:1001" (23.976fps), "30000:1001" (29.97fps), or - "25:1" (25fps). This option is temporary, and may disappear in future - releases. (Hint: To convert a decimal like 23.976 to an integer ratio, just - multiply by 1000, i.e. 23976:1000) + Force input video to be interpreted as *RATIO* frames per second. + May be necessary for some ASF, MOV, or other videos. *RATIO* should + be an integer ratio such as "24000:1001" (23.976fps), "30000:1001" + (29.97fps), or "25:1" (25fps). This option is temporary, and may + disappear in future releases. (Hint: To convert a decimal like + 23.976 to an integer ratio, just multiply by 1000, i.e. 23976:1000) **-crop** *WIDTH*:*HEIGHT*:*X*:*Y* Crop a portion of the video *WIDTH* by *HEIGHT* in size, with the top-left corner at *X*, *Y*. **-widetv** - Always encode to 16:9 widescreen (only supported by **-dvd**, **-kdvd**, - **-bdvd**), for optimal viewing on a widescreen monitor or TV. + Always encode to 16:9 widescreen (only supported by **-dvd**, + **-kdvd**, **-bdvd**), for optimal viewing on a widescreen monitor + or TV. Audio stream options -------------------------------------------------------------------------------- +~~~~~~~~~~~~~~~~~~~~ **-normalize** Analyze the audio stream and then normalize the volume of the audio. @@ -1338,44 +1534,42 @@ normalize without any parameters. The default is -12dB average level with 0dB gain. -**-amplitude** *NUM[dB]* - In addition to analyzing and normalizing, apply the gain to the audio - such that the 'average' (RMS) sound level is *NUM*. Valid values - range 0.0 - 1.0, with 0.0 being silent and 1.0 being full scale. Use - *NUMdB* for a decibel gain below full scale (the default without - **-amplitude** is -12dB). +**-amplitude** *NUM*[dB] + In addition to analyzing and normalizing, apply the gain to the + audio such that the ’average’ (RMS) sound level is *NUM*. Valid + values range 0.0 - 1.0, with 0.0 being silent and 1.0 being full + scale. Use *NUM*dB for a decibel gain below full scale (the default + without -amplitude is -12dB). **-abitrate** *NUM* - Encode audio at *NUM* kilobits per second. Reasonable values include - 128, 224, and 384. The default is 224 kbits/sec, good enough for most - encodings. The value must be within the allowable range for the chosen disc - format; Ignored for VCD, which must be 224. + Encode audio at *NUM* kilobits per second. Reasonable values include + 128, 224, and 384. The default is 224 kbits/sec, good enough for + most encodings. The value must be within the allowable range for the + chosen disc format; Ignored for VCD, which must be 224. **-audiotrack** *NUM* - Encode the given audio track, if the input video has multiple audio tracks. - *NUM* is *1* for the first track, *2* for the second, etc. You may - also provide a list of tracks, separated by spaces or commas, for example - **-audiotrack 3,1,2**. Use **tovid id** on your source video to determine - which audio tracks it contains. + Encode the given audio track, if the input video has multiple audio + tracks. *NUM* is *1* for the first track, *2* for the second, etc. + You may also provide a list of tracks, separated by spaces or + commas, for example **-audiotrack 3,1,2**. Use **tovid id** on your + source video to determine which audio tracks it contains. **-downmix** - Encode all audio tracks as stereo. This can save space on your DVD if - your player only does stereo. The default behavior of tovid is to use - the original number of channels in each track. For aac audio, downmixing - is not possible: tovid runs a quick 1 frame test to try to downmix the - input track with the largest number of channels, and if it fails then it - will revert to the default behavior of using the original channels. - -**-async** *NUM* - Adjust audio synchronization by *NUM* seconds. + Encode all audio tracks as stereo. This can save space on your DVD + if your player only does stereo. The default behavior of tovid is to + use the original number of channels in each track. For aac audio, + downmixing is not possible: tovid runs a quick 1 frame test to try + to downmix the input track with the largest number of channels, and + if it fails then it will revert to the default behavior of using the + original channels. Other options -------------------------------------------------------------------------------- +~~~~~~~~~~~~~ **-config** *FILE* - Read configuration from *FILE*, containing 'tovid' alone on the first - line, and free-formatted (whitespace-separated) tovid command-line options - on remaining lines. + Read configuration from *FILE*, containing ’tovid’ alone on the + first line, and free-formatted (whitespace-separated) tovid + command-line options on remaining lines. **-force** Force encoding of already-compliant video or audio streams. @@ -1385,85 +1579,82 @@ **-out** option). **-priority** {low|medium|high} - Sets the main encoding process to the given priority. With high priority, - it may take other programs longer to load and respond. With lower priority, - other programs will be more responsive, but encoding may take 30-40% - longer. The default is high priority. + Sets the main encoding process to the given priority. With high + priority, it may take other programs longer to load and respond. + With lower priority, other programs will be more responsive, but + encoding may take 30-40% longer. The default is high priority. **-discsize** *NUM* - When encoding, tovid automatically splits the output file into several - pieces if it exceeds the size of the target media. This option sets the - desired target DVD/CD-R size to *NUM* mebibytes (MiB, 2^20). By default, - splitting occurs at 700 for CD, 4300 for DVD. Use higher values at your - own risk. Use 650 or lower if you plan to burn to smaller-capacity CDs. - Doesn't work with the **-ffmpeg** option. + When encoding, tovid automatically splits the output file into + several pieces if it exceeds the size of the target media. This + option sets the desired target DVD/CD-R size to *NUM* mebibytes + (MiB, 2^20). By default, splitting occurs at 700 for CD, 4300 for + DVD. Use higher values at your own risk. Use 650 or lower if you + plan to burn to smaller-capacity CDs. Doesn’t work with the + **-ffmpeg** option. **-fit** *NUM* Fit the output file into *NUM* MiB. Rather than using default (or - specified) video bitrates, tovid will calculate the correct video bitrate - that will limit the final output size to *NUM* MiB. This is different - than **-discsize**, which cuts the final file into *NUM* MiB pieces. - **-fit** makes sure that the file never exceeds *NUM* MiB. This works - with **-ffmpeg**, but not with **-vcd** since VCDs have a standardized - constant bitrate. + specified) video bitrates, tovid will calculate the correct video + bitrate that will limit the final output size to *NUM* MiB. This is + different than **-discsize**, which cuts the final file into *NUM* + MiB pieces. **-fit** makes sure that the file never exceeds *NUM* + MiB. This works with **-ffmpeg**, but not with **-vcd** since VCDs + have a standardized constant bitrate. **-parallel** - Perform ripping, encoding, and multiplexing processes in parallel using - named pipes. Maximizes CPU utilization and minimizes disk usage. Note that - this option simply does more tasks simultaneously, in order to make better - use of available CPU cycles; it's unrelated to multi-CPU processing (which - is done automatically anyway). Has no effect when **-ffmpeg** is used. + Perform ripping, encoding, and multiplexing processes in parallel + using named pipes. Maximizes CPU utilization and minimizes disk + usage. Note that this option simply does more tasks simultaneously, + in order to make better use of available CPU cycles; it’s unrelated + to multi-CPU processing (which is done automatically anyway). Has no + effect when **-ffmpeg** is used. **-update** *SECS* - Print status updates at intervals of *SECS* seconds. This affects how - regularly the progress-meter is updated. The default is once every five - seconds. + Print status updates at intervals of *SECS* seconds. This affects + how regularly the progress-meter is updated. The default is once + every five seconds. -**-mplayeropts** "**OPTIONS**" - Append *OPTIONS* to the mplayer command run during video encoding. Use - this if you want to add specific video filters (documented in the mplayer - manual page). Overriding some options will cause encoding to fail, so use - this with caution! +**-mplayeropts** **"***OPTIONS***"** + Append *OPTIONS* to the mplayer command run during video encoding. + Use this if you want to add specific video filters (documented in + the mplayer manual page). Overriding some options will cause + encoding to fail, so use this with caution! **-nofifo** (EXPERIMENTAL) - Do not use a FIFO pipe for video encoding. If you are getting "Broken pipe" - errors with normal encoding, try this option. WARNING: This uses lots of - disk space (about 2 GB per minute of video). + Do not use a FIFO pipe for video encoding. If you are getting + "Broken pipe" errors with normal encoding, try this option. WARNING: + This uses lots of disk space (about 2 GB per minute of video). **-keepfiles** - Keep the intermediate files after encoding. Usually, this means the audio - and video streams are kept (eg the .ac3 and .m2v files for an NTSC DVD). - This doesn't work with **-parallel** because the intermediate files are named - pipes, and not real files. + Keep the intermediate files after encoding. Usually, this means the + audio and video streams are kept (eg the .ac3 and .m2v files for an + NTSC DVD). This doesn’t work with -parallel because the intermediate + files are named pipes, and not real files. **-slice** *START*-*END* Encode a segment from *START* to *END* (in seconds). Only works with - **-ffmpeg**. + -ffmpeg. **-from-gui** - Put makempg into a fully non-interactive state, suitable for calling from - a gui. + Put makempg into a fully non-interactive state, suitable for calling + from a gui. **-noask** - Don't ask questions when choices need to be made. Assume reasonable + Don’t ask questions when choices need to be made. Assume reasonable answers. - -.. _command-id: - Command:id -=============================================================================== +========== -**tovid id** identifies each multimedia video file in a -list, and reports its compliance with video disc standards such as VCD, -SVCD, and DVD. +**tovid id** identifies each multimedia video file in a list, and +reports its compliance with video disc standards such as VCD, SVCD, and +DVD. Usage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: +----- - tovid id [OPTIONS] VIDEO_FILE(s) +**tovid id** [*OPTIONS*] *VIDEO\_FILE(s)* For example: @@ -1471,37 +1662,39 @@ ``tovid id -tabluar videos/*.mpg`` Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +------- **-terse** - Print raw video characteristics, no formatting. Helpful when - calling from other scripts. + Print raw video characteristics, no formatting. Helpful when calling + from other scripts. **-verbose** Print extra information from mplayer, tcprobe, and ffmpeg. **-accurate** - Do lengthy play-time estimation by scanning through the entire video file. - Use this if the default behavior is giving you inaccurate play times. + Do lengthy play-time estimation by scanning through the entire video + file. Use this if the default behavior is giving you inaccurate play + times. **-fast** Skip lengthy play-time estimation, and go with what mplayer reports as being the video duration. Unlike pre-0.32 versions of tovid, this - is now the default behavior, and the **-fast** option doesn't do anything. + is now the default behavior, and the **-fast** option doesn’t do + anything. **-tabular** Display output in a table format for easier comparison. Most useful when identifying multiple video files. -**-isformat** [pal-dvd|ntsc-dvd] (same syntax for vcd and svcd) - Check *VIDEO_FILE* for compliance with the given disc format. - If *VIDEO_FILE* matches the given format, then **tovid id** reports "true" - and exits successfully. Otherwise, **tovid id** reports "false" and exits - with status 1 (failure). This checks and reports both vcd/svcd/dvd - and pal/ntsc. +**-isformat** [*pal-dvd*|*ntsc-dvd*] (same syntax for vcd and svcd) + Check *VIDEO\_FILE* for compliance with the given disc format. If + *VIDEO\_FILE* matches the given format, then **tovid id** reports + "true" and exits successfully. Otherwise, **tovid id** reports + "false" and exits with status 1 (failure). This checks and reports + both vcd/svcd/dvd and pal/ntsc. Examples -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------- ``tovid id -verbose homevideo.avi`` Report everything mplayer, ffmpeg, and transcode can determine about @@ -1510,528 +1703,102 @@ ``tovid id -isformat dvd homevideo.mpg`` Check to see if homevideo.mpg is compliant with the DVD standard. - -.. _command-menu: - -Command:menu -=============================================================================== - -**tovid menu** generates textual (S)VCD- or DVD-compliant MPEG videos for use -as navigational menus, given a list of text strings to use for title names. You -can customize the menu by providing an optional background image or audio clip, -or by using custom font and font color. - -Usage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - tovid menu [OPTIONS] TITLES -out OUT_PREFIX - -For example: - -``tovid menu "Season One" "Season Two" "Featurettes" -out MainMenu`` - -Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -**-ntsc** (default) - Generate an NTSC-format menu - -**-ntscfilm** - Generate an NTSC-format menu (24000/1001fps) - -**-pal** - Generate a PAL-format menu - -**-dvd** (default) - Generate a DVD-format menu, with highlighted text included - as a multiplexed subtitle stream. - -**-vcd** or **-svcd** - Generate a VCD/SVCD menu; each menu option will have a - number associated with it. You can have up to nine menu - options per menu. - -Menu background/audio options: - -**-background** *IMAGE* - Use *IMAGE* (in most any graphic format) as a background. If image is not - the correct aspect ratio (4:3), it will be scaled and/or cropped, - depending on the **-crop** and **-scale** options. If no background is - supplied, a default background will be created. - -**-crop** (default) - If provided background image is not 4:3 aspect ratio, crop edges - to make it so. Image will be scaled up if it is too small. Cropping - keeps the center area of image. If you want to do cropping/scaling - yourself in another program, provide an image of 768x576 pixels. - -**-scale** - If provided background image is not 4:3 aspect ratio, scale/stretch - it to make it fit. May cause visible distortion! - -**-audio** *AUDIOFILE* - Use *AUDIOFILE* (in most any audio format) for background music. The - menu will play for long enough to hear the whole audio clip. If - one is not provided, 4 seconds of silence will be used. - -**-length** *NUM* - Make the menu *NUM* seconds long. Useful for menus with **-audio**: - if you don't want the entire *AUDIOFILE* in the menu, then you can trim - the length of the menu with **-length**. - -Menu text options: - -**-menu-title** "*MENU TITLE TEXT*" - Add *MENU TITLE TEXT* as a title/header to the menu. - -**-font** *FONTNAME* (default Helvetica) - Use *FONTNAME* for the menu text. Run 'convert -list type' to see a - list of the fonts that you can use; choose a font name from the - leftmost column that is displayed. Or you can specify a ttf font file instead. - E.g., **-font /path/to/myfont.ttf**. - -**-fontsize** *NUM* (default 24) - Sets the size for the font to *NUM* pixels. - -**-menu-title-fontsize** *NUM* (default **-fontsize** + 8) - Sets the size of the menu title. - -**-fontdeco** '*FONTDECORATION*' - Sets the font decoration method to *FONTDECORATION*. It is used by the - 'convert' ImageMagick command to draw the menu text. You can add colored - text outlines, gradient fills, and many others. See **Usage notes**. - -**-align** {left|center|middle|right} - Align the text at the top left, top center, very middle, or top right - side of the screen. You may also substitute any "gravity" keyword - allowed by ImageMagick (north|south|east|west|northeast|southwest|...). - -**-textcolor** {#RRGGBB|#RGB|COLORNAME} - Use specified color for menu text. #RRGGBB and #RGB are - hexadecimal triplets (e.g., #FF8035). COLORNAME may be any of - several hundred named colors; run 'convert -list color' to see them. - White (#FFF) is the default color. - -DVD-only options: - -**-button** *BUTTON* (default '>') - Specify the button used for menu selection. Specify either a *single* - character or one of the shortcuts: - - **play** - Use a button shaped like 'Play' on many A/V electronics: - a triangle pointing to the right. (uses the font Webdings) - **movie** - Use a button shaped like an old movie projector. - (uses the font Webdings) - **utf8** - Use your own non-keyboard character as a button. Provide - only the four hex digits: eg **-button utf8 00b7**. Beware that - ImageMagick's utf8 characters aren't the same as those drawn in - character browsers like gucharmap. - -**-highlightcolor** {#RRGGBB|#RGB|COLORNAME} - Use the specified color for button highlighting. Yellow (#FF0) is the - default color. - -**-selectcolor** {#RRGGBB|#RGB|COLORNAME} - Use the specified color for button selections (when a menu item is played - or activated). Red (#F00) is the default color. - -**-button-outline** {#RRGGBB|#RGB|COLORNAME} - Outline buttons with the specified color. 'none' is the default. - -**-button-font** *FONTNAME* - Specify a differnt font to use for the buttons. By default, the button - font will be inherited from the title font (see **-font**). Use this - option to use a different font for the buttons. The button font size is - inherited from **-fontsize** and cannot be changed. - -Other options: - -**-debug** - Print extra debugging information to the log file. Useful in - diagnosing problems if they occur. This option also leaves - the log file (with a .log extension) in the directory after - encoding finishes as well as all the temporary files created. - -**-nosafearea** - Do not attempt to put text inside a TV-safe viewing area. Most - television sets cut off about 10% of the image border, so the script - automatically leaves a substantial margin. This option turns that - behavior off, leaving only a tiny margin. Use at your own risk. - -**-overwrite** - Overwrite any existing output menu. - -**-noask** - Don't ask interactive questions, and assume answers that will - continue making the menu until completion. - -**-quiet** - Limit output to essential messages. - -If the word "**back**" is given as an episode title, a "back" button for -returning to a higher-level menu will be added at the end of the list -of titles. "**Back**" *must be the last title listed*. - -Examples -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Make an NTSC VCD menu with white Helvetica text containing three centered -selections: Episode 1, Episode 2, and Episode 3. The finished menu will be -called Season-1.mpg:: - - $ tovid menu -ntsc -vcd \ - -align center -textcolor white -font "Helvetica" \ - "Episode 1" "Episode 2" "Episode 3" \ - -out "Season-1" - -Make an NTSC DVD menu with white Kirsty text containing three lower-left -aligned selections: Episode 1, Episode 2, and Episode 3. Items under the cursor -will be highlighted a pale blue, and selected items will be a pale orange -(before going to the selected title). The finished menu will be called -Main-menu.mpg:: - - $ tovid menu -ntsc -dvd \ - -align southwest \ - -textcolor white \ - -highlightcolor "#5f65ff" \ - -selectcolor "#ffac5f" \ - -font "Kirsty" \ - "Episode 1" "Episode 2" "Episode 3" \ - -out "Main_menu" - -Usage notes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The argument given to **-font** must be one of the fonts listed by the command -'convert -list type'. Please note that many of your installed fonts may not be -available; if you want to maximize the number of fonts available, download and -run Anthony Thyssen's (http://www.cit.gu.edu.au/~anthony/anthony.html) -imagick_type_gen.pl (http://www.cit.gu.edu.au/~anthony/software/imagick_type_gen.pl) -script and run it like this:: - - imagick_type_gen.pl > ~/.magick/type.xml. - -If that doesn't work, try:: - - imagick_type_gen.pl > ~/.magick/type.mgk. - -Or you can specify a ttf font file directly to the **-font** options if you -don't want to install fonts to ImageMagick. - -The **-fontdeco** option is quite flexible and takes a lot of ImageMagick's -*convert* options. Please refer to the tovid wiki -(http://tovid.wikia.com/wiki/Making_a_DVD_with_text_menus) -and Anthony Thyssen's guide for further explanation and examples. - - -.. _command-xml: - -Command:xml -=============================================================================== - -**tovid xml** generates XML output describing an (S)VCD -or DVD file structure and navigation hierarchy in the format expected by -dvdauthor (http://dvdauthor.sourceforge.net/) or -vcdxbuild (http://www.vcdimager.org/). - -Usage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - tovid xml [OPTIONS] VIDEOS -out OUTFILE - -For example:: - - tovid xml -menu MainMenu.mpg \ - Season1.mpg Season2.mpg Featurettes.mpg \ - -out MyDisc - -Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -**-dvd** (default) - Generate the XML for a DVD disc, to be used with dvdauthor or **tovid dvd**. - -**-vcd** - Generate the XML for a VCD disc, to be used with vcdxbuild or **tovid vcd**. - -**-svcd** - Generate the XML for an SVCD disc, to be used with vcdxbuild or **tovid vcd**. - -**-overwrite** - Overwrite any existing output files. - -**-quiet** - Limit output to essential messages. - -*VIDEOS* may be any of the following: - -*<file list>* - List of one or more video files to include, separated by spaces. At - minimum, a DVD must have one video file. You can use shell wildcards - (i.e., "\*.mpg") to include multiple files easily. Put filenames in - quotes if they have spaces in them. - -**-menu** *VIDEO* *<file list>* - Use video file *VIDEO* as a menu from which you can jump to each of - the listed video files. If you have multiple menus, include a - top menu so they are reachable. - -**-slides** *<file list>* - Create a slide-show of still images - -DVD-only options - -**-group** *<file list>* **-endgroup** - (DVD only) List of video files to include as one single title. This is useful - if you have split a movie into several video files. - -**-topmenu** *VIDEO* [**-menu** *VIDEO* *<file list>*] [**-menu** *VIDEO* *<file list>*]... - (DVD only) Use video file *VIDEO* for the top-level (VMGM) menu. The - top menu will jump to each of the subsequent [-menu...] videos listed. - Use this only if you have multiple sub-menus to jump to. You can only - have one top menu. - -**-titlesets** - (DVD only) Forces the creation of a separate titleset per title. This - is useful if the titles of a DVD have different video formats, - e.g. PAL + NTSC or 4:3 + 16:9. If used with menus, there must be a - **-topmenu** option that specifies a menu file with an entry for each of the - titlesets. - -**-chapters** *INTERVAL* - (DVD only) Creates a chapter every *INTERVAL* minutes (default 5 minutes: - without **-chapters**, each movie will be divided into 5-minute chapters). - This option can be put at any position in a *<file list>* and is valid - for all subsequent titles until a new **-chapters** option is encountered. - Using this option may take some time, since the duration of the video is - calculated. - -**-nochapters** - (DVD only) Don't create chapters for the videos. - -*OUT_PREFIX* is the file that will receive the resulting XML. - -Usage notes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The 'xml' command checks to make sure the video filenames you -give it exist, but it does not check whether they are valid for the -chosen disc format. MPEG videos of menus should have the specified -number of buttons for reaching each of the videos, and, if you're -using DVD, should be multiplexed with their corresponding subtitles -using spumux of the dvdauthor 0.6.0 package prior to -authoring using dvdauthor. If you use the 'tovid menu' -component to generate the menu, this should all be handled for you. - -Examples -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``tovid xml -dvd title-1.mpg title-2.mpg title-3.mpg -out My_DVD`` - Make a DVD without a menu. Title 1, 2, and 3 will play in sequence. - -``tovid xml -dvd -group chapter-1.mpg chapter-2.mpg chapter-3.mpg -endgroup -out My_DVD`` - Group the file chapter-1|2|3.mpg into one title and make a DVD without a menu. - -``tovid xml -dvd -menu main_menu.mpg -chapters 3 movie-1.mpg -chapters 10 movie-2.mpg -out My_DVD`` - Make a DVD with a main menu that points to two movies, with movie-1.mpg - divided into 3-minute chapters, and movie-2.mpg into 10-minute chapters. - - -.. _command-dvd: - Command:dvd -=============================================================================== +=========== -**tovid dvd** takes a dvdauthor XML file (as generated by the **tovid xml** -command) and authors a DVD filesytem. This command can also burn a DVD disc -from either the XML file or from an existing DVD file-system. +**tovid dvd** takes a dvdauthor XML file (as generated by the **tovid +xml** command) and authors a DVD filesytem. This command can also burn a +DVD disc from either the XML file or from an existing DVD file-system. To ensure that this script successfully executes, please run it from a -directory with plenty of free space. "Plenty" would be 10 GB for single-layer -discs, and 20 GB for dual-layer discs. Running this program may slow down your -other applications, due to intense disk activity. +directory with plenty of free space. "Plenty" would be 10 GB for +single-layer discs, and 20 GB for dual-layer discs. Running this program +may slow down your other applications, due to intense disk activity. Usage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: +----- - tovid dvd [OPTIONS] FILE.xml - tovid dvd [OPTIONS] DVD_DIR +**tovid dvd** [*OPTIONS*] *DVD\_DIR* **tovid dvd** [*OPTIONS*] +*FILE.xml* For example: -``tovid dvd -burn MyDisc.xml`` ``tovid dvd -burn /path/to/DVD/directory`` +``tovid dvd -burn MyDisc.xml`` Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +------- **-author** Author the DVD described by *FILE.xml*. Overwrites an existing directory containing the dvdauthor output if already present. **-burn** - Burn a DVD file-system in *DVD_DIR* (must contain a VIDEO_TS folder). + Burn a DVD file-system in *DVD\_DIR* (must contain a VIDEO\_TS + folder). + +**-eject** + Eject the DVD tray after burning is complete. By default, the DVD is + not ejected. **-device** *DEVICE* (default /dev/dvdrw) - Burn the disc image to *DEVICE*, the Linux device file-system - name of your DVD-recorder. Common examples might be /dev/dvdrw, - /dev/scd1, and /dev/hdc. You can also use a bus/id/lun triple - such as ATAPI:0,1,0 + Burn the disc image to *DEVICE*, the Linux device file-system name + of your DVD-recorder. Common examples might be /dev/dvdrw, + /dev/scd1, and /dev/hdc. You can also use a bus/id/lun triple such + as ATAPI:0,1,0 **-speed** *NUM* (default 1) Burn disc at speed *NUM*. -**-label** *DISC_LABEL* - Uses *DISC_LABEL* as the volume ID. This appears as the mount - name of the disc on some computer platforms. Must be <=32 +**-label** *DISC\_LABEL* + Uses *DISC\_LABEL* as the volume ID. This appears as the mount name + of the disc on some computer platforms. Must be <=32 alphanumeric digits without spaces. **-quiet** Limit output to essential messages. **-noask** - Don't ask interactive questions and assume answers that will continue - execution. + Don’t ask interactive questions and assume answers that will + continue execution. Examples -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------- ``tovid dvd -burn -device /dev/dvdrw foo.xml`` Author the dvd file-system and burn to /dev/dvdrw. This will - automatically call dvdauthor to make the file-system. **-author** - is not explicitly needed. If there's an existing file-system, it - will be burned. + automatically call dvdauthor to make the file-system. **-author** is + not explicitly needed. If there’s an existing file-system, it will + be burned. ``tovid dvd -author foo.xml`` Author the DVD file-system and exit without burning. If the output directory given in foo.xml already exists, then the contents are - removed before authoring. At this point, the DVD can be previewed - by calling ``xine dvd:/path/to/output/directory``. - - -.. _command-vcd: - -Command:vcd -=============================================================================== - -**tovid vcd** takes an XML file (which may be generated by **tovid xml**) and -creates a cue/bin (S)VCD image. It can also burn (S)VCD discs. - -To ensure that this script successfully executes, please run it from a directory -with plenty of free space. "Plenty" would be about 1 GB. Running this program -may slow down your other applications, due to intense disk activity. - -Usage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - tovid vcd [OPTIONS] VCDIMAGER.xml - -For example: - -``tovid vcd -burn MyDisc.xml`` - -Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -**-overwrite** (default off -- nothing is overwritten) - Overwrite any existing cue/bin files matching *VCDIMAGER.xml*. Useful - if you modified the xml file and wish to re-image or burn the new (S)VCD. - -**-burn** (default off -- no images are burned) - Burn the (S)VCD described by *VCDIMAGER.xml*. + removed before authoring. At this point, the DVD can be previewed by + calling ***xine** dvd:/path/to/output/directory*. -**-device** *DEVICE* (default /dev/cdrw) - Burn the disc image to *DEVICE*, the Linux device file-system - name of your CD-recorder. Common examples might be /dev/cdrw, - /dev/scd1, and /dev/hdc. +Command:chapters +================ -**-speed** *NUM* (default 12) - Burn the disc at speed *NUM*. +**tovid chapters** will start a GUI using mplayer to set chapter points +in a video. If the video plays through and you want to add more chapters +you can press the play button again, but remember that new chapter +points will be appended (in correct sequential order). It will display +the resulting chapter points, and also output to a terminal (useful for +scripts). As well it will give the option of saving the chapters string +to a text file. -**-quiet** - Limit output to essential messages. +Note that the ’tovid gui’ now features a similar widget when you press +the chapters button on the opening page. Examples -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``tovid vcd -burn -device /dev/cdrw foo.xml`` - Create the (S)VCD image and burn it to /dev/cdrw. This will - automatically call vcdxbuild to make the image. If there is an existing - image, it will be burned. - -``tovid vcd -overwrite foo.xml`` - Create the (S)VCD image and exit without burning. If the image - already exists, then it is removed before re-imaging. - - -.. _command-postproc: - -Command:postproc -=============================================================================== - -**tovid postproc** is designed to do simple post-processing on MPEG video files, such -as those generated by tovid. It can adjust audio/video sync, and re-quantize -(shrink) without re-encoding. - -Usage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - tovid postproc [OPTIONS] IN_FILE OUT_FILE - -Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -**-audiodelay** *NUM* - Delay the audio stream by *NUM* milliseconds. Use this if - your final output has audio that is not synced with the - video. For example, if the audio comes 2 seconds sooner than - the video, use **-audiodelay 2000**. Use a negative number for - audio that comes later than the video. - -**-normalize** - Analyze the audio stream and then normalize the volume of the audio. - This is useful if the audio is too quiet or too loud, or you want to - make volume consistent for a bunch of videos. Similar to running - normalize without any parameters. The default is -12dB average level - with 0dB gain. - -**-amplitude** *NUM[dB]* - In addition to analyzing and normalizing, apply the gain to the audio - such that the 'average' (RMS) sound level is *NUM*. Valid values - range 0.0 - 1.0, with 0.0 being silent and 1.0 being full scale. Use - *NUMdB[dB]* for a decibel gain below full scale (the default without - -amplitude is -12dB). - -**-shrink** *NUM* - Shrink the video stream by a factor of *NUM*. May be a decimal - value. A value of 1.0 means the video will be the same size; - larger values cause more reduction in size. Beyond 2.0, the - returns are diminishing. - -**-parallel** - Run all processes in parallel and pipe into multiplexer, should - increase speed significantly. - -**-debug** - Save output in a temporary file, for later viewing if - something goes wrong. +-------- -Contact -=============================================================================== +``tovid chapters foo.avi`` +{chapters=$(tovid chapters /home/grepper/videos/foo.avi)} -For further assistance, contact information, forum and IRC links, -please refer to the tovid homepage (http://tovid.wikia.com/). +CONTACT +======= +For further assistance, contact information, forum and IRC links, please +refer to the {tovid homepage} {http://tovid.wikia.com/}.
View file
tovid-0.34.tar.bz2/docs/src/en/tovid.t2t -> tovid-0.35.tar.gz/docs/src/en/tovid.t2t
Changed
@@ -13,11 +13,16 @@ author and burn a ready-to-watch DVD, with just a few shell commands. A graphical interface is also provided to make the process even easier. -**NOTE**: As of tovid 0.32, this is the only manual page provided by tovid. +**NOTE**: As of tovid 0.35, the legacy scripts **makemenu** and **makexml** +have been removed and no longer appear in this manpage. +All of their functions and more can be done with the 'tovid disc' command, +(todisc script). See **Command:disc** and the [wiki http://tovid.wikia.com] +for more info. + +Also note that as of tovid 0.32, this is the only manual page provided by tovid. There is now a single executable frontend to all functionality in the suite, so -if you were expecting to find manpages for **todisc**, **idvid**, **makemenu** +if you were expecting to find manpages for **todisc**, **idvid**, **makempg** and their kin, they can all be found in the **tovid** manpage you are reading now. - And yes, this makes for a pretty large manual page. If you are viewing this manpage from the command-line **man** utility, which normally pages through the **less** utility, you can skip to a section by searching with the **/** key, @@ -32,31 +37,27 @@ Where //COMMAND// is one of the following: + Main Commands +: **disc** + Encode, make menus, author, burn. (was **todisc**. See **Command:disc**) : **gui** Start the tovid GUI (was **todiscgui**. See **Command:gui**) : **titlesets** - A tovid GUI wizard for multiple titlesets. (new: See **Command:titlesets**) -: **disc** - Create a DVD with menus (was **todisc**. See **Command:disc**) + A GUI wizard for multiple titlesets. (new: See **Command:titlesets**) + + + Helper Commands : **mpg** Encode videos to MPEG format (was **tovid**. See **Command:mpg**) -: **id** - Identify one or more video files (was **idvid**. See **Command:id**) -: **menu** - Create an MPEG menu (was **makemenu**. See **Command:menu**) -: **xml** - Create (S)VCD or DVD .xml file (was **makexml**. See **Command:xml**) : **dvd** Author and/or burn a DVD (was **makedvd**. See **Command:dvd**) -: **vcd** - Author and/or burn a VCD (was **makevcd**. See **Command:vcd**) -: **postproc** - Post-process an MPEG video file (was **postproc**. See **Command:postproc**) +: **id** + Identify one or more video files (was **idvid**. See **Command:id**) : **chapters** A GUI using mplayer for setting chapter points. It will return a string of - chapter points in a format recognized by 'tovid disc' (todisc) or - by 'tovid gui', for the **-chapters** option. - + chapter points to the terminal, in a format recognized by 'tovid disc' + (todisc) or by 'tovid gui', for the **-chapters** option. + The //OPTIONS// differ for each command; run **tovid <command>** with no further arguments to get help on a command, and what options it expects. @@ -69,47 +70,86 @@ : **~/.tovid/preferences** Defines working directory for all scripts. - In addition you can define the output directory for makempg here. + You can define the output directory for makempg here. + The 'ffmpeg' executable can be set here: ffmpeg or avconv (TOVID_FFMPEG) : **~/.tovid/tovid.ini** Includes command-line options that should be passed to the various - **tovid** sub-commands. + **tovid** sub-commands. Note: each sub-command has its own section, + starting with the line [sub-command], for example: +``` + [disc] + ; -no-warn + -static + -no-ask +``` + Edit these files if you wish to change your configuration. + The following environment variables are also honoured: -TOVID_WORKING_DIR (working directory for all scripts). -TOVID_OUTPUT_DIR (output directory for the makempg script). +``` + TOVID_HOME (directory containing preferences: ~/.tovid) + TOVID_WORKING_DIR (working directory for all scripts). + TOVID_OUTPUT_DIR (output directory for the makempg script). + TOVID_FFMPEG_CMD (the 'ffmpeg' executable to use: ffmpeg or avconv) +``` +These will override 'TOVID_HOME', 'WORKING_DIR', 'OUTPUT_DIR', +and 'TOVID_FFMPEG' if set in ~/.tovid/preferences. =Command:gui= +=Usage= + +**tovid gui** [//OPTIONS//] + **tovid gui** starts the graphical user interface (GUI) for tovid. This is -the easiest way to start creating DVDs with tovid. At this time, there are no -additional command-line options; the GUI controls take care of everything, -and all help is integrated in the form of tooltips. You can also see -**Command:disc ** for more detail about the options. Note: if you wish to -make multiple titlesets on the same DVD use 'tovid titlesets', which is a wizard -that uses the the tovid GUI. Chapter submenus can be made with 'tovid gui' -however. +the easiest way to start creating DVDs with tovid. The optional arguments +//OPTIONS// are any option used by todisc ('tovid disc') which will save +entering it manually, OR the full path to a saved script from the GUI. +You can also combine these, but the script must be the FIRST option +directly after **tovid gui** . (This option to save the contents of your +project allows you to use it as a bash script later, or to reload the +project to continue working with it at another time.) + + +**tovid gui** will also take the option **--position**, which denotes the +screen position that the GUI will start at, in the form '+X+Y', similar to +this part of the Xorg -geometry string. + +All help is integrated in the form of tooltips. You can also see +**Command:disc ** for more detail about the options. Note: if you wish to use +a GUI to make multiple titlesets on the same DVD use ***tovid titlesets***, +which is a wizard that uses the the 'tovid gui. See ***Command:titlesets***. + + +Please note that although the interface may seem complex with so many options, +you can create a fully functional DVD with only a few options on the opening +tab of the GUI (select video files and an output name). =Command:titlesets= **tovid titlesets** will assist in making a DVD with multiple titlesets. It can be started without any options, or you can feed it the path to a saved titleset -script as an option. +script as an option. The option to save a script is also useful as the resulting +script can be run later from a terminal. =Command:disc= -**tovid disc** creates a DVD file-system with menus, from a list of multimedia -video files and their titles. As this is a low level script it is the easiest -command line program for creating a DVD from start to finish, including -automatically converting non-compliant videos and prompting to burn at -completion. It does animated menus, static thumbnail menus and text only -menus. In addition, it can do slideshows, using images as input, and combine -slideshows with videos. It supports sub-menus for chapter breaks, configurable -menu style, animated backgrounds and transparency effects. +**tovid disc** creates a DVD file-system with optional menus, from a list of +multimedia video files and their titles. As todisc can function as a master +script, calling other scripts as it needs them, it is the easiest command line +program for creating a DVD from start to finish, including automatically +converting non-compliant videos and prompting to burn at completion. It can do +animated menus, static thumbnail menus, text-only menus, or author with no menu. +In addition, it can do slideshows, using images as input, and even combine +slideshows with videos. It supports sub-menus for chapter breaks, +configurable menu style, animated backgrounds and transparency effects. +From simple (no menu) to complex (switched menus and titlesets), you should +be able to do what you want with 'tovid disc'. ==Usage== @@ -117,7 +157,7 @@ ``` tovid disc [OPTIONS] \ -files <file list> -titles <title list> - -out OUT_PREFIX + -out mydvd ``` For example: @@ -133,10 +173,12 @@ as titles. If you are doing a slideshow or multiple slideshows, use **-slides** rather than **-files** for passing in the images. You may use -files and -slides more than once to create an ordering in a mixed -slideshows/videos menu. See SLIDESHOWS part of Usage section, below. +slideshows/videos menu. See Slideshows part of Usage section, below. If the input files are not mpeg, you will have the option to auto-encode them. +General Options + **At present there are 2 display arrangements or "templates":** : A. (Default) @@ -172,6 +214,7 @@ $ tovid disc -submenus \ -files file1.mpg file2.mpg ... \ -titles "Short 1" "Short 2" \ + -submenus \ -submenu-titles "Long Title One" "Long Title Two" \ -out foo @@ -179,7 +222,22 @@ The **-align** argument will position both titles and thumbs either south, north east, west, southwest, northwest, southeast, northeast, subject to -certain constraints of each arrangement. +certain constraints of each arrangement. For example a showcase style with +a showcase thumb can only do north|south|center. + +More Examples: + +A text-only menu: + +``` + $ tovid disc -textmenu ... +``` +No menu: + +``` + $ tovid -nomenu -files file1.mpg file2.mp4 "file 3.avi" -out mydvd +``` + **Titlesets** @@ -195,9 +253,9 @@ will need as many TITLES after **-titles** as you have menus. Any options outside the **-titleset** **-end-titleset** and **-vmgm** -**-end-vmgm** areas will be general options applying to every titleset. -If a general option is duplicated inside a **-titleset** or **-vmgm** area, the -general option will be overridden. +**-end-vmgm** areas will be global options applying to every titleset. +If a global option is duplicated inside a **-titleset** or **-vmgm** area, the +global option will be overridden. Note: you do not need titlesets for a single menu with chapter break menus, for that just use **-submenus** or **-ani-submenus** @@ -207,23 +265,25 @@ ``` $ tovid disc -static -out MY_DVD \ - \ - -titleset -files 1.mpg 2.mpg 3.mpg \ + \ + -titleset \ + -files 1.mpg 2.mpg 3.mpg \ -titles "Title One" "Title Two" "Title Three" \ -end-titleset \ \ - -titleset -files 4.mpg 5.mpg \ + -titleset \ + -files 4.mpg 5.mpg \ -titles "Title Four" "Title Five" \ - -background foo.jpg \ - -showcase bar.png \ - -end-titleset \ - \ - -vmgm \ - -titles "Season One" "Season Two" \ - -background bg.jpg \ - -bgaudio foo.mp3 \ - -titles-fontsize 20 \ - -end-vmgm + -background foo.jpg \ + -showcase bar.png \ + -end-titleset \ + \ + -vmgm \ + -titles "Season One" "Season Two" \ + -background bg.jpg \ + -bgaudio foo.mp3 \ + -titles-fontsize 20 \ + -end-vmgm ``` See also **-titleset** and **-vmgm** @@ -283,7 +343,7 @@ -out myslideshow ``` -See the other slideshow options in the SLIDESHOWS options section. +See the other slideshow options in the Slideshows options section. @@ -299,15 +359,40 @@ **-vbitrate**, **-quality**, **-safe**, **-crop**, **-filters**, **-abitrate**, **-priority**, **-deinterlace**, **-progressive**, **-interlaced**, **-interlaced_bf**, **-type**, **-fit**, **-discsize**, - **-parallel**, **-mkvsub**, **-autosubs**, **-subtitles**, **-update**, \ + **-parallel**, **-mkvsub**, **-autosubs**, **-subtitles**, **-update**, **-mplayeropts**, **-audiotrack**, **-downmix**, **-ffmpeg**, **-nofifo**, **-from-gui**, **-slice**, **-quiet**, **-fake**, **-keepfiles** -==Options== +==General Options== : **-keep-files**, **-keepfiles** Keep all intermediate/temporary files (helps with debugging) +: **-no-ask** | **-noask** + Skip all interactive questions. No preview, automatic re-encoding with + tovid if needed, no interactive option to use background video for bgaudio. +: **-no-warn**, **-nowarn** + Don't pause after outputting warning or info messages +: **-jobs** + By default, **tovid disc** starts a parallel job for each processor + detected. With this option you can manually set the number of jobs. For + example if you have a computer with 2 CPUs you can set "-jobs 1" to keep + one processor free for other things. At present this applies to the time + consuming imagemagick loops: you will notice a substantial speedup now if + you have a multi-cpu system. +: **-grid** + Show a second preview image with a grid and numbers that will help in finding + coordinates for options that might use them, like **-text-start** +: **-no-confirm-backup** + This option is for when your DVD contains images for a slideshow. + Slideshows are an experimental (but well tested) feature. Todisc is + unlikely to overwrite your personal files, but you should take precautions + and backup your images, as you would with any beta software. Todisc + will prompt you to backup your files normally. If you have already backed + up your images, use this option to disable the prompt. + +==Options== + : **-ntsc** 720x480 output, compatible with NTSC standard (default) : **-pal** @@ -320,10 +405,17 @@ : **-no-menu | -nomenu** With this option todisc will just create a DVD file system, ready for burning, with NO MENU, just the supplied video files. These do not need - to be compliant, as non-compliant files will be encoded as usual. Each - video will be a chapter unless **-chapters** OPTION is passed. The - **-chapters** option is a number indicating the chapter interval in - minutes, or a HH:MM:SS string indicating chapter points. See **-chapters** + to be compliant, as non-compliant files will be encoded as usual. The + **-out** option is not required. Each video will be a chapter unless + **-chapters** OPTION is passed. The **-chapters** option is a number + indicating the chapter interval in minutes, or a HH:MM:SS string + indicating chapter points. See **-chapters** +: **-encode-only** + This option was originally meant for the GUI, to allow it to be used for + just encoding rather than making a DVD structure. But it works well from + the command line as well as it has the added advantage that you can input + a list of files. Remember any makempg ('tovid mpg') options you use will + be passed on to the makempg script when encoding. ==Menu style== @@ -333,18 +425,19 @@ This is a different arrangement of images for the menu: small thumbnails go at left (and right) side of screen, with a larger image in the centre. Maximum of 10 videos. If the provided argument is a video file, the - central thumb will be animated. Only 4:3 or 16:9 videos and images are - accepted for the showcase file: if not one of these todisc will assume it - is the same ratio as the videos in the titleset. + central thumb will be animated (regardless of whether **-static** is part + of the command line). Only 4:3 or 16:9 videos and images are accepted for + for the showcase file: if not one of these todisc will assume it is the + aspect ratio as the videos in the titleset. : **-textmenu**, **-text-menu** NUM If used without an argument, create a textmenu out of the supplied titles The optional argument specifies how many titles are in the 1st column, i.e. giving 4 titles and using "-textmenu 2" would make 2 columns of 2 titles. The default is to put all titles up to 13 in the first column before starting a second column. Maximum: 2 columns and 26 titles. - Note that column 2 titles are aligned to the right. - If no video files for either **-background** or **-showcase** are supplied, - the menu will be static. + Note that column 2 titles are justified to the left unless you add + **-edge-justify** to the command line. The menu will be static if no video + files are supplied with either **-background** or **-showcase** options. : **-quick-menu** If you are using ffmpeg 0.8 or newer you can use this option. This will make a very quick menu by using ffmpeg instead of imagemagick. @@ -354,19 +447,19 @@ text-menu style of menu, with no video thumbs, and a central showcase IMAGE(static) | VIDEO(animated). (i) see **-bg-color** if you are not using a **-background** and want to - change the default black ) - (ii) Note: todisc will still work with vhooks if you have an old ffmpeg with - vhooks compiled in. + change the default. (default is dark blue for -quick-menu arrangements). ) + (ii) Note: todisc will still work with 'vhooks' if you have an old ffmpeg + with vhooks compiled in. Specifying the IMAGE|VIDEO argument to **-showcase** is mandatory for this style of menu, unless used in conjunction with **-switched-menus** in which case the videos passed with **-files** automatically become the - showcase videos. If this is used in combination with **-switched-menus** - it can really speed up an otherwise time consuming process. + showcase videos. If **-quick-menu** is used in combination with + **-switched-menus** it really speeds up an otherwise time consuming process. Example: ``` - -quick-menu -showcase /home/robert/showcase.mpg + -quick-menu -showcase /home/grepper/showcase.mpg ``` See **-switched-menus** for example of making switched menus with **-quick-menu** @@ -375,7 +468,8 @@ The color to use for the menu background. (default: ntsc-safe black) Note: use a color a great deal darker than you want, as it appears quite a bit lighter in the video version. You can use hexadecimal ('#ffac5f') - or named colors notation. + notation or named colors ('Lime'). convert -list color will show them. + See [colors http://www.imagemagick.org/script/color.php] for more details. : **-submenu-bg-color**, **-submenu-bg-colour** The color to use as background for the submenu(s). (default: ntsc-safe black) See **-bg-color** @@ -385,7 +479,7 @@ a 'moving' menu, in spite of the static buttons. This option also does double duty for the **-switched-menus** option, and will create static "switched" images. - See also **-switched-menu** + See also **-switched-menus** : **-background** IMAGE|VIDEO Menu background. This can be a image file or an video file. If it is a video file the background will be animated. Pick a file of correct aspect @@ -398,21 +492,21 @@ : **-menu-title** Title for the root menu - may be longer than thumbnail labels Also if you use \n in the title, you can use multi line titles, but you - would need to adjust **-menu-fontsize** to something smaller than default + would need to adjust **-title-fontsize** to something smaller than default for example: ``` - $ tovid disc ... -menu-title "A\nMultilined\nTitle" -menu-fontsize 24 + $ tovid disc ... -menu-title "A\nMultilined\nTitle" -title-fontsize 24 ``` -: **-menu-font** FONT +: **-title-font**, **-menu-font** FONT Font to use for titles, either by ImageMagick font name (ex., "Arial") or explicit pathname (ex., "/full/path/to/arial.ttf"). To see a complete list of acceptable ImageMagick font names, run **convert -list type**, and refer to the leftmost column -: **-menu-fontsize** +: **-title-fontsize**, **-menu-fontsize** Font size for main menu - best to -preview if you use this : **-submenu-font** - Font to use for the sub-menu main titles. See **-menu-font** + Font to use for the sub-menu main titles. See **-title-font** : **-submenu-fontsize** Font size for the sub-menu main titles : **-menu-fade** ['BACKGROUND DURATION'] @@ -461,7 +555,7 @@ using **-quick-nav** as you would not have a way to get to other titlesets. : **-skip-vmgm** Start DVD from the first titleset instead of the VMGM ( root ) menu. -: **-switched-menus** +: **-switched-menus**, **-switched-menu** This will make a "switched menu": there will be a central image where the showcase image would go, and text menu titles along the menu edge where textmenu titles go. As you select a video title with the down or up arrow @@ -485,6 +579,10 @@ ==Thumbnail style== +: **-titles-font** FONT + Display thumbnail or textmenu titles in the given font +: **-titles-fontsize** POINTS + Font size to use for thumbnail or textmenu titles : **-thumb-shape** normal|oval|vignette|plectrum|arch|spiral|blob|star|flare Apply a shaped transparency mask to thumbnail videos. @@ -506,10 +604,6 @@ : **-3d-thumbs**, **-3dthumbs** This will give an illusion of 3D to the thumbnails: dynamic lighting on rounded thumbs, and a raised effect on rectangular thumbs. Try it ! -: **-titles-font** FONT - Display thumbnail or textmenu titles in the given font -: **-titles-fontsize** POINTS - Font size to use for thumbnail or textmenu titles ==Slideshows== @@ -603,7 +697,7 @@ be static. If you used with a mixed menu of videos and slideshows, then the video thumbs WILL be animated, so you may wish to use -static or -textmenu with the option in that case. If you want to use the - **-switched-menus option with a mixed menu leave this option out. + **-switched-menus option with a mixed menu leave this option out. : **-background-slideshow**, **-bg-slideshow** If doing multiple slideshows or mixed videos and slideshow(s), then use @@ -616,6 +710,7 @@ and backup your images, as you would with any beta software. Todisc will prompt you to backup your files normally. If you have already backed up your images, use this option to disable the prompt. + See **General Options** : **-use-dvd-slideshow** [CONFIG FILE] If you pass this option without an argument, tovid will use the @@ -639,7 +734,7 @@ The speed to use for burning the disc. -==ADVANCED USAGE== +==Advanced usage== ===Options=== @@ -650,11 +745,11 @@ audio for static submenus. (Assuming that -submenu-audio was passed in). The default is to use 10 seconds of audio for static menus. : **-submenu-stroke** COLOR - The color for the sub-menu font outline (stroke) + The color for the sub-menu font shadow : **-submenu-title-color**, **-submenu-title-colour** The fill color used for sub-menu title fonts : **-submenu-titles** - You can supple a list of titles here for sub-menus without the length + You can supply a list of titles here for sub-menus without the length restrictions found in thumb titles. Must equal number of videos : **-chapters** [ NUM | CHAPTER POINTS in HH:MM:SS ] The number of chapters for each video (default: 6) OR @@ -725,7 +820,7 @@ : **-chapter-color** COLOR The color for the chapters font. : **-chapter-stroke** COLOR - The color for the chapters font outline (stroke) + The color for the chapters font shadow : **-seek** NUM | "NUM1 NUM2 NUM3 . . ." Seek to NUM seconds before generating thumbnails (default: 2.0 seconds) @@ -772,21 +867,6 @@ title and/or thumbnail for bar.mpg will appear in the menu. You can use **-group** more than once for multiple groups. Be sure to quote video filenames if they contain spaces. -: **-jobs** - By default, **tovid disc** starts a parallel job for each processor - detected. With this option you can manually set the number of jobs. For - example if you have a computer with 2 CPUs you can set "-jobs 1" to keep - one processor free for other things. At present this applies to the time - consuming imagemagick loops: you will notice a substantial speedup now if - you have a multi-cpu system. -: **-no-ask**, **-noask** - Skip all interactive questions. No preview, automatic re-encoding with - tovid if needed, no interactive option to use background video for bgaudio. -: **-no-warn**, **-nowarn** - Don't pause after outputting warning or info messages -: **-grid** - Show a second preview image with a grid and numbers that will help in finding - coordinates for options that might use them, like **-text-start** ==Menu Style== @@ -799,22 +879,35 @@ Move menu title by this offset from its N|S|E|W|Center position. You may need to use -align as well if you don't want your title covering other parts of your menu. See **-align** -: **-button-style** rect|text|line|text-rect +: **-button-style** line|rect|text|text-rect [line] The style of button that you will see when you play the DVD. - "rect" draws a rectangle around the thumb when you select it - in the DVD player. "text" highlights the video title text, "line" - underlines the title, and "text-rect" draws a rectangle around the title + "line" style underlines the title, "rect" draws a rectangle around the + thumb when you select it in the DVD player, "text" highlights the video + title text, and "text-rect" draws a rectangle around the title text. : **-title-color**, **-title-colour** COLOR Color to use for the main menu title. For list of supported colors do: **convert -list** color. HTML notation may be used: "#ff0000". See: http://www.imagemagick.org/script/color.php : **-title-stroke** COLOR - Outline color for the main menu's title font. Use "none" for transparent - outline (see title-color) + Shadow color for the main menu's title font. Use "none" for transparent + outline (see title-color). Note: this is not a -stroke in the sense that + imagemagick uses the term, but a shadow (the font is drawn twice). To get + a true imagemagick stroke see **-title-font-deco** +: **-title-font-deco**, **-title-fontdeco** "IMAGEMAGICK STRING" + Sets the font decoration method to FONTDECORATION. It is used by the 'convert' + ImageMagick command to draw the menu text. You can add colored text + outlines, gradient fills, and many others. See **Usage notes** : **-titles-stroke** COLOR - Outline color for the thumb or textmenu video titles font. Use "none" for - transparent outline (see **-titles-color**). + Shadow color for the thumb or textmenu video titles font. Use "none" for + transparent outline (see **-titles-color**). Note: this is not a -stroke + in the sense that imagemagick uses the term, but a shadow + (the font is drawn twice). To get a true imagemagick stroke, + see **-titles-font-deco** +: **-titles-font-deco**, **-titles-fontdeco** "IMAGEMAGICK STRING" + Sets the font decoration method to FONTDECORATION. It is used by the 'convert' + ImageMagick command to draw the menu text. You can add colored text + outlines, gradient fills, and others. See **Usage notes** for more info. : **-highlight-color**, **-highlight-colour** Color to use for the menu buttons that your DVD remote uses to navigate. : **-select-color**, **-select-colour** @@ -846,7 +939,7 @@ Only 4:3 aspect is supported: 16:9 will give unexpected results. -===Menu Style options specific to showcase and textmenu arrangements=== +===Style options specific to showcase/textmenu arrangements=== : **-text-start** N This option is for **-textmenu** menus. The titles will start at the Nth pixel from the top of the menu ( Y axis ). @@ -858,7 +951,8 @@ (default: if used without options, the rotate will be 5 degrees). Note: this will not turn a portait image into a landscape image! : **-showcase-geo** GEOMETRY - The position of the showcase image. ( XxY position ) + The position of the showcase image. ( +X+Y position ) + For example: **-showcase-geo** +300+200 : **-wave** default|GEOMETRY Wave effect for showcase image|video. Alters thumbs along a sine wave using GEOMETRY. (default: no wave) @@ -894,11 +988,12 @@ ==Thumbnail Style== -: **-user-thumbs** IMAGE +: **-user-thumbs** IMAGE(S) Supply your own images for menu buttons, rather than relying on todisc to generate them from the video. They must be the same aspect ratio as the videos in the titleset (4:3 or 16:9), as todisc will resize them without - checking and cropping. + checking and cropping. There must be on image for each thumb that will be + displayed on the menu (ie. one thumb for each video in a titleset). : **-opacity** [0-100] (default 100) Opacity of thumbnail videos as a percentage (no percent sign). Anything less than 100(%) is semi-transparent. Not recommended with dark @@ -912,10 +1007,22 @@ The amount of 'feather' blur to apply to the showcase image/video. Choose values between 0.1 and 2.0. This option has no effect on **-3d-showcase**. See **-thumb-blur** for more info. -: **-align** north|south - This will align thumbs/titles north or south. +: **-align** DIRECTION + This will align thumbs/titles in DIRECTION, which is a compass direction + as used by imagemagick: ie. north|south|east|west|northeast|northwest etc. If **-align** south then menu title will align north, unless you manually set one or both of **-menu-title-geo** or **-menu-title-offset**. + Only **-align** north|south|center has any effect on showcase with thumb, + or with the default montage arrangement of central thumbs. The most + apparent changes with be with textmenu, though with 2 column arrangements + only the north* and south* changes will show an effect. + + Diagram: +: . northwest north northeast . +: . . +: . west center east . +: . . +: . southwest south souteast . : **-thumb-mist** [COLOR] Use a mist behind thumbnails. The optional argument is the color of the mist. This option helps with contrast. Be sure to set the font color @@ -973,7 +1080,7 @@ the **-vmgm** ... **-end-vmgm** options to allow playing ALL titlesets. (If you want also to have a playall button in each titleset you could use this option between each **-titleset** ... **-end-titleset** option or put - it outside of the vmgm and titlset options as a general option. + it outside of the vmgm and titlset options as a global option. : **-videos-are-chapters** A button will be made on the main menu for each video, which you can use as a chapter button. Selecting any video will play them all in order @@ -1037,6 +1144,33 @@ equal the number of grouped videos. + +==Usage notes== + +The argument given to various *-font options that set the font to use must be +one of the fonts listed by the command 'convert -list type'. Please note that +many of your installed fonts may not be available; if you want to maximize the +number of fonts available to todisc, download and run +[Anthony Thyssen's http://www.cit.gu.edu.au/~anthony/anthony.html] +[imagick_type_gen http://www.imagemagick.org/Usage/scripts/imagick_type_gen] +script and run it like this: +imagick_type_gen > ~/.magick/type.xml. +If that doesn't work, try imagick_type_gen > ~/.magick/type.mgk. + +Or you can specify a ttf font file directly to the *-font options if you don't +want to install fonts to ImageMagick. + +The *-stroke options in todisc are not a stroke in the sense that ImageMagick +uses the term, but rather a font shadow (the text is drawn twice) To get a +truer Imagemagick -stroke try something like: +-title-font-deco "-stroke black" (or -titles-font-deco "-stroke black"). The +**-fontdeco** option is quite flexible and takes a lot of ImageMagick's +//convert// options. Please refer to the tovid +[wiki http://tovid.wikia.com/wiki/Making_a_DVD_with_text_menus] and Anthony +Thyssen's guide [http://www.imagemagick.org/Usage] for further explanation and examples. + + + =Command:mpg= **tovid mpg** converts arbitrary video files into (S)VCD/DVD-compliant @@ -1044,6 +1178,7 @@ standalone DVD player. + ==Usage== **tovid mpg** [//OPTIONS//] **-in** //INFILE// **-out** //OUTPREFIX// @@ -1339,7 +1474,7 @@ regularly the progress-meter is updated. The default is once every five seconds. -: **-mplayeropts** **"**//OPTIONS//**"** +: **-mplayeropts** //OPTIONS// Append //OPTIONS// to the mplayer command run during video encoding. Use this if you want to add specific video filters (documented in the mplayer manual page). Overriding some options will cause encoding to fail, so use @@ -1409,6 +1544,9 @@ Display output in a table format for easier comparison. Most useful when identifying multiple video files. +: **-keepfiles** + Keep temporary directory for debugging. + : **-isformat** [//pal-dvd//|//ntsc-dvd//] (same syntax for vcd and svcd) Check //VIDEO_FILE// for compliance with the given disc format. If //VIDEO_FILE// matches the given format, then **tovid id** reports "true" @@ -1427,365 +1565,35 @@ Check to see if homevideo.mpg is compliant with the DVD standard. -=Command:menu= - -**tovid menu** generates textual (S)VCD- or DVD-compliant MPEG videos for use -as navigational menus, given a list of text strings to use for title names. You -can customize the menu by providing an optional background image or audio clip, -or by using custom font and font color. - - -==Usage== - -**tovid menu** [//OPTIONS//] //TITLES// **-out** //OUT_PREFIX// - -For example: - -: ``tovid menu "Season One" "Season Two" "Featurettes" -out MainMenu`` - - -==Options== - -: **-ntsc** (default) - Generate an NTSC-format menu -: **-ntscfilm** - Generate an NTSC-format menu (24000/1001fps) -: **-pal** - Generate a PAL-format menu -: **-dvd** (default) - Generate a DVD-format menu, with highlighted text included - as a multiplexed subtitle stream. -: **-vcd** -: **-svcd** - Generate a VCD/SVCD menu; each menu option will have a - number associated with it. You can have up to nine menu - options per menu. - - -Menu background/audio options: - -: **-background** //IMAGE// - Use //IMAGE// (in most any graphic format) as a background. If image is not - the correct aspect ratio (4:3), it will be scaled and/or cropped, - depending on the **-crop** and **-scale** options. If no background is - supplied, a default background will be created. - -: **-crop** (default) - If provided background image is not 4:3 aspect ratio, crop edges - to make it so. Image will be scaled up if it is too small. Cropping - keeps the center area of image. If you want to do cropping/scaling - yourself in another program, provide an image of 768x576 pixels. - -: **-scale** - If provided background image is not 4:3 aspect ratio, scale/stretch - it to make it fit. May cause visible distortion! - -: **-audio** //AUDIOFILE// - Use //AUDIOFILE// (in most any audio format) for background music. The - menu will play for long enough to hear the whole audio clip. If - one is not provided, 4 seconds of silence will be used. - -: **-length** //NUM// - Make the menu //NUM// seconds long. Useful for menus with **-audio**: - if you don't want the entire //AUDIOFILE// in the menu, then you can trim - the length of the menu with **-length**. - - -Menu text options: - -: **-menu-title** **"**//MENU TITLE TEXT//**"** - Add //MENU TITLE TEXT// as a title/header to the menu. - -: **-font** //FONTNAME// (default Helvetica) - Use //FONTNAME// for the menu text. Run 'convert -list type' to see a - list of the fonts that you can use; choose a font name from the - leftmost column that is displayed. Or you can specify a ttf font file instead. - E.g., '-font /path/to/myfont.ttf'. - -: **-fontsize** //NUM// (default 24) - Sets the size for the font to //NUM// pixels. - -: **-menu-title-fontsize** //NUM// (default **-fontsize** + 8) - Sets the size of the menu title. - -: **-fontdeco** **'**//FONTDECORATION//**'** - Sets the font decoration method to //FONTDECORATION//. It is used by the - 'convert' ImageMagick command to draw the menu text. You can add colored - text outlines, gradient fills, and many others. See **Usage notes**. - -: **-align** {**left**|**center**|**middle**|**right**} - Align the text at the top left, top center, very middle, or top right - side of the screen. You may also substitute any "gravity" keyword - allowed by ImageMagick (north|south|east|west|northeast|southwest|...). - -: **-textcolor** {**#**//RRGGBB//|**#**//RGB//|//COLORNAME//} - Use specified color for menu text. #//RRGGBB// and #//RGB// are - hexadecimal triplets (e.g., #FF8035). //COLORNAME// may be any of - several hundred named colors; run 'convert -list color' to see them. - White (#FFF) is the default color. - - -DVD-only options: - -: **-button** //BUTTON// (default '>') - Specify the button used for menu selection. Specify either a _single_ - character or one of the shortcuts: - - **play** -- Use a button shaped like 'Play' on many A/V electronics: - a triangle pointing to the right. (uses the font Webdings) - - **movie** -- Use a button shaped like an old movie projector. - (uses the font Webdings) - - **utf8** -- Use your own non-keyboard character as a button. Provide - only the four hex digits: eg '-button utf8 00b7'. Beware that - ImageMagick's utf8 characters aren't the same as those drawn in - character browsers like gucharmap. - - -: **-highlightcolor** {**#**//RRGGBB//|**#**//RGB//|//COLORNAME//} - Use the specified color for button highlighting. Yellow (#FF0) is the - default color. - -: **-selectcolor** {**#**//RRGGBB//|**#**//RGB//|//COLORNAME//} - Use the specified color for button selections (when a menu item is played - or activated). Red (#F00) is the default color. - -: **-button-outline** {**#**//RRGGBB//|**#**//RGB//|//COLORNAME//} - Outline buttons with the specified color. 'none' is the default. - -: **-button-font** //FONTNAME// - Specify a differnt font to use for the buttons. By default, the button - font will be inherited from the title font (see **-font**). Use this - option to use a different font for the buttons. The button font size is - inherited from **-fontsize** and cannot be changed. - - -Other options: - -: **-debug** - Print extra debugging information to the log file. Useful in - diagnosing problems if they occur. This option also leaves - the log file (with a .log extension) in the directory after - encoding finishes as well as all the temporary files created. - -: **-nosafearea** - Do not attempt to put text inside a TV-safe viewing area. Most - television sets cut off about 10% of the image border, so the script - automatically leaves a substantial margin. This option turns that - behavior off, leaving only a tiny margin. Use at your own risk. - -: **-overwrite** - Overwrite any existing output menu. - -: **-noask** - Don't ask interactive questions, and assume answers that will - continue making the menu until completion. - -: **-quiet** - Limit output to essential messages. - - -If the word "**back**" is given as an episode title, a "back" button for -returning to a higher-level menu will be added at the end of the list -of titles. "**Back**" //must be the last title listed//. - - -==Examples== - -Make an NTSC VCD menu with white Helvetica text containing three centered -selections: Episode 1, Episode 2, and Episode 3. The finished menu will be -called Season-1.mpg: - -``` -tovid menu -ntsc -vcd \ - -align center -textcolor white -font "Helvetica" \ - "Episode 1" "Episode 2" "Episode 3" \ - -out "Season-1" -``` - -Make an NTSC DVD menu with white Kirsty text containing three lower-left -aligned selections: Episode 1, Episode 2, and Episode 3. Items under the cursor -will be highlighted a pale blue, and selected items will be a pale orange -(before going to the selected title). The finished menu will be called -Main-menu.mpg: - -``` -tovid menu -ntsc -dvd \ - -align southwest \ - -textcolor white \ - -highlightcolor "#5f65ff" \ - -selectcolor "#ffac5f" \ - -font "Kirsty" \ - "Episode 1" "Episode 2" "Episode 3" \ - -out "Main_menu" -``` - - - -==Usage notes== - -The argument given to **-font** must be one of the fonts listed -by the command 'convert -list type'. Please note that many of -your installed fonts may not be available; if you want to maximize the -number of fonts available, download and run -[Anthony Thyssen's http://www.cit.gu.edu.au/~anthony/anthony.html] -[imagick_type_gen.pl http://www.cit.gu.edu.au/~anthony/software/imagick_type_gen.pl] -script and run it like this: -imagick_type_gen.pl > ~/.magick/type.xml. -If that doesn't work, try -imagick_type_gen.pl > ~/.magick/type.mgk. - -Or you can specify a ttf font file directly to the **-font** options if you -don't want to install fonts to ImageMagick. - -The **-fontdeco** option is quite flexible and takes a lot of ImageMagick's -//convert// options. Please refer to the tovid -[wiki http://tovid.wikia.com/wiki/Making_a_DVD_with_text_menus] -and Anthony Thyssen's guide for further explanation and examples. - - -=Command:xml= - -**tovid xml** generates XML output describing an (S)VCD -or DVD file structure and navigation hierarchy in the format expected by -[dvdauthor http://dvdauthor.sourceforge.net/] or -[vcdxbuild http://www.vcdimager.org/]. - - -==Usage== - -**tovid xml** [//OPTIONS//] //VIDEOS// -out //OUTFILE// - -For example: - -``` -$ tovid xml -menu MainMenu.mpg \ - Season1.mpg Season2.mpg Featurettes.mpg \ - -out MyDisc -``` - - -==Options== - -: **-dvd** (default) - Generate the XML for a DVD disc, to be used with dvdauthor or **tovid dvd**. -: **-vcd** - Generate the XML for a VCD disc, to be used with vcdxbuild or **tovid vcd**. -: **-svcd** - Generate the XML for an SVCD disc, to be used with vcdxbuild or **tovid vcd**. -: **-overwrite** - Overwrite any existing output files. -: **-quiet** - Limit output to essential messages. - - -//VIDEOS// may be any of the following: - -: //<file list>// - List of one or more video files to include, separated by spaces. At - minimum, a DVD must have one video file. You can use shell wildcards - (i.e., "*.mpg") to include multiple files easily. Put filenames in - quotes if they have spaces in them. - -: **-menu** //VIDEO// //<file list>// - Use video file //VIDEO// as a menu from which you can jump to each of - the listed video files. If you have multiple menus, include a - top menu so they are reachable. - -: **-slides** //<file list>// - Create a slide-show of still images - - -DVD-only options - -: **-group** //<file list>// **-endgroup** - (DVD only) List of video files to include as one single title. This is useful - if you have split a movie into several video files. - -: **-topmenu** //VIDEO// [**-menu** //VIDEO// //<file list>//] [**-menu** //VIDEO// //<file list>//]... - (DVD only) Use video file //VIDEO// for the top-level (VMGM) menu. The - top menu will jump to each of the subsequent [-menu...] videos listed. - Use this only if you have multiple sub-menus to jump to. You can only - have one top menu. - -: **-titlesets** - (DVD only) Forces the creation of a separate titleset per title. This - is useful if the titles of a DVD have different video formats, - e.g. PAL + NTSC or 4:3 + 16:9. If used with menus, there must be a - **-topmenu** option that specifies a menu file with an entry for each of the - titlesets. - -: **-chapters** //INTERVAL// - (DVD only) Creates a chapter every //INTERVAL// minutes (default 5 minutes: - without **-chapters**, each movie will be divided into 5-minute chapters). - This option can be put at any position in a //<file list>// and is valid - for all subsequent titles until a new **-chapters** option is encountered. - Using this option may take some time, since the duration of the video is - calculated. - -: **-nochapters** - (DVD only) Don't create chapters for the videos. - - -//OUT_PREFIX// is the file that will receive the resulting XML. - - -==Usage notes== - -The 'xml' command checks to make sure the video filenames you -give it exist, but it does not check whether they are valid for the -chosen disc format. MPEG videos of menus should have the specified -number of buttons for reaching each of the videos, and, if you're -using DVD, should be multiplexed with their corresponding subtitles -using spumux of the dvdauthor 0.6.0 package prior to -authoring using dvdauthor. If you use the 'tovid menu' -component to generate the menu, this should all be handled for you. - - -==Examples== - -: ``tovid xml -dvd title-1.mpg title-2.mpg title-3.mpg -out My_DVD`` - Make a DVD without a menu. Title 1, 2, and 3 will play in sequence. - -: ``tovid xml -dvd -group chapter-1.mpg chapter-2.mpg chapter-3.mpg -endgroup -out My_DVD`` - Group the file chapter-1|2|3.mpg into one title and make a DVD without a menu. - -: ``tovid xml -dvd -menu main_menu.mpg -chapters 3 movie-1.mpg -chapters 10 movie-2.mpg -out My_DVD`` - Make a DVD with a main menu that points to two movies, with movie-1.mpg -divided into 3-minute chapters, and movie-2.mpg into 10-minute chapters. - - =Command:dvd= -**tovid dvd** takes a dvdauthor XML file (as generated by the **tovid xml** -command) and authors a DVD filesytem. This command can also burn a DVD disc -from either the XML file or from an existing DVD file-system. +**tovid dvd** takes a DVD directory as generated by tovid with 'tovid disc' or +one of the GUI frontends like 'tovid gui' or 'tovid titlesets' and burns +it to appropriate media. This will also work if the DVD directory is +generated by the dvdauthor backend that tovid also uses. -To ensure that this script successfully executes, please run it from a -directory with plenty of free space. "Plenty" would be 10 GB for single-layer -discs, and 20 GB for dual-layer discs. Running this program may slow down your -other applications, due to intense disk activity. +Running this program may slow down your other applications, due to intense +disk activity. ==Usage== -**tovid dvd** [//OPTIONS//] //FILE.xml// **tovid dvd** [//OPTIONS//] //DVD_DIR// For example: -: ``tovid dvd -burn MyDisc.xml`` -: ``tovid dvd -burn /path/to/DVD/directory`` +: ``tovid dvd /path/to/DVD/directory`` ==Options== -: **-author** - Author the DVD described by //FILE.xml//. Overwrites an existing - directory containing the dvdauthor output if already present. - : **-burn** Burn a DVD file-system in //DVD_DIR// (must contain a VIDEO_TS folder). + This option is currently not necessary as the makedvd script ONLY burns + now that legacy scripts like makexml have been removed. Left for + compatibility only. : **-eject** Eject the DVD tray after burning is complete. By default, the DVD is not @@ -1813,133 +1621,29 @@ execution. -==Examples== - -: ``tovid dvd -burn -device /dev/dvdrw foo.xml`` - Author the dvd file-system and burn to /dev/dvdrw. This will - automatically call dvdauthor to make the file-system. **-author** - is not explicitly needed. If there's an existing file-system, it - will be burned. - -: ``tovid dvd -author foo.xml`` - Author the DVD file-system and exit without burning. If the output - directory given in foo.xml already exists, then the contents are - removed before authoring. At this point, the DVD can be previewed - by calling //**xine** dvd:/path/to/output/directory//. - - -=Command:vcd= - -**tovid vcd** takes an XML file (which may be generated by **tovid xml**) and -creates a cue/bin (S)VCD image. It can also burn (S)VCD discs. - -To ensure that this script successfully executes, please run it from a directory -with plenty of free space. "Plenty" would be about 1 GB. Running this program -may slow down your other applications, due to intense disk activity. - - -==Usage== - -**tovid vcd** [//OPTIONS//] //VCDIMAGER.xml// - -For example: - -: ``tovid vcd -burn MyDisc.xml`` - - -==Options== - -: **-overwrite** (default off -- nothing is overwritten) - Overwrite any existing cue/bin files matching //VCDIMAGER.xml//. Useful - if you modified the xml file and wish to re-image or burn the new (S)VCD. - -: **-burn** (default off -- no images are burned) - Burn the (S)VCD described by //VCDIMAGER.xml//. - -: **-device** //DEVICE// (default /dev/cdrw) - Burn the disc image to //DEVICE//, the Linux device file-system - name of your CD-recorder. Common examples might be /dev/cdrw, - /dev/scd1, and /dev/hdc. - -: **-speed** //NUM// (default 12) - Burn the disc at speed //NUM//. - -: **-quiet** - Limit output to essential messages. - - -==Examples== - -: ``tovid vcd -burn -device /dev/cdrw foo.xml`` - Create the (S)VCD image and burn it to /dev/cdrw. This will - automatically call vcdxbuild to make the image. If there is an existing - image, it will be burned. - -: ``tovid vcd -overwrite foo.xml`` - Create the (S)VCD image and exit without burning. If the image - already exists, then it is removed before re-imaging. - - - -=Command:postproc= - -**tovid postproc** is designed to do simple post-processing on MPEG video files, such -as those generated by tovid. It can adjust audio/video sync, and re-quantize -(shrink) without re-encoding. + After burning, the DVD can be previewed by calling: + //**xine** dvd:/path/to/output/directory// + or: + //**vlc** /path/to/output/directory// -==Usage== - -**tovid postproc** [//OPTIONS//] //IN_FILE// //OUT_FILE// - - -==Options== - -: **-audiodelay** //NUM// - Delay the audio stream by //NUM// milliseconds. Use this if - your final output has audio that is not synced with the - video. For example, if the audio comes 2 seconds sooner than - the video, use "-audiodelay 2000". Use a negative number for - audio that comes later than the video. - -: **-normalize** - Analyze the audio stream and then normalize the volume of the audio. - This is useful if the audio is too quiet or too loud, or you want to - make volume consistent for a bunch of videos. Similar to running - normalize without any parameters. The default is -12dB average level - with 0dB gain. - -: **-amplitude** //NUM//[dB] - In addition to analyzing and normalizing, apply the gain to the audio - such that the 'average' (RMS) sound level is //NUM//. Valid values - range 0.0 - 1.0, with 0.0 being silent and 1.0 being full scale. Use - //NUM//dB for a decibel gain below full scale (the default without - -amplitude is -12dB). - -: **-shrink** //NUM// - Shrink the video stream by a factor of //NUM//. May be a decimal - value. A value of 1.0 means the video will be the same size; - larger values cause more reduction in size. Beyond 2.0, the - returns are diminishing. - -: **-parallel** - Run all processes in parallel and pipe into multiplexer, should - increase speed significantly. - -: **-debug** - Save output in a temporary file, for later viewing if - something goes wrong. - =Command:chapters= **tovid chapters** will start a GUI using mplayer to set chapter points in a -video. Its only (mandatory) option is the path to a video file. +video. If the video plays through and you want to add more chapters you can +press the play button again, but remember that new chapter points will be +appended (in correct sequential order). It will display the resulting chapter +points, and also output to a terminal (useful for scripts). As well it will +give the option of saving the chapters string to a text file. + +Note that the 'tovid gui' now features a similar widget when you press the +chapters button on the opening page. ==Examples== : ``tovid chapters foo.avi`` -: ``tovid chapters /home/grepper/videos/foo.avi`` +: ``chapters=$(tovid chapters /home/grepper/videos/foo.avi)`` =CONTACT=
View file
tovid-0.34.tar.bz2/libtovid/__init__.py -> tovid-0.35.tar.gz/libtovid/__init__.py
Changed
@@ -3,29 +3,16 @@ __all__ = [ # Subdirectories - 'backend', - 'gui', 'guis', 'metagui', - 'render', - 'template', - 'test', - 'util', # .py files - 'author', 'cli', - 'deps', - 'encode', 'odict', - 'opts', - 'rip', - 'standard', - 'stats', 'utils', - 'xml', ] import os +from sys import version_info # Python < 3.x try: @@ -34,6 +21,16 @@ except ImportError: from configparser import ConfigParser +# Python 3.x compatibility assignments +if version_info[0] < 3: # python 3.x + unicode = unicode + basestring = basestring + xrange = xrange +else: # Python 3.x + unicode = str + basestring = str + xrange = range + # Configuration file reader/writer class Config (ConfigParser): """Interface for reading/writing tovid configuration files. Just a wrapper
View file
tovid-0.34.tar.bz2/libtovid/cli.py -> tovid-0.35.tar.gz/libtovid/cli.py
Changed
@@ -80,12 +80,9 @@ import subprocess import signal import os - # Small workaround for Python 3.x -try: - _temp = unicode -except NameError: - unicode = str +from libtovid import unicode, basestring + class ProgramNotFound (ValueError): """Raised when the program given to a command is not available.
View file
tovid-0.34.tar.bz2/libtovid/guis/helpers.py -> tovid-0.35.tar.gz/libtovid/guis/helpers.py
Changed
@@ -1,21 +1,29 @@ -import Tkinter as tk import time import shlex -import commands import re import os import fnmatch from libtovid.metagui import * from libtovid.metagui.control import _SubList from libtovid.util import filetypes -from subprocess import Popen, PIPE, STDOUT -from tempfile import mkdtemp +from subprocess import Popen, PIPE +from tempfile import mkdtemp, mkstemp +from sys import stdout + +try: + from commands import getstatusoutput, getoutput + import Tkinter as tk +except ImportError: + # python 3 + from subprocess import getstatusoutput, getoutput + import tkinter as tk __all__ = [ 'VideoGui', 'SetChapters', 'Chapters', 'strip_all', 'to_title', 'find_masks', 'nodupes', 'video_filetypes', 'image_filetypes', 'visual_filetypes', 'dvd_video_files', 'av_filetypes', 'sys_dir', 'thumb_masks', 'home_dir', 'tovid_prefix', 'tovid_icon', 'os_path', -'heading_text', '_files_and_titles', '_out' ] +'heading_text', '_files_and_titles', '_out', 'CopyableInfo' ] + class VideoGui(tk.Frame): """A basic GUI to play video files. It runs mplayer in slave mode @@ -24,7 +32,7 @@ Without subclassing it only contains a 'play/pause button and an 'exit' button. """ - def __init__(self, master, args='', title='', callback=None, style='popup'): + def __init__(self, master, args='', title='', callback=None): """Initialize GUI master @@ -36,8 +44,6 @@ the wm title given to the master widget. callback a function run at program exit, before cleanup of temp files - style - may be one of 'popup' (default), 'standalone', or 'embedded'(TBA) """ tk.Frame.__init__(self, master) @@ -50,98 +56,143 @@ try: self.master.title(title) except AttributeError: - print "Error: " + \ - "VideoGui master must be a root window for 'title' option" + print("Error: " + \ + "VideoGui master must be a root window for 'title' option") self.callback = callback - self.style = style - + self.v_width = 540 + self.v_height = 405 self.is_running = tk.BooleanVar() self.is_running.set(False) self.pauseplay = tk.StringVar() - self.pauseplay.set('play') + self.pauseplay.set('Play') # temporary directory for fifo and other mplayer files + self.make_tmps() + self.draw() + + def make_tmps(self): + """Make temporary directory containing fifo for mplayer commmands, + editlist, and log + """ self.tempdir = mkdtemp(prefix='tovid-') self.cmd_pipe = os.path.join(self.tempdir, 'slave.fifo') self.editlist = os.path.join(self.tempdir, 'editlist') os.mkfifo(self.cmd_pipe) self.log = os.path.join(self.tempdir, 'mplayer.log') - self.draw() - + def draw(self): """Draw the GUI in self.master and get X11 identifier for container""" self.root_frame = tk.Frame(self) self.root_frame.pack(side='top', fill='both', expand=1, pady=20) self.container = tk.Frame(self.root_frame, bg='black', container=1, colormap='new') + self.container.configure(width=self.v_width, height=self.v_height, bg='black') self.container.pack() # X11 identifier for the container frame self.xid = self.tk.call('winfo', 'id', self.container) - # bindings for exit - if self.style == 'standalone': - self._root().protocol("WM_DELETE_WINDOW", self.confirm_exit) - self._root().bind('<Control-q>', self.confirm_exit) self.add_widgets() def add_widgets(self): - """ - Add buttons to the VideoGui. Override this to customize buttons. + """Add buttons to the VideoGui. Override this to customize buttons. root_frame has 'grab_set()' applied to it so make sure widgets go into this frame or they will not be functional! This function is called in draw() """ button_frame = tk.Frame(self.root_frame) button_frame.pack(side='bottom', fill='x', expand=1) - control_frame = tk.Frame(button_frame, borderwidth=1, relief='groove') - control_frame.pack() - exit_button = tk.Button(control_frame, command=self.exit_mplayer, text='exit') - pause_button = tk.Button(control_frame, command=self.pause, + self.control_frame = tk.Frame(button_frame, borderwidth=1, relief='groove') + self.control_frame.pack() + self.load_button = tk.Button(self.control_frame, + command=self.load, text='load video') + self.load_button.pack(side='left') + exit_button = tk.Button(self.control_frame, command=self.exit_mplayer, text='exit') + self.pause_button = tk.Button(self.control_frame, command=self.pause, width=12, textvariable=self.pauseplay) - exit_button.pack(side='left') - pause_button.pack(side='left') + self.pause_button.pack(side='left') + exit_button.pack(side='left', padx=5) + self.mp_ctrls = [self.pause_button] + self.toggle_controls('disabled', self.mp_ctrls) def identify(self, video): - """ - Get information about video from mplayer -identify. + """Get information about video from mplayer -identify. Called by set_container() """ - output = commands.getoutput('mplayer -vo null -ao null -frames 5 \ - -channels 6 -identify %s' %video) - return output + cmd = 'mplayer -vo null -ao null -frames 5 -channels 6 -identify' + cmd = shlex.split(cmd) + [video] + output = Popen(cmd, stdout=PIPE, stderr=PIPE) + return output.communicate()[0] - def set_container(self, video): + def load(self, event=None): + """Load a file to play in the GUI""" + try: + from tkFileDialog import askopenfilename + except ImportError: + # python 3 + from tkinter.filedialog import askopenfilename + vid_name = askopenfilename() + if vid_name: + self.toggle_controls('normal', self.mp_ctrls) + if self.pauseplay.get() == 'Pause': + self.pauseplay.set('Play') + self.run(vid_name) + + def set_container(self, video=None): """Get aspect ratio and set dimensions of video container. Called by run(). """ - if self.style == 'standalone': - v_width = 600 - else: - v_width = 540 media_info = self.identify(video) - asr = re.findall('ID_VIDEO_ASPECT=.*', media_info) + asr = re.findall('ID_VIDEO_ASPECT=.*', str(media_info)) # get last occurence as the first is 0.0 with mplayer if asr: asr = sorted(asr, reverse=True)[0].split('=')[1] - try: - asr = float(asr) - except ValueError: - asr = 0.0 + try: + asr = float(asr) + except ValueError: + asr = 0.0 # get largest value as mplayer prints it out before playing file if asr and asr > 0.0: - v_height = int(v_width/asr) + v_height = int(self.v_width/asr) else: # default to 4:3 if identify fails - v_height = int(v_width/1.333) - self.container.configure(width=v_width, height=v_height) + v_height = int(self.v_width/1.333) + self.container.configure(width=self.v_width, height=v_height) def run(self, video): """Play video in this GUI using mplayer.""" + if video == None: + self.toggle_controls('disabled', self.mp_ctrls) + return + elif not os.path.exists(video): + try: + from tkMessageBox import showerror + except ImportError: + from tkinter.messagebox import showerror + showerror('Oops', video + ' does not exist') + self.toggle_controls('disabled', self.mp_ctrls) + self.master.master.withdraw() + else: + self.toggle_controls('enabled', self.mp_ctrls) + # a new video has been loaded if no temp files, so make them + if not os.path.exists(self.tempdir): + self.make_tmps() + # set the container size, then run the video self.set_container(video) command = 'mplayer -wid %s -nomouseinput -slave \ -input nodefault-bindings:conf=/dev/null:file=%s \ - -edlout %s %s %s' \ - %(self.xid, self.cmd_pipe, self.editlist, self.args, video) - self.command = shlex.split(command) + -edlout %s %s' \ + %(self.xid, self.cmd_pipe, self.editlist, self.args) + self.command = shlex.split(command) + [video] + + def toggle_controls(self, state, widgets): + """ + Enable/disable mplayer control widgets + state is either 'normal' or 'disabled', widgets is an instance list + """ + for widget in widgets: + try: + widget.configure(state=state) + except tk.TclError: + pass def poll(self): """ @@ -153,20 +204,24 @@ """ if not self.is_running.get(): return - tail = 'tail -n 1 %s' %self.log - log_output = commands.getoutput(tail) - # restart mplayer with same commands if it exits without being sent - # an explict 'quit'. - if '(End of file)' in log_output: - self.on_eof() - # check for is_running again as on_oef() might set it to false - if self.is_running.get(): - cmd = Popen(self.command, stderr=open(os.devnull, 'w'), \ - stdout=open(self.log, "w")) - if self.show_osd: - self.send('osd 3\n') - self.pause() - self.master.after(200, self.poll) + f = open(self.log, 'r') + # seek to 50 bytes from end of file + try: + f.seek(-50, 2) + if '(End of file)' in f.read(): + self.on_eof() + # check for is_running again as on_oef() might set it to false + if self.is_running.get(): + cmd = Popen(self.command, stderr=open(os.devnull, 'w'), \ + stdout=open(self.log, "w")) + if self.show_osd: + self.send('osd 3') + self.pause() + # if file does not contain 50 bytes, do nothing + except IOError: + pass + self.master.after(100, self.poll) + def on_eof(self): """ @@ -177,20 +232,20 @@ pass def send(self, text): - """send command to mplayer's slave fifo""" + """Send command to mplayer's slave fifo""" if self.is_running.get(): - commands.getstatusoutput('echo -e "%s" > %s' %(text, self.cmd_pipe)) + getstatusoutput('echo "%s" > %s' %(text, self.cmd_pipe)) def pause(self): - """send pause to mplayer via slave and set button var to opposite value""" + """Send pause to mplayer via slave and set button var to opposite value""" # mplayer's 'pause' pauses if playing and plays if paused - # pauseplay ==play in pause mode, and ==pause in play mode (button text) + # pauseplay ==Play in pause mode, and ==Pause in play mode (button text) if self.is_running.get(): - if self.pauseplay.get() == 'pause': - self.pauseplay.set('play') + if self.pauseplay.get() == 'Pause': + self.pauseplay.set('Play') else: - self.pauseplay.set('pause') - self.send('pause\n') + self.pauseplay.set('Pause') + self.send('pause') else: # start the video for the 1st time cmd = Popen(self.command, stderr=open(os.devnull, 'w'), stdout=open(self.log, "w")) @@ -198,32 +253,35 @@ self.poll() # show osd time and remaining time if self.show_osd: - self.send('osd 3\n') - self.pauseplay.set('pause') + self.send('osd 3') + self.pauseplay.set('Pause') - def exit_mplayer(self): + def exit_mplayer(self): # called by [done] button """ Close mplayer if it is running, then exit, running callback if it exists """ # unpause so mplayer doesn't hang if self.is_running.get(): - if self.pauseplay.get() == 'play': - self.send('mute 1\n') - self.send('pause\n') - self.send('quit\n') + if self.pauseplay.get() == 'Play': + self.send('mute 1') + self.send('pause') + self.send('quit') self.is_running.set(False) time.sleep(0.3) self.confirm_exit() + def confirm_msg(self): + mess = "osd_show_text 'please exit mplayer first' 4000 3" + if not self.show_osd: + self.send('osd 3\n%s' %mess) + self.after(2500, lambda:self.send('osd 0')) + else: + self.send(mess) + def confirm_exit(self, event=None): - """on exit, make sure that mplayer is not running before quit""" + """On exit, make sure that mplayer is not running before quit""" if self.is_running.get(): - mess = "osd_show_text 'please exit mplayer first' 4000 3\n" - if not self.show_osd: - self.send('osd 3\n%s' %mess) - self.after(2500, lambda:self.send('osd 0\n')) - else: - self.send(mess) + self.confirm_msg() else: # run any custom commands on exit if callable(self.callback): @@ -234,15 +292,16 @@ os.remove(f) if os.path.exists(self.tempdir): os.rmdir(self.tempdir) - if self.style == 'standalone': - self.quit() - else: - self.destroy() + self.quit() + + def quit(self): + """Quit the application. This detroys the root window, exiting Tkinter""" + self.destroy() class SetChapters(VideoGui): - """A GUI to set video chapter points using mplayer""" - def __init__(self, master, args='', title='', callback=None, style='popup'): + """Elements for a GUI to set video chapter points using Mplayer""" + def __init__(self, master, args='', title='', callback=None): """ master Pack into this widget @@ -252,75 +311,96 @@ Window manager titlebar title (master must be root window for this) callback Function to run on application exit, run before temp file cleanup - style - Can one of: 'popup' (default), 'standalone', or 'embedded'(TBA) """ - VideoGui.__init__(self, master, args, title, callback, style) - + VideoGui.__init__(self, master, args, title, callback) self.chapter_var = tk.StringVar() def add_widgets(self): + """ + Add buttons to the Gui. root_frame has 'grab_set()' applied to it so + make sure widgets go into this frame or they will not be functional! + This function is called in draw() + """ # button frame and buttons button_frame = tk.Frame(self.root_frame) button_frame.pack(side='bottom', fill='x', expand=1) - control_frame = tk.Frame(button_frame, borderwidth=1, relief='groove') - control_frame.pack() - exit_button = tk.Button(control_frame, command=self.exit_mplayer, text='done !') - mark_button = tk.Button(control_frame, command=self.set_chapter,text='set chapter') - pause_button = tk.Button(control_frame, command=self.pause, + self.control_frame = tk.Frame(button_frame, borderwidth=1, relief='groove') + self.control_frame.pack() + exit_button = tk.Button(self.control_frame, command=self.exit_mplayer, text='done !') + mark_button = tk.Button(self.control_frame, command=self.set_chapter,text='set chapter') + pause_button = tk.Button(self.control_frame, command=self.pause, width=12, textvariable=self.pauseplay) - framestep_button = tk.Button(control_frame, text='step >', command=self.framestep) - forward_button = tk.Button(control_frame, text='seek >', command=self.forward) - back_button = tk.Button(control_frame, text='< seek', command=self.back) - # seek frame and scale widget - seek_frame = tk.Frame(self.root_frame) - seek_frame.pack(side='left', fill='x', expand=1, padx=30) - self.seek_scale = tk.Scale(seek_frame, from_=0, to=100, tickinterval=10, - orient='horizontal', label='Use slider to seek to point in file (%)') - self.seek_scale.bind('<ButtonRelease-1>', self.seek) + framestep_button = tk.Button(self.control_frame, text='step>', + command=self.framestep) + forward_button = tk.Button(self.control_frame, text='>>', + command=self.forward) + fast_forward_button = tk.Button(self.control_frame, text='>>>', + command=self.fastforward) + back_button = tk.Button(self.control_frame, text='<<', command=self.back) + fast_back_button = tk.Button(self.control_frame, text='<<<', command=self.fast_back) +# self.seek_scale = tk.Scale(seek_frame, from_=0, to=100, tickinterval=10, +# orient='horizontal', label='Use slider to seek to point in file (%)') +# self.seek_scale.bind('<ButtonRelease-1>', self.seek) # pack the buttons and scale in their frames mark_button.pack(side='bottom', fill='both', expand=1) - self.seek_scale.pack(side='left', fill='x', expand=1) + #self.seek_scale.pack(side='left', fill='x', expand=1) exit_button.pack(side='left') + fast_back_button.pack(side='left') back_button.pack(side='left') - pause_button.pack(side='left') + pause_button.pack(side='left', expand=1) framestep_button.pack(side='left') forward_button.pack(side='left') + fast_forward_button.pack(side='left') + self.mp_ctrls = self.control_frame.winfo_children() - def seek(self, event=None): - """seek in video according to value set by slider""" - self.send('seek %s 3\n' %self.seek_scale.get()) +# def seek(self, event=None): +# """Seek in video according to value set by slider""" +# self.send('seek %s 3\n' %self.seek_scale.get()) +# self.after(500, lambda:self.seek_scale.set(0)) def forward(self): - """seek forward 10 seconds and make sure button var is set to 'pause'""" - self.send('seek 10\n') - self.pauseplay.set('pause') + """Seek forward 10 seconds and make sure button var is set to 'Pause'""" + self.send('seek 10') + self.pauseplay.set('Pause') + + def fastforward(self): + """Seek forward 5 minutes and make sure button var is set to 'Pause'""" + self.send('seek 300') + self.pauseplay.set('Pause') def back(self): - """seek backward 10 seconds and make sure button var is set to 'pause'""" - self.send('seek -10\n') - self.pauseplay.set('pause') + """Seek backward 10 seconds and make sure button var is set to 'Pause'""" + self.send('seek -10') + self.pauseplay.set('Pause') + + def fast_back(self): + """Seek backward 10 seconds and make sure button var is set to 'Pause'""" + self.send('seek -300') + self.pauseplay.set('Pause') def framestep(self): - """step frame by frame forward and set button var to 'play'""" - self.send('pausing frame_step\n') - self.pauseplay.set('play') + """Step frame by frame forward and set button var to 'Play'""" + self.send('pausing frame_step') + self.pauseplay.set('Play') def set_chapter(self): - """send chapter mark (via slave) twice so mplayer writes the data. + """Send chapter mark (via slave) twice so mplayer writes the data. we only take the 1st mark on each line """ for i in range(2): - self.send('edl_mark\n') - mess = "osd_show_text 'chapter point saved' 2000 3\n" + self.send('edl_mark') + mess = "osd_show_text 'chapter point saved' 2000 3" if not self.show_osd: - self.send('osd 3\n%s' %mess) - self.after(2500, lambda:self.send('osd 0\n')) + self.send('osd 3%s' %mess) + self.after(2500, lambda:self.send('osd 0')) else: self.send(mess) def get_chapters(self): + """Read mplayer's editlist to get chapter points and return + HH:MM:SS.xxx format string, comma separated + """ # need a sleep to make sure mplayer gives up its data if not os.path.exists(self.editlist): return @@ -328,8 +408,8 @@ f = open(self.editlist) c = f.readlines() f.close() - # if chapter_var has value, editlist has been reset. Append value, if any. - # only 1st value on each line is taken (2nd is to make mplayer write out) + # if chapter_var has value, editlist has been reset. Append value. + # only 1st value on each line is taken (the 2nd makes mplayer write out) s = [ i.split()[0] for i in self.chapter_var.get().splitlines() if i] c.extend(s) times = [ float(shlex.split(i)[0]) for i in c ] @@ -339,13 +419,127 @@ chapters.append(time.strftime('%H:%M:%S', time.gmtime(t)) + fraction) if c: return '%s' %','.join(chapters) + + def on_eof(self): + """ + Run when 'End of file' discovered in mplayer output by poll(). + """ + f = open(self.editlist) + self.chapter_var.set(f.read()) + f.close() + +class SetChaptersGui(SetChapters): + """A standalone GUI to set video chapter points using SetChapters class""" + def __init__(self, master, args='', title='', callback=None): + """ + master + Pack into this widget + args + Additional args to pass to mplayer + title + Window manager titlebar title (master must be root window for this) + callback + Function to run on application exit, run before temp file cleanup + """ + SetChapters.__init__(self, master, args, title, callback) + self.callback = self.print_chapters + # bindings for exit + self._root().protocol("WM_DELETE_WINDOW", self.exit) + self._root().bind('<Control-q>', self.exit) + + + def add_widgets(self): + """Override add_widgets() from SetChapters, calling it first + then adding widgets to it + """ + SetChapters.add_widgets(self) + self.result_frame = tk.Frame(self) + self.text_frame = tk.Frame(self.result_frame) + self.result_frame.pack(side='bottom', fill='x', expand=1) + self.text_frame.pack(side='bottom', fill='x', expand=1) + self.load_button = tk.Button(self.text_frame, + command=self.load, text='Load Video') + self.load_button.pack(side='left', padx=5) + self.entry = tk.Entry(self.text_frame) + self.entry.insert(0, "00:00:00.0") + self.entry.pack(side='left', fill='x', expand=1) + self.exit_button = tk.Button(self.text_frame, + command=self.exit, text='Exit') + self.exit_button.pack(side='left') + # keep a list of mplayer controls so we can disable/enable them later + self.mp_ctrls = self.control_frame.winfo_children() + + def load(self, event=None): + """Load a file to play in the GUI""" + try: + from tkFileDialog import askopenfilename + except ImportError: + # python 3 + from tkinter.filedialog import askopenfilename + vid_name = askopenfilename() + if vid_name: + self.toggle_controls('normal', self.mp_ctrls) + # reset entry to 0 and chapter_var if we have a new video loaded + self.entry.delete(0, tk.END) + self.entry.insert(0, "00:00:00.0") + if self.pauseplay.get() == 'Pause': + self.pauseplay.set('Play') + self.run(vid_name) + + def print_chapters(self): + """ + Run get_chapters(), output result to stdout, entry box, and write + to tempory file. Disable mplayer controls. + This functions as the callback on mplayer exit. + """ + if self.get_chapters(): + try: + from tkMessageBox import askyesno, showinfo + except ImportError: + # python 3 + from tkinter.messagebox import askyesno, showinfo + output = self.get_chapters() + stdout.write(output + '\n') + self.entry.delete(0, tk.END) + self.entry.insert(0, output) + self.toggle_controls('disabled', self.mp_ctrls) + string1 = "Chapter string will be saved to: " + string2 = '\nDo you wish to save it ?' + #string2 += ' Choose "Yes" to save it.' + # get basename of video, remove extension, add a '_' + vid = os.path.basename(self.command[-1]) + '_' + tmpfile = mkstemp(prefix=vid) + if askyesno(title="Save chapter string", + message= '%s%s%s' %(string1, tmpfile[1], string2)): + save_msg = "%s%s\n" %('Saved ', tmpfile[1]) + showinfo(title='Chapters saved', message=save_msg) + if os.path.exists(tmpfile[1]): + f = open(tmpfile[1], 'w') + f.write(output) + f.close() + else: + os.remove(tmpfile[1]) + + def quit(self): + """Override quit() from base class, as standalone uses exit()""" + # disable controls, because tempdir has been deleted + self.toggle_controls('disabled', self.mp_ctrls) + if self.chapter_var.get(): + self.chapter_var.set('') + + def exit(self, event=None): + """Exit the GUI after confirming that mplayer is not running.""" + if self.is_running.get(): + self.confirm_msg() + else: + self.master.destroy() # class for control that allow setting chapter points class Chapters(ListToOne): """A popup version of the ListToOne Control, that also - allows setting chapter points with a mplayer GUI - (SetChapters). This Control is specific to the tovid GUI. + allows setting chapter points with a mplayer GUI + (SetChapters). This Control is specific to the tovid GUI. """ def __init__(self, parent, @@ -359,9 +553,9 @@ text='', **kwargs): """initialize Chapters - text - The text for the button that calls mplayer - For other options see help(control.ListToOne) + text + The text for the button that calls mplayer + For other options see help(control.ListToOne) """ ListToOne.__init__(self, parent, label, option, default, help, control, filter, side, **kwargs) @@ -371,7 +565,7 @@ self.top_height = 540 def draw(self, master): - """initialize Toplevel popup, video/chapters lists, and mplayer GUI. + """Initialize Toplevel popup, video/chapters lists, and mplayer GUI. Only pack the video/chapter lists (_SubList). Withdraw until called. """ chapters_button = tk.Button(master, text='edit', command=self.popup) @@ -387,7 +581,7 @@ ' 2. Or, use a different auto chapter value for each video.\n' + \ 'HH:MM:SS format:\n' + \ ' 1. Enter timecode for each video, eg. 00:00:00,00:05:00 ...\n' + \ - ' 2. Or use the "set with mplayer" button to use a GUI' + ' 2. Or use the "set with mplayer" button to use a GUI.' self.top.label = tk.Label(self.top, text=txt, justify=tk.LEFT) self.top.label.pack(side=tk.TOP) self.top_button = tk.Button(self.top, text='Okay', command=self.top.withdraw) @@ -413,14 +607,14 @@ def get_geo(self, widget): """Get geometry of a widget. - Returns List (integers): width, height, Xpos, Ypos + Returns List (integers): width, height, Xpos, Ypos """ geo = widget.winfo_geometry() return [ int(x) for x in geo.replace('x', '+').split('+') ] def center_popup(self, master, width, height): """Get centered screen location of popup, relative to master. - Returns geometry string in form of 'WxH+Xpos+Ypos' + Returns geometry string in form of 'WxH+Xpos+Ypos' """ root_width, root_height, rootx, rooty = self.get_geo(master) xoffset = (root_width - width) / 2 @@ -429,7 +623,7 @@ return '%dx%d+%d+%d' %(width, height, rootx + xoffset, rooty + yoffset) def popup(self): - """popup the list of chapters, with button to run mplayer GUI""" + """Popup the list of chapters, with button to run mplayer GUI""" videolist = self.parent_listbox self.top.transient(self.parent._root()) w = self.top_width @@ -440,7 +634,7 @@ self.parent_listbox.select_index(0) def run_mplayer(self, event=None): - """run the mplayer GUI to set chapters""" + """Run the mplayer GUI to set chapters""" selected = self.parent_listbox.selected.get() if selected: # initialize mplayer GUI @@ -460,9 +654,9 @@ self.top.bind('<Escape>', self.mpl.confirm_exit) def on_exit(self): - """callback run when mplayer GUI exits. This sets the chapters list - to the timecodes set by the mplayer gui, repacks the label and the - list frame, sets/resets bindings, and releases the grab_set(). + """Callback run when mplayer GUI exits. This sets the chapters list + to the timecodes set by the mplayer gui, repacks the label and the + list frame, sets/resets bindings, and releases the grab_set(). """ if self.mpl.get_chapters(): self.control.variable.set(self.mpl.get_chapters()) @@ -477,11 +671,12 @@ self.top.bind('<Escape>', self.withdraw_popup) def withdraw_popup(self, event=None): + """Withdraw the chapters popup window""" self.top.withdraw() def select(self, index, value): """Select an item in the list and enable editing. - List select method overriden in order to clear entry selection. + List select method overriden in order to clear entry selection. """ List.select(self, index, value) # don't make it easy to erase a chapters string with a keypress @@ -512,6 +707,185 @@ [noDupes.append(i) for i in seq if not noDupes.count(i)] return noDupes +def get_loadable_opts(opts): + good_opts = [] + bad_opts = [] + add_opt = False + for index, opt in enumerate(opts): + if opt.startswith('-'): + if opt in no_load_opts: + add_opt = False + else: + add_opt = True + # -colour is not loadable, but is a valid todisc option + if '-colour' in opt: + opt = opt.replace('-colour','-color') + if add_opt: + good_opts.append(opt) + else: + bad_opts.append(opt) + + return [good_opts, bad_opts] + +# this is part of the HACK in working around broken load_args +# load_script was lifted from gui.py in metagui, with mods +def load_script(filename): + #"""Load current script options and arguments from a text file. + #""" + # Read lines from the file and reassemble the command + command = '' + for line in open(filename, 'r'): + line = line.strip() + # Discard comment lines and PATH assignment + if line and not (line.startswith('#') or line.startswith('PATH=')): + command += line.rstrip('\\') + # Split the full command into arguments, according to shell syntax + args = shlex.split(command) + + # Ensure the expected program is being run + program = args.pop(0) + if program != 'todisc': + raise ValueError("This script runs '%s', expected '%s'" % + (program, 'todisc')) + return args + + +def filter_args(master=None, args=None): + # HACK + # we need to sanitize the GUI args as load_args in metagui is broken + # this function and imports of it can be removed when it is fixed + a = get_loadable_opts(args) + args = a[0] + if a[1]: + #import Tkinter as tk + from textwrap import dedent + heading = ''' + The tovid GUI did not load some of your options. + This is normal as loading options externally + is experimental. Sorry for the inconvenience. + + You can copy this for reference as you will need + to set the following options yourself in the GUI: + + ''' + + #u = unloadable_opts[:] + #data = ['\n' + x + '\n' if x.startswith('-') else x for x in u] + nonloadable = [] + for i in a[1]: + if i.startswith('-'): + nonloadable.append('\n' + i) + elif ' ' in i: + nonloadable.append("'" + i + "'") + else: + nonloadable.append(i) + #data = ' '.join(nonloadable) + master.title('Important!') + info_msg = CopyableInfo(master, 'Important', dedent(heading), + ' '.join(nonloadable), tovid_icon) + info_msg.mainloop() + return args + + +from libtovid.metagui.support import show_icons +from libtovid.metagui import Style +class CopyableInfo(tk.Frame): + def __init__(self, master, title='', heading='', data='', icon=None): + tk.Frame.__init__(self, master) + self.pack() + master.minsize(300, 300) + text_frame = tk.Frame(self) + text_frame.pack(side='top') + style = Style() + inifile = os.path.expanduser('~/.metagui/config') + if os.path.exists(inifile): + style.load(inifile) + font = style.font or None + else: + font = None + text_widget = tk.Text(text_frame, width=50, height=20, wrap='word') + text_widget["bg"] = self.cget('background') + text_widget["relief"] = 'flat' + master["relief"] = 'flat' + if font: + text_widget["font"] = font + text_widget.pack(side='top', fill='both', expand=1) + text_widget.insert('1.0',heading) + #text_widget.bind("<1>", self.set_focus(self, text_widget)) + text_widget.insert('end',data) + text_widget['state'] = 'disabled' + lines = int(text_widget.index('end-1c').split('.')[0]) + text_widget['height'] = lines + 3 + rclick = RightClickMenu(text_widget) + text_widget.bind("<3>", rclick) + exit_button = tk.Button(self, text='Close', + command=lambda:self._quit()) + #exit_button.focus_set() + exit_button.pack(side='bottom') + master.bind('<Control-q>', lambda event=None: self._quit()) + master.bind('<Escape>', lambda event=None: self._quit()) + if icon: + show_icons(self.master, icon) + master.update_idletasks() # update geometry + # center the popup + m = master + x = int((m.winfo_screenwidth() / 2) - (m.winfo_width() /2)) + y = int((m.winfo_screenheight() / 2) - int((m.winfo_height() /2))) + master.geometry('+%s+%s' %(x, y)) + + + + def _quit(self, event=None): + self.master.destroy() + #self.master.destroy() + + +class RightClickMenu(object): + # thanks to 'paperrobot' at: + # http://paperrobot.wordpress.com for this gem + """ + Simple widget to add basic right click menus to entry widgets. + + usage: + + rclickmenu = RightClickMenu(some_entry_widget) + some_entry_widget.bind("<3>", rclickmenu) + + Replace all Tix references with Tkinter and this will still work fine. + """ + def __init__(self, parent): + self.parent = parent + # bind Control-A to select_all() to the widget. Others work ok without + self.parent.bind("<Control-a>", lambda e: self.select_all(), add='+') + self.parent.bind("<Control-A>", lambda e: self.select_all(), add='+') + def __call__(self, event): + # grab focus of the entry widget. this way you can see + # the cursor and any marking selections + self.parent.focus_force() + self.build_menu(event) + def build_menu(self, event): + self.menu = tk.Menu(self.parent, tearoff=0) + #self.parent.bind("<Button-1>", self.close_menu) + #self.parent.bind("<Escape>", self.close_menu) + if self.parent.tag_ranges("sel"): + self.menu.add_command( + label="Copy", + command=lambda: self.parent.event_generate("<<Copy>>")) + else: + self.menu.add_command(label="Copy", state=tk.DISABLED) + self.menu.add_command(label="Cut", state=tk.DISABLED) + self.menu.add_command(label="Paste", state=tk.DISABLED) + # make things pretty with a horizontal separator + self.menu.add_separator() + self.menu.add_command(label="Select All", command=self.select_all) + self.menu.tk_popup(event.x_root, event.y_root) + def select_all(self): + self.parent.tag_add(tk.SEL, 1.0, tk.END) + # return 'break' because doesn't work otherwise. + return 'break' + + + # List of file-type selections for Filename controls image_filetypes = [filetypes.image_files] image_filetypes.append(filetypes.all_files) @@ -519,7 +893,7 @@ # video file-types from filetypes needs some additions v_filetypes = 'm2v vob ts ' v_filetypes += filetypes.get_extensions('video').replace('*.', '') -v_filetypes += ' mp4 mpeg4 mp4v divx mkv ogv ogm ram rm rmvb wmv' +v_filetypes += ' mp4 mpeg4 mp4v divx mkv ogv ogm ram rm rmvb wmv webm' vid_filetypes = filetypes.new_filetype('Video files', v_filetypes) video_filetypes = [vid_filetypes] video_filetypes += [filetypes.all_files] @@ -537,6 +911,12 @@ # Users can use their own thumb masks. Add to thumb mask control drop-down masks = [ 'none', 'normal', 'oval', 'vignette', 'plectrum', 'arch', 'spiral', \ 'blob', 'star', 'flare' ] + +# some options can not be loaded by the gui: +# options with multiple choices for args, for example: none, single, multiple +# this is a list of 'unloadable' options for the GUI +no_load_opts = ['-chapter-titles', '-menu-fade', '-loop', '-video-pause', '-group-video-pause', '-slide-blur', '-slide-border', '-slide-frame', '-chain-videos', '-showcase', '-titles-font-deco', '-chapters', '-subtitle-lang', '-audio-channel', '-audio-lang', '-seek', '-showcase-seek', '-bg-video-seek', '-bgvideo-seek', '-bg-audio-seek', '-bgaudio-seek', '-submenu-audio-seek', '-rotate-thumbs', '-tile3x1', '-tile-3x1', '-tile4x1', '-tile-4x1'] + # $PREFIX/lib/tovid is already added to end of PATH os_path = os.environ['PATH'].rsplit(':') sys_dir = os_path[-1] + '/masks' @@ -544,11 +924,16 @@ for dir in sys_dir, home_dir: masks.extend(find_masks(dir, '*.png')) thumb_masks = '|'.join(nodupes(masks)) -tovid_prefix = commands.getoutput('tovid -prefix') +tovid_prefix = getoutput('tovid -prefix') tovid_icon = os.path.join(tovid_prefix, 'lib', 'tovid', 'tovid.png') +# default heading text for tovid GUI (opening pane) +heading_text = 'You can author (and burn) a DVD with a simple menu ' +heading_text += 'using ONLY this "Basic" pane\n' +heading_text += 'Required: video files (and/or slideshows) and "Output name"' + ### configuration for titleset wizard ( 'tovid titlesets' ) -wizard = os.getenv('METAGUI_WIZARD') +wizard = os.getenv('METAGUI_WIZARD') or '0' if wizard == '1': # General options heading_text = 'General options applying to all titlesets.\n' @@ -562,10 +947,6 @@ # titleset options heading_text = 'Options for titleset %s\n' %(int(wizard) - 2) heading_text += 'Required: 1 or more videos and/or slideshows' -else: - heading_text = 'You can author (and burn) a DVD with a simple menu ' - heading_text += 'using ONLY this "Basic" pane\n' - heading_text += 'Required: video files (and/or slideshows) and "Output name"' if wizard == '2': # Root menu options @@ -586,7 +967,7 @@ Text(), filter=to_title) -if wizard and wizard != '1': +if int(wizard) and wizard != '1': # 'Output name' only for General Options ( '1' ) _out = Label(' ') else:
View file
tovid-0.34.tar.bz2/libtovid/guis/todisc.py -> tovid-0.35.tar.gz/libtovid/guis/todisc.py
Changed
@@ -3,7 +3,11 @@ """A GUI for the todisc command-line program. """ -import Tkinter as tk +try: + import Tkinter as tk +except ImportError: + # python 3 + import tkinter as tk # Get supporting classes from libtovid.metagui from libtovid.metagui import * @@ -75,11 +79,10 @@ Number('Columns', '', 13, '', 0, 13)) _quick_menu = Flag('Quick menu (may need a menu video)', - '-quick-menu', False, 'Note: may not be available in your ffmpeg ' - 'as the needed "vhooks" have been deprecated. Ten times faster than ' - 'normal showcase animation. A showcase or background video is required ' - 'unless doing switched menus. Menu links are text only. Not compatible ' - 'with wave or rotate options.') + '-quick-menu', False, 'Note: you need a recent ffmpeg with the "movie" ' + 'filter enabled. Ten times faster than normal showcase animation. A ' + 'showcase or background video is required unless doing switched menus. ' + 'Menu links are text only. Not compatible with wave or rotate options.') _switched_menus = Flag('Switched menus (try with "Quick menu" !)', '-switched-menus', False, @@ -377,8 +380,9 @@ _thumb_shape = Choice('Thumb shape', '-thumb-shape', 'none', 'Apply a shaped transparency mask to thumbnail videos or images. These ' '"feathered" shapes look best against a plain background or used with ' - '**-thumb-mist** [COLOR]. To use a "mist" background behind each thumb, ' + '-thumb-mist [COLOR]. To use a "mist" background behind each thumb, ' 'see "Thumb mist" section. No frame will be used for this option. ' + 'See "man tovid" (-thumb-shape) for info on how to add your own masks.' 'Leave at "none" to not use a feathered shape.', thumb_masks, 'dropdown') @@ -449,8 +453,11 @@ '(4 videos only). Not a showcase option.') _align = Choice('Align', '-align', 'north', - 'Controls positioning of the thumbnails and their titles. ' - 'With some arrangements this will have limited effects however.', + 'Controls positioning of the thumbnails (if any) and video titles. ' + 'With some arrangements this will have limited effects however.' + 'For example only north|south|center can be used with the default montage ' + 'of thumbs arrangement, or with showcase with thumb arrangement. ' + 'It will be most effective with single column showcase and textmenu styles', 'north|south|east|west|center', 'dropdown') _seek = SpacedText('Thumbnail seek(s)', '-seek', '', @@ -458,16 +465,19 @@ 'A single value or space separated list, 1 value per video. ' 'Also used for seeking in switched menus.') +_user_thumbs = List('Image(s)', '-user-thumbs', None, + 'Images for thumbnails. This option requires one image for each title.', + Filename('', filetypes=image_filetypes)) ### -------------------------------------------------------------------- ### Fonts and font colors ### -------------------------------------------------------------------- # Menu title font -_menu_font = Font('', '-menu-font', 'Helvetica', +_menu_font = Font('', '-title-font', 'Helvetica', 'The font to use for the menu title') -_menu_fontsize = Number('Size', '-menu-fontsize', 24, +_menu_fontsize = Number('Size', '-title-fontsize', 24, 'The font size to use for the menu title', 0, 80, 'pixels', toggles=True) @@ -492,6 +502,9 @@ # Video title font _titles_font = Font('', '-titles-font', 'Helvetica', 'The font to use for the video titles') +# unused FIXME +_titles_font_deco = SpacedText('Custom font decoration', '', '', + 'Space-separated list of custom options to imagemagick.'), _titles_fontsize = Number('Size', '-titles-fontsize', 12, 'The font size to use for the video titles. ' @@ -779,10 +792,11 @@ ), VPanel('Backgrounds', VPanel('Image or video options', - _bgvideo_seek, - _bg_color), + HPanel('', _bgvideo_seek, + _bg_color)), VPanel('Audio options', HPanel('', _bgaudio_seek, _menu_audio_fade)), + HPanel('Menu alignment', _align), ), ), ), @@ -872,7 +886,7 @@ HPanel('', Number('Number of slides shown on menu', '-menu-slide-total', 0, 'Use this many slides for making the slideshow menu. ' - 'The default is to use all the slides given.', + 'Leave at 0 for default: use all slides given.', 0, 100), _submenu_slide_total, ), @@ -906,10 +920,16 @@ slideshows = Tabs('Slideshows', *tab_list) -thumbnails = VPanel("Thumbnails", +thumbnails = Tabs("Thumbnails", + VPanel('Menu link thumbnails', + VPanel('', HPanel('', - VPanel('Menu link thumbnails', - HPanel('Seeking', _seek), + VPanel('', + HPanel('', + VPanel('Aspect ratio', Label('Automatic: force video ratio on "Playback" tab')), + VPanel('Seeking', _seek), + ), + HPanel('', VPanel("Effects", HPanel('',_opacity, Label('(Also affects showcase thumb)')), HPanel('', _blur, _3dthumbs), @@ -920,11 +940,21 @@ _thumb_framesize, _thumb_frame_color, _thumb_columns, - _align, + ), ), ), + ), + VPanel('User supplied thumbs', + VPanel('', + Label("Use this only if you want to substitute your own thumbs for default thumbnails.", 'center'), + _user_thumbs, + ), + ), + ), + ), VPanel("Showcase thumbnail", HPanel('Seeking', _showcase_seek), + HPanel('', VPanel('Effects', _wave, HPanel('', _showcase_blur, _3dshowcase), @@ -936,9 +966,7 @@ _showcase_frame_color, _showcase_geo), ), - ), - HPanel('Aspect ratio', Label('Note: the aspect ratio of menu link ' - 'thumbnails is automatic: (force video ratio on "Playback" tab)')), + ), ) from libtovid.guis import tovid @@ -975,23 +1003,68 @@ encoding = VPanel('Encoding', Label("\nVideo re-encoding options - you may leave these at defaults.", 'center'), - Tabs('tovid options', + Tabs('', tovid.BASIC_OPTS, tovid.VIDEO, tovid.AUDIO, tovid.BEHAVIOR, ), - SpacedText('Custom makempg options', '', '', + Flag('Encode only', '-encode-only', False, + 'Use this GUI for encoding only. On the Main tab, load files and ' + 'select an out filename'), + SpacedText('Custom makempg ("tovid mpg") options', '', '', 'Space-separated list of custom options to pass to makempg.'), + ) ### -------------------------------------------------------------------- -def run(args=None): +def run(args=None, position='', project=''): + from libtovid.guis.helpers import get_loadable_opts, load_script + import os + # if the first arg is a text file, treat it as a script and try to load + # the options from it as a list into args + # load_script from helpers overrides load_script from gui.py as the latter + # suffers from the load_args bug mentioned in that file. + if args: + script = args[0] + if not script.startswith('-'): + try: + from commands import getoutput + except ImportError: + # python 3 + from subprocess import getoutput + if os.path.exists(script) \ + and 'text' in getoutput('file %s' %script): + script = args.pop(0) + args.extend(load_script(script)) + # now check if we have unloadable options, this first call does only that + # this will return 2 lists, [0] is loadable and [1] is unloadable + # probably don't want to do this anyway, as filter_args will just return + # the args it is sent if none are unloadable + a = get_loadable_opts(args) + if a[1]: + from libtovid.guis.helpers import filter_args + r = tk.Tk() + args = filter_args(r, args) + # workaround for netbooks (could use xrandr perhaps, but this works fine) + gui_width, gui_height = 800, 660 + root = tk.Tk() + root.withdraw() + root.update_idletasks() + screen_height = root.winfo_screenheight() + # insure screen is not 800x600 or somesuch which doesn't work for gui anyway + # need float like 1.3333333 that we multiply * 100 and convert back to int + screen_width = float(root.winfo_screenwidth()) + if int(screen_height) < 660 and not int(screen_width / screen_height * 100) == 133: + gui_height = 600 + root.destroy() + + # finally, run it app = Application('todisc', main, main_menu, submenus, thumbnails, slideshows, playback, behavior, encoding) - gui = GUI("tovid gui", 800, 660, app, icon=tovid_icon) - gui.run(args) + gui = GUI("tovid gui", gui_width, gui_height, app, icon=tovid_icon, position=position) + gui.run(args, script=project) if __name__ == '__main__':
View file
tovid-0.34.tar.bz2/libtovid/guis/tovid.py -> tovid-0.35.tar.gz/libtovid/guis/tovid.py
Changed
@@ -78,7 +78,7 @@ 0, 4400, units='MiB') # Encoder options -_mplayeropts = SpacedText('mplayer options', '-mplayeropts', '', 'TODO: Tooltip') +_mplayeropts = Text('mplayer options', '-mplayeropts', '', 'TODO: Tooltip') _filters = Choice('mplayer filters', '-filters', 'none', 'TODO: Tooltip', 'none|denoise|deblock|contrast|all', side='top') _ffmpeg = Flag('Encode using ffmpeg', '-ffmpeg', False)
View file
tovid-0.34.tar.bz2/libtovid/metagui/control.py -> tovid-0.35.tar.gz/libtovid/metagui/control.py
Changed
@@ -28,9 +28,11 @@ def any(iterable): """Return True if bool(x) is True for any x in iterable.""" for item in iterable: - if not item: - return False - return True + if item: + return True + return False + + # Python < 3.x try: @@ -45,6 +47,9 @@ (asksaveasfilename, askopenfilename, askopenfilenames) from tkinter.colorchooser import askcolor +# Python 3.x +from libtovid import basestring + from libtovid.metagui.widget import Widget from libtovid.metagui.variable import VAR_TYPES, ListVar from libtovid.metagui.support import \ @@ -472,7 +477,10 @@ """Event handler to update the color preview. """ color = self.variable.get().strip() - self.set(color) + try: + self.set(color) + except (ValueError): + pass def pick_color(self): @@ -1000,7 +1008,8 @@ def next_item(self, event): """Select the next item in the parent listbox. """ - self.parent_list.listbox.next_item(event) + if self.parent_list is not None: + self.parent_list.listbox.next_item(event) class SpacedText (Text):
View file
tovid-0.34.tar.bz2/libtovid/metagui/gui.py -> tovid-0.35.tar.gz/libtovid/metagui/gui.py
Changed
@@ -11,32 +11,35 @@ import tempfile import shlex import subprocess -from sys import exit +from sys import exit, argv # Python < 3.x try: + import Tix import Tkinter as tk from ScrolledText import ScrolledText - from tkFileDialog import \ - (asksaveasfilename, askopenfilename) from tkMessageBox import showinfo, showerror - import Tix + from tkFileDialog import ( + asksaveasfilename, askopenfilename + ) # Python 3.x except ImportError: import tkinter as tk + import tkinter.tix as Tix from tkinter.scrolledtext import ScrolledText - from tkinter.filedialog import \ - (asksaveasfilename, askopenfilename) from tkinter.messagebox import showinfo, showerror - import tkinter.tix as Tix + from tkinter.filedialog import ( + asksaveasfilename, askopenfilename + ) from libtovid import cli from libtovid.metagui.widget import Widget from libtovid.metagui.panel import Panel, Tabs -from libtovid.metagui.support import \ - (ConfigWindow, Style, ensure_type, askyesno, get_photo_image, show_icons) from libtovid.metagui.control import Control, NoSuchControl +from libtovid.metagui.support import ( + ConfigWindow, Style, ensure_type, askyesno, get_photo_image, show_icons + ) DEFAULT_CONFIG = os.path.expanduser('~/.metagui/config') @@ -210,6 +213,7 @@ self.notify("Output saved to '%s'" % filename) +from textwrap import dedent class Application (Widget): """Graphical frontend for a command-line program """ @@ -246,10 +250,14 @@ """Draw the Application in the given master. """ Widget.draw(self, master) + self.master = master # Draw all panels as tabs self.tabs = Tabs('', *self.panels) self.tabs.draw(self) self.tabs.pack(anchor='n', fill='both', expand=True) + # need to wait until draw is called before setting this variable + self.script = tk.StringVar() + self.script.set('') def draw_toolbar(self, config_function, exit_function): @@ -328,6 +336,13 @@ self.executor.notify("Cancelled.") self.toolbar.enable() + def set_scriptname(self, name): + """Set script filename. Called externally, this sets the variable + that used used for save_exit() as well as the 'initial file' for + prompt_save_script(). + """ + self.script.set(name) + def prompt_save_script(self): """Prompt for a script filename, then save the current @@ -336,7 +351,8 @@ # TODO: Make initialfile same as last saved script, if it exists filename = asksaveasfilename(parent=self, title="Select a filename for the script", - initialfile='%s_commands.bash' % self.program) + #initialfile='%s_commands.bash' % self.program) + initialfile=self.script.get() or '%s_commands.bash' % self.program) if not filename: return @@ -347,20 +363,34 @@ showerror(title="Error", message="Failed to save '%s'" % filename) raise else: + saved_script = os.path.split(filename)[1] showinfo(title="Script saved", message="Saved '%s'" % filename) def save_exit(self): - filename = os.getcwd() + os.path.sep + '%s_commands.bash' % self.program + """Save current command to script and exit, without prompt + """ + # hack for titleset wizard to get gui's screen position + from sys import stderr + stderr.write("%s %+d%+d" + %('gui position', self._root().winfo_x(), self._root().winfo_y())) + + default = os.getcwd() + os.path.sep + '%s_commands.bash' % self.program + filename = self.script.get() or default self.save_script(filename) - # exit code borrowed from apache so wizard knows it has a file to read - exit(200) + exit() def prompt_load_script(self): - """Prompt for a script filename, then load current Control settings - from that file. + """Prompt for script filename; reload gui with current Control settings """ + #"""Prompt for a script filename, then load current Control settings + #from that file. + #""" + # Hack: This is broken (commented section), presumably because of + # load_args limitations. This hack fixes it for libtovid, but does not + # belong in metagui. So refactor this when load_args is fixed. + # see http://code.google.com/p/tovid/issues/detail?id=121 filename = askopenfilename(parent=self, title="Select a shell script or text file to load", filetypes=[('Shell scripts', '*.sh *.bash'), @@ -368,15 +398,23 @@ if not filename: return - + # begin Hack + geometry = self._root().winfo_x(), self._root().winfo_y() + command = argv[0] try: - self.reset() - self.load_script(filename) + cmd = command, '--position', '+%s+%s' %geometry, filename + os.execlp(cmd[0], *cmd) except: - showerror(title="Error", message="Failed to load '%s'" % filename) + showerror(title="Error", message="Failed load '%s'" %filename) raise - else: - showinfo(title="Script loaded", message="Loaded '%s'" % filename) + #try: + # self.reset() + # self.load_script(filename) + #except: + # showerror(title="Error", message="Failed to load '%s') + # raise + #else: + # showinfo(title="Script loaded", message="Loaded '%s'" % filename) def save_script(self, filename): @@ -398,26 +436,29 @@ def load_script(self, filename): - """Load current Control settings from a text file. - """ + # this is now disabled and its functionality passed to guis.helpers.py + # see http://code.google.com/p/tovid/issues/detail?id=121 + pass + #"""Load current Control settings from a text file. + #""" # Read lines from the file and reassemble the command - command = '' - for line in open(filename, 'r'): - line = line.strip() + #command = '' + #for line in open(filename, 'r'): + # line = line.strip() # Discard comment lines and PATH assignment - if line and not (line.startswith('#') or line.startswith('PATH=')): - command += line.rstrip('\\') + # if line and not (line.startswith('#') or line.startswith('PATH=')): + # command += line.rstrip('\\') # Split the full command into arguments, according to shell syntax - args = shlex.split(command) + #args = shlex.split(command) # Ensure the expected program is being run - program = args.pop(0) - if program != self.program: - raise ValueError("This script runs '%s', expected '%s'" % - (program, self.program)) + #program = args.pop(0) + #if program != self.program: + # raise ValueError("This script runs '%s', expected '%s'" % + # (program, self.program)) # Load the rest of the arguments - self.load_args(args) - print("Done reading '%s'" % filename) + #self.load_args(args) + #print("Done reading '%s'" % filename) # TODO: Relocate all this stuff into Control and its subclasses @@ -484,6 +525,8 @@ Name of an .ini-formatted file with GUI configuration icon Full path to an image to use as the titlebar icon + position + position on screen: '+X+Y' """ Tix.Tk.__init__(self) @@ -491,19 +534,20 @@ ensure_type("GUI needs Application", Application, application) self.application = application + # Get keyword arguments + self.inifile = kwargs.get('inifile', DEFAULT_CONFIG) + self.icon_file = kwargs.get('icon', None) + self.position = kwargs.get('position', '') + # Set main window attributes - self.geometry("%dx%d" % (width, height)) + self.geometry("%dx%d%s" % (width, height, self.position)) self.title(title) self.width = width self.height = height - # Get keyword arguments - self.inifile = kwargs.get('inifile', DEFAULT_CONFIG) - self.icon_file = kwargs.get('icon', None) - self.style = Style() if os.path.exists(self.inifile): - print("Loading style from config file: '%s'" % self.inifile) + print("Loading style from the config file: '%s'" % self.inifile) self.style.load(self.inifile) else: print("Creating config file: '%s'" % self.inifile) @@ -519,11 +563,14 @@ self.bind('<Control-q>', self.confirm_exit) - def run(self, args=None): + def run(self, args=None, script=''): """Run the GUI and enter the main event handler. This function does not return until the GUI is closed. + args: arguments to the programe being run + script: a filename to save the GUI command output to """ self.draw() + if args: # If first argument looks like a filename, load # a script from that file @@ -541,6 +588,9 @@ # If more args remain, load those too if args: self.application.load_args(args) + # if a script/project name was provided, set it in 'application' + if script: + self.application.set_scriptname(script) # Enter the main event handler self.mainloop() @@ -581,6 +631,11 @@ def confirm_exit(self, event=None): """Exit the GUI, with confirmation prompt. """ + # Hack to sync titleset wizard's position with exiting GUI's position + if os.getenv('METAGUI_WIZARD'): + from sys import stderr + stderr.write("%s %+d%+d" + %('gui position', self._root().winfo_x(), self._root().winfo_y())) if askyesno(message="Exit?"): self.quit()
View file
tovid-0.34.tar.bz2/libtovid/metagui/panel.py -> tovid-0.35.tar.gz/libtovid/metagui/panel.py
Changed
@@ -19,14 +19,15 @@ except ImportError: import tkinter as tk +from base64 import b64encode from libtovid import cli from libtovid.odict import Odict from libtovid.metagui.widget import Widget from libtovid.metagui.control import Control, Flag -from libtovid.metagui.support import \ - (ComboBox, ensure_type, divide_list, get_photo_image) from libtovid.metagui.variable import ListVar -from base64 import b64encode +from libtovid.metagui.support import ( + ComboBox, ensure_type, divide_list, get_photo_image + ) class Label (Widget):
View file
tovid-0.34.tar.bz2/libtovid/metagui/support.py -> tovid-0.35.tar.gz/libtovid/metagui/support.py
Changed
@@ -43,6 +43,16 @@ import tkinter.tix as Tix import tkinter.font as tkFont +# Python 2.4 +try: + all +except NameError: + def all(iterable): + for element in iterable: + if not element: + return False + return True + from libtovid import cli from libtovid.util import imagemagick_fonts from libtovid.metagui.variable import ListVar
View file
tovid-0.34.tar.bz2/libtovid/metagui/widget.py -> tovid-0.35.tar.gz/libtovid/metagui/widget.py
Changed
@@ -12,6 +12,9 @@ except ImportError: import tkinter as tk +# Python 3 compatibility +from libtovid import basestring + class Widget (tk.Frame): """Generic metagui widget, suitable for Controls, Panels, etc. """
View file
tovid-0.34.tar.bz2/libtovid/util/__init__.py -> tovid-0.35.tar.gz/libtovid/util/__init__.py
Changed
@@ -24,6 +24,8 @@ import doctest import mimetypes import tempfile +# Python 3 compatibility +from libtovid import basestring, unicode # Special characters that may need escaping special_chars = '\\ #*:;&?!<>[]()"\'' @@ -89,14 +91,21 @@ # Split text into lines, converting tabs to spaces lines = text.expandtabs().splitlines() # Determine minimum indentation (except first line) - indent = sys.maxint + try: + MAXINT = sys.maxint + # python 3 compatibility + except AttributeError: + MAXINT = sys.maxsize + + indent = MAXINT + for line in lines[1:]: stripped = line.lstrip() if stripped: indent = min(indent, len(line) - len(stripped)) # Remove indentation (first line is special) trimmed = [lines[0].strip()] - if indent < sys.maxint: + if indent < MAXINT: for line in lines[1:]: # Append line, minus indentation trimmed.append(line[indent:].rstrip()) @@ -250,7 +259,7 @@ """Print a message and pause for the given number of seconds. """ print("Resuming in %s seconds..." % seconds) - os.system('sleep %ss' % seconds) + os.system('sleep %s' % seconds) def imagemagick_version():
View file
tovid-0.34.tar.bz2/setup.py -> tovid-0.35.tar.gz/setup.py
Changed
@@ -20,7 +20,12 @@ as a string like 'svn-r1234'. If svn is not installed, or if something goes wrong, return 'svn-unknown' """ - from commands import getoutput + try: + from commands import getoutput + except ImportError: + # python 3 + from subprocess import getoutput + rev_line = getoutput('svn info 2>/dev/null | grep ^Revision') # If rev_line is found, get the revision number if rev_line: @@ -39,7 +44,7 @@ # Current SVN version number #_tovid_version = svn_version() # Official release number -_tovid_version = '0.34' +_tovid_version = '0.35' import os @@ -181,7 +186,7 @@ # Build tovid-init with regular 'build' command build.sub_commands.append(('build_tovid_init', None)) -#build.sub_commands.append(('build_docs', None)) +build.sub_commands.append(('build_docs', None)) # The actual setup setup( @@ -205,8 +210,6 @@ 'libtovid.guis', 'libtovid.util', 'libtovid.metagui', - 'libtovid.render', - 'libtovid.backend', ], # Executable files go into /$PREFIX/bin/ @@ -222,17 +225,10 @@ # Bash scripts 'src/idvid', 'src/makedvd', - 'src/makemenu', - 'src/makevcd', - 'src/makexml', - 'src/postproc', 'src/todisc', 'src/todisc-fade-routine', 'src/makempg', - 'src/tovid-batch', 'src/tovid-init', - 'src/tovid-interactive', - 'src/make_titlesets', # Python scripts 'src/todiscgui',
View file
tovid-0.34.tar.bz2/src/idvid -> tovid-0.35.tar.gz/src/idvid
Changed
@@ -1,5 +1,4 @@ #!/usr/bin/env bash -#set -u ME="[idvid]:" . tovid-init 2>/dev/null || @@ -8,7 +7,6 @@ echo -e "Or are you trying to run the script directly?" echo -e "Please run idvid as:\ntovid id OPTIONS" exit 1 ; } - # idvid # Part of the tovid suite # ======================= @@ -17,7 +15,7 @@ # # Project homepage: http://tovid.wikia.com # -# Copyright (C) 2005-2010 +# Copyright (C) 2005-2015 # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -53,6 +51,7 @@ -terse Suitable for parsing -verbose Also use ffmpeg and tcprobe -accurate Do accurate duration estimation + -keepfiles Keep temporary directory for debugging -isformat [ntsc-vcd|pal-vcd|ntsc-svcd|pal-svcd|ntsc-dvd|pal-dvd] Tell whether the first file is compliant with the given format; prints "true" or "false" (returns shell 0 or 1) @@ -89,8 +88,9 @@ MATCH_FORMAT="" MATCH_TVSYS="" TABULAR=false -USE_MENCODER=: +GET_FFMPEG_LEN=: USE_NAVLOG=false +KEEPFILES=false ID_FILES="" mkdir -p "$STAT_DIR" @@ -140,18 +140,36 @@ echo "Identifying video with ffmpeg..." echo $SEPARATOR # ffmpeg puts its output on standard error - ffmpeg -i "$INFILE" 2>&1 | tee -a "$SCRATCH_FILE" + $FFmpeg -i "$INFILE" 2>&1 | tee -a "$SCRATCH_FILE" else - ffmpeg -i "$INFILE" >> "$SCRATCH_FILE" 2>&1 + $FFmpeg -i "$INFILE" >> "$SCRATCH_FILE" 2>&1 fi fi + # avconv messed with formatting, so we need to move to ffprobe/avprobe + # ffprobe and avprobe show slightly different formatting, but this should do + # adds a new line after [/STREAM] (ffmpeg). avconv already has it. + if test -n $FFprobe; then + i=0 + while IFS= read -r line; do + [[ $line ]] || { ((++i)); continue; } + probe_info[i]+=$line$'\n' + done < <($FFprobe -show_streams "$INFILE" 2>/dev/null | \ + sed '/\[\/STREAM\]/{G;s/$//;};/DISPOSITION/d') + fi + # avprobe begins with a # comment\n so delete that index and flatten array + for i in ${!probe_info[@]}; do + grep -q '^#' <<< ${probe_info[i]} && unset probe_info[i] + done + # if index 0 is unset flatten array + [[ ${probe_info[0]+unset} ]] || probe_info=( "${probe_info[@]}" ) + # Identify video using tcprobe if test -n "$TCPROBE"; then if $VERBOSE ; then echo $SEPARATOR echo "Identifying video with tcprobe..." echo $SEPARATOR - tcprobe -i "$INFILE" 2>&1 | tee -a "$SCRATCH_FILE" + tcprobe -i "$INFILE" 2>&1 | tee -a "$SCRATCH_FILE" 2>/dev/null else tcprobe -i "$INFILE" >> "$SCRATCH_FILE" 2>/dev/null fi @@ -169,6 +187,10 @@ fi exit 1 fi + # remove ffmpeg metadata from scratch file + # make portable for bsd sed etc + #sed '/Metadata/,/Duration/{//!d}' "$SCRATCH_FILE" > "${SCRATCH_FILE}2" + #mv "${SCRATCH_FILE}2" "$SCRATCH_FILE" # Defaults. Many of these values may be overridden by # vars from mplayer's output to be sourced later. @@ -190,14 +212,15 @@ V_DURATION="" ID_LENGTH="0" - # bash appears to have no way of initializing empty arrays; we append to these later, - # so unsetting them clears out their previous contents - unset A_SAMPRATES - unset A_BITRATES - unset A_CODECS - unset A_HEX_TRACKS - unset A_TRACKS - unset wavs + # arrays + A_SAMPRATES=() + A_BITRATES=() + A_CODECS=() + A_HEX_TRACKS=() + A_TRACKS=() + MPL_AIDS=() + wavs=() + probe_audio_info=() # send formated mplayer's output to a vars file to be sourced to set relevant variables. # (ID_V(ideo), ID_A(udio), and ID_L(ength)) @@ -212,25 +235,33 @@ # get array of mplayer audio ids, used if no hextracks from ffmpeg while read; do MPL_AIDS+=(${REPLY##*=}); done < <(grep ID_AUDIO_ID "$SCRATCH_FILE") - ID_VIDEO_FRAMES=$(grep 'length:' "$SCRATCH_FILE" | \ - awk -F ' ' '{print $2}') - test -z $ID_VIDEO_FRAMES && ID_VIDEO_FRAMES="0" - - # ffmpeg has a better concept of the actual bitrate than mplayer - TOTAL_AV_BITRATE=$(awk -F: '{gsub("kb/s", "")}; /bitrate:/ {print $6*1000}' "$SCRATCH_FILE") - ## take the lower of the two - if test $ID_VIDEO_BITRATE -eq 0 || test $TOTAL_AV_BITRATE -lt $ID_VIDEO_BITRATE; then - # make sure we have a value from ffmpeg - if test_is_number $TOTAL_AV_BITRATE; then - ID_VIDEO_BITRATE=$TOTAL_AV_BITRATE + # try tcprobe to determine length (# of frames) + # assuming it is installed, otherwise this should 'fail' silently + ID_VIDEO_FRAMES=$(awk '/length:/ {print $2}' "$SCRATCH_FILE") + ((ID_VIDEO_FRAMES)) || ID_VIDEO_FRAMES="0" + + FF_V_BITRATE=$(sed -n 's/.*Stream.*Video:.*\(\ [0-9][0-9][0-9]*\) kb\/s.*/\1/p' "$SCRATCH_FILE" |uniq) + FF_V_BITRATE=${FF_V_BITRATE// /} # trim spaces + # make sure we have a value from ffmpeg (a number and non zero) + if test_is_number "$FF_V_BITRATE" && (( FF_V_BITRATE )); then + # kilobits to bits + ID_VIDEO_BITRATE=${FF_V_BITRATE}000 + elif [[ -z $ID_VIDEO_BITRATE || $ID_VIDEO_BITRATE = 0 ]]; then + mplayer_stats_br=$(sed '/VIDEO:/!d;s/.*(//; s/).*=\ /:/;s/[kK][bB].*//g' "$SCRATCH_FILE") + # make an integer + mplayer_stats_br=${mplayer_stats_br%.*} + # make sure it is a number + if test_is_number $mplayer_stats_br && (( mplayer_stats_br )); then + ID_VIDEO_BITRATE=$(( mplayer_stats_br * 8 * 1000 )) fi - else - ID_VIDEO_BITRATE=$ID_VIDEO_BITRATE fi + # if mplayer decides there is no video, unset ID_VIDEO_BITRATE + # else it will still show a value from TOTAL_AV_BITRATE + grep -qi "no video" "$SCRATCH_FILE" && unset ID_VIDEO_BITRATE # if we still don't have a value for ID_VIDEO_WIDTH and ID_VIDEO_HEIGHT MP_FRAMESIZE=$(awk '/=>/ {print $3}' "$SCRATCH_FILE") if test $ID_VIDEO_WIDTH -eq 0; then - test_is_number ${MP_FRAMESIZE%x*} && ID_VIDEO_WIDTH=${MP_FRAMESIZE%x*} + test_is_number ${MP_FRAMESIZE%x*} && ID_VIDEO_WIDTH=${MP_FRAMESIZE%x*} fi if test $ID_VIDEO_HEIGHT -eq 0; then test_is_number ${MP_FRAMESIZE#*x} && ID_VIDEO_HEIGHT=${MP_FRAMESIZE#*x} @@ -238,18 +269,25 @@ # Find out which channel is the video channel ( 1st ) # TODO Do we want to worry about videos with multiple channels of video ? - VIDEO_INFO=$(grep "Video:" "$SCRATCH_FILE") - ID_VIDEO_TRACKS=( $(sed -r 's/.*Stream #([0-9]\.[0-9]+).*/\1/' <<< "$VIDEO_INFO") ) - ID_VIDEO_TRACK="${ID_VIDEO_TRACKS[0]}" + VIDEO_INFO=$(grep "Video:" "$SCRATCH_FILE" 2>&1| uniq) + ID_VIDEO_TRACKS=( $(sed -r 's/.*Stream #([0-9][:.][0-9]+).*/\1/' <<< "$VIDEO_INFO") ) + #ID_VIDEO_TRACKS=( $(awk '/Stream.*Video/ { gsub("#|: ", " ") ; print $2}' <<< "$VIDEO_INFO") ) + test_is_number "${ID_VIDEO_TRACKS[0]/:/}" && ID_VIDEO_TRACK="${ID_VIDEO_TRACKS[0]}" # Find out what audio channels are available + for p in ${!probe_info[@]}; do + if grep -q codec_type=audio <<< "${probe_info[p]}"; then + probe_audio_info+=( "${probe_info[p]}" ) + fi + done if test -n "$ID_AUDIO_ID"; then - AUDIO_INFO=$(grep -w "Audio:" "$SCRATCH_FILE") + # grep for Steam.*Audio instead of just "Audio:" fixes some wmv issues + AUDIO_INFO=$(grep "Stream.*Audio:" "$SCRATCH_FILE") # ID_AUDIO_ID needs "TRACKS" var to remain in columns - TRACKS=$(sed -r 's/.*Stream #([0-9]\.[0-9]+).*/\1/' <<< "$AUDIO_INFO") + TRACKS=$(sed -r 's/.*Stream #([0-9][:.][0-9]+).*/\1/' <<< "$AUDIO_INFO") A_TRACKS=(${TRACKS//$'\n'/ }) # Get hexadecimal track IDs, if present if grep -q "\[0x[0-9a-fA-F]*]" <<< $AUDIO_INFO; then - HEX_TRACKS=$(awk -F [][] '{gsub("0x", ""); print $2}' <<< "$AUDIO_INFO") + HEX_TRACKS=$(awk -F '[][]' '{gsub("0x", ""); print $2}' <<< "$AUDIO_INFO") HEX_TRACKS=(${HEX_TRACKS//$'\n'/ }) USE_HEX_TRACKS=: else @@ -258,15 +296,30 @@ # Loop through available tracks and get specs on each for ((i=0; i<${#A_TRACKS[@]}; i++)); do CUR_CHAN=$(grep "Stream #${A_TRACKS[i]}" <<< "$AUDIO_INFO") - A_SAMPRATES=("${A_SAMPRATES[@]}" "$(echo $CUR_CHAN | \ - sed -r 's/.* ([0-9]+) Hz.*/\1/')") - ! test_is_number ${A_SAMPRATES[i]} && A_SAMPRATES[i]=? - A_BITRATES=("${A_BITRATES[@]}" "$(echo $CUR_CHAN | \ - sed -r 's/.* ([0-9]+) kb\/s.*/\1/')") - # make sure the above is a number, else set A_BITRATE to 0 - ! test_is_number ${A_BITRATES[i]} && A_BITRATES[i]=0 - A_CODECS=("${A_CODECS[@]}" "$(echo $CUR_CHAN | \ - sed -r 's/.*Audio: ([^,]+),.*/\1/')") + A_SAMPRATES[i]=$(sed -r 's/.* ([0-9]+) Hz.*/\1/' <<< "$CUR_CHAN") + if ! test_is_number ${A_SAMPRATES[i]}; then + # probe_audio_info should have same indexes as A_TRACKS + aud_samplerate=$(awk -F= '/^sample_rate=/ {print $2}' <<< "${probe_audio_info[i]}") + if test_is_number $aud_samplerate; then + A_SAMPRATES[i]=${aud_samplerate%.*} + else + A_SAMPRATES[i]=0 + fi + fi + A_BITRATES[i]=$(sed -r 's/.* ([0-9]+) kb\/s.*/\1/' <<< "$CUR_CHAN") + # test for a number, add 3 zeros (bits), else set A_BITRATE to 0 + if test_is_number ${A_BITRATES[i]} && (( ${A_BITRATES[i]} )); then + A_BITRATES[i]=${A_BITRATES[i]}000 + else + # probe_audio_info should have same indexes as A_TRACKS + aud_bitrate=$(awk -F= '/^bit_rate=/ {print $2}' <<< "${probe_audio_info[i]}") + if test_is_number $aud_bitrate; then + A_BITRATES[i]=${aud_bitrate%.*} + else + A_BITRATES[i]=0 + fi + fi + A_CODECS[i]=$(sed -nr 's/.*Audio: (\w+).*/\1/p' <<< "$CUR_CHAN") if $USE_HEX_TRACKS; then MP_TRACKNUM=$((16#${HEX_TRACKS[i]})) else @@ -275,21 +328,24 @@ fi ID_AUDIO_IDS="$ID_AUDIO_IDS ${MP_TRACKNUM//$'\n'/ }" - # last ditch efforts to get audio bitrate if we still don't have it - if test ${A_BITRATES[i]} -eq 0; then - MP_ABITRATE=$(mplayer -nomsgcolor -vo null -ao null -frames 30 \ - -channels 6 -identify -aid $MP_TRACKNUM -noconsolecontrols \ - "$INFILE" 2>&1 | grep ID_AUDIO_BITRATE|awk -F= 'END{print $2}') - if test_is_number $MP_ABITRATE; then - MP_ABITRATE=${MP_ABITRATE%.*} - A_BITRATES[i]=${MP_ABITRATE/000*} - else # final attempt - MENC_ABITRATE=$(mencoder "$INFILE" -aid $MP_TRACKNUM -oac pcm -ovc copy \ - -frames 30 -o /dev/null 2>&1 | awk '/AUDIO/ {print $7}') - test_is_number $MENC_ABITRATE && A_BITRATES[i]=${MENC_ABITRATE%.*} + # last ditch efforts to get audio {bit,sample}rate if 0 + if (( ${A_BITRATES[i]} == 0 )) || (( ${A_SAMPRATES[i]} == 0 )); then + MP_CHAN_INFO=$(mplayer -nomsgcolor -vo null -ao null -frames 30 \ + -channels 6 -identify -aid ${MPL_AIDS[i]} -noconsolecontrols \ + "$INFILE" 2>&1) + # we want the last match: AFTER mplayer plays it a bit + MP_ABITRATE=$(awk -F= '/^ID_AUDIO_BITRATE=/ {b=$2} END{print b}' <<< "$MP_CHAN_INFO") + MP_SAMPRATE=$(awk -F= '/^ID_AUDIO_RATE=/ {b=$2} END{print b}' <<< "$MP_CHAN_INFO") + MP_ABITRATE=${MP_ABITRATE%.*} + MP_SAMPRATE=${MP_SAMPRATE%.*} + if test_is_number $MP_ABITRATE && (( MP_ABITRATE )); then + [[ ${A_BITRATES[i]} = 0 ]] && A_BITRATES[i]=$MP_ABITRATE + fi + if test_is_number $MP_SAMPRATE && (( MP_SAMPRATE )); then + [[ ${A_SAMPRATES[i]} = 0 ]] && A_SAMPRATES[i]=$MP_SAMPRATE fi fi - A_HEX_TRACKS=("${A_HEX_TRACKS[@]}" "$MP_TRACKNUM") + A_HEX_TRACKS[i]=$MP_TRACKNUM done # use comma separator and remove possible leading comma ID_AUDIO_IDS=${ID_AUDIO_IDS// /,} @@ -315,16 +371,16 @@ tracks=( ${TRACKS[@]} ) if (( ${#tracks[@]} > 0 )); then for i in ${!tracks[@]}; do - map_cmd[i]="-map ${tracks[i]}" - wavs=( "${wavs[@]}" "$TMP_DIR/$i.wav" ) + # for -map seperator needs to be ':' not '.' + map_cmd[i]="-map ${tracks[i]/./:}" + wavs[i]="$TMP_DIR/$i.wav" done for r in ${!tracks[@]}; do - test_tracks[r]="$(ffmpeg -i "$INFILE" -ss 2 -t 1 ${map_cmd[r]} -y ${wavs[r]} 2>&1)" + test_tracks[r]="$($FFmpeg -i "$INFILE" -ss 2 -t 1 ${map_cmd[r]} -y ${wavs[r]} 2>&1)" if grep -q Unsupported <<< "${test_tracks[r]}"; then tracks[r]="Unsupported" fi done - #test_tracks=( "$(ffmpeg -i "$INFILE" -ss 2 -t 1 ${map_cmd[@]} -y ${wavs[@]} 2>&1)" ) echo "${test_tracks[@]}" >> "$SCRATCH_FILE" rm -f "${wavs[@]}" fi @@ -334,30 +390,25 @@ ID_AUDIO_TRACKS=${TRACKS// /,} fi # if test -n "$ID_AUDIO_ID" - # If tcprobe reports an aspect ratio, use that - if grep -q "aspect ratio" "$SCRATCH_FILE"; then - RATIO=$(awk '/aspect ratio/ {print $3}' "$SCRATCH_FILE") - V_ASPECT_WIDTH=$(expr ${RATIO%:*} \* 100 \/ ${RATIO#*:}) - # Otherwise, infer from mplayer - else - # Infer aspect ratio from width/height of mplayer playback - MPLAYER_RES=$(grep '^VO:' "$SCRATCH_FILE" | \ - sed -e "s/..*=> *//g" -e "s/ .*$//g") - #PLAY_WIDTH=$(echo $MPLAYER_RES | awk -F 'x' '{print $1}') - #PLAY_HEIGHT=$(echo $MPLAYER_RES | awk -F 'x' '{print $2}') - # patch from ML: - PLAY_WIDTH=$(echo "$MPLAYER_RES" | awk -F '[x ]' 'BEGIN {wid = 0}; {if ($1 > wid) wid = $1}; END {print wid}') - PLAY_HEIGHT=$(echo "$MPLAYER_RES" | awk -F '[x ]' 'BEGIN {hgt = 0}; {if ($2 > hgt) hgt = $2}; END {print hgt}') - # Fix nulls - if test -z "$PLAY_WIDTH" || test -z "$PLAY_HEIGHT"; then - PLAY_WIDTH="100" - PLAY_HEIGHT="100" - fi - V_ASPECT_WIDTH=$(expr $PLAY_WIDTH \* 100 \/ $PLAY_HEIGHT) + # Infer aspect ratio from width/height of mplayer playback + MPLAYER_RES=$(grep '^VO:' "$SCRATCH_FILE" | \ + sed -e "s/..*=> *//g" -e "s/ .*$//g") + # patch from ML: + PLAY_WIDTH=$(awk -F '[x ]' 'BEGIN {wid = 0}; {if ($1 > wid) wid = $1}; END {print wid}'<<< "$MPLAYER_RES") + PLAY_HEIGHT=$(awk -F '[x ]' 'BEGIN {hgt = 0}; {if ($2 > hgt) hgt = $2}; END {print hgt}' <<< "$MPLAYER_RES") + # fix nulls and division by 0 errors as well (( xxx )) + if ! (( PLAY_WIDTH )) || ! (( PLAY_HEIGHT )); then + PLAY_WIDTH="100" + PLAY_HEIGHT="100" fi + V_ASPECT_WIDTH=$(expr $PLAY_WIDTH \* 100 \/ $PLAY_HEIGHT) # Normalized aspect ratio - V_ASPECT_RATIO=$(echo $V_ASPECT_WIDTH | \ - sed -r -e 's/([0-9]*)([0-9][0-9])/\1.\2:1/g') + if test_is_number "$V_ASPECT_WIDTH"; then + V_ASPECT_RATIO=$(sed -r -e 's/([0-9]*)([0-9][0-9])/\1.\2:1/g' \ + <<< "$V_ASPECT_WIDTH") + fi + # if mplayer decides there is no video, unset V_ASPECT_WIDTH + grep -qi "no video" "$SCRATCH_FILE" && unset V_ASPECT_WIDTH NAV_LOG="${INFILE}.nav_log" USE_NAVLOG=false @@ -369,41 +420,41 @@ # if a nav_log file exists and we have a value for FPS, use the log if [[ -s "$NAV_LOG" && ${ID_VIDEO_FPS%%.*} -ne 0 ]]; then ! $TERSE && echo "Using $NAV_LOG" - USE_MENCODER=false + GET_FFMPEG_LEN=false USE_NAVLOG=: else # no nav_log or ID_VIDEO_FPS missing # If doing -fast identification, skip "accurate" length determination if $FAST; then # skip this long process - USE_MENCODER=false # USE_NAV_LOG already set to false + GET_FFMPEG_LEN=false # USE_NAV_LOG already set to false else - # check if tcdemux present, and if mpg extension (vob uses mencoder) - if grep -qi mpg <<< "${INFILE##*.}" && hash tcdemux 2>/dev/null && \ + # check if tcdemux present, and if mpg extension (vob uses ffmpeg) + if egrep -qi 'mpg$|mpeg$|vob$' <<< "${INFILE##*.}" && hash tcdemux 2>/dev/null && \ [[ ${ID_VIDEO_FPS%%.*} -ne 0 ]]; then NAVSEEK_CMD=(nice tcdemux -f $ID_VIDEO_FPS -W -i "$INFILE") # or check if aviindex installed, and if extension is avi elif grep -qi avi <<< "${INFILE##*.}" && hash aviindex 2>/dev/null && \ [[ ${ID_VIDEO_FPS%%.*} -ne 0 ]]; then NAVSEEK_CMD=(nice aviindex -x -i "$INFILE" -o "$NAV_LOG") - else # not $FAST and indexing not possible, so use mencoder - USE_MENCODER=: + else # not $FAST, no indexing: so use ffmpeg for length/frames + GET_FFMPEG_LEN=: fi fi if [[ "${NAVSEEK_CMD[@]}" ]]; then "${NAVSEEK_CMD[@]}" > "$NAV_LOG" 2>/dev/null if [[ -s "$NAV_LOG" ]]; then # if non empty lets use it - USE_MENCODER=false + GET_FFMPEG_LEN=false USE_NAVLOG=: else - # remove empty log and we will use mencoder in next code block + # remove empty log and we will use ffmpeg in next code block [[ -e "$NAV_LOG" ]] && rm -f "$NAV_LOG" - USE_MENCODER=: + GET_FFMPEG_LEN=: fi fi fi # set variables from NAV_LOG results if $USE_NAVLOG; then - if grep -qi mpg <<< "${INFILE##*.}"; then - ID_VIDEO_FRAMES=$(cat "$NAV_LOG" | awk 'END{print NR}') + if egrep -qi 'mpeg$|mpg$|vob$' <<< "${INFILE##*.}"; then + ID_VIDEO_FRAMES=$(awk 'END{print NR}' "$NAV_LOG" ) V_DUR=$(bc <<< "$ID_VIDEO_FRAMES / $ID_VIDEO_FPS") V_DURATION=${V_DUR%%.*} # final value is integer ( seconds ) else @@ -413,32 +464,93 @@ # final value is in seconds V_DURATION=${V_DURATION%%.*} # integer fi - # if no usable value, use mencoder - { ! test_is_number $V_DURATION || ((V_DURATION == 0)) ; } && USE_MENCODER=: + # if no usable value, use ffmpegs + { ! test_is_number $V_DURATION || ((V_DURATION == 0)) ; } && GET_FFMPEG_LEN=: fi - # find duration by playing the video with mencoder into /dev/null + # find duration by playing the video with ffmpeg into /dev/null # any of: no/empty log file, ! $FAST, no tcdemux/aviindex, or not an mpg/avi - if $USE_MENCODER; then - MENCODER_STATS=$(LC_ALL=C mencoder -ovc copy -nosound -noskiplimit \ - "$INFILE" -o /dev/null 2>/dev/null) - V_DURATION=$(awk 'END{print $(NF-3)}' <<< "$MENCODER_STATS") - V_DURATION=${V_DURATION%%.*} # integer in seconds + if $GET_FFMPEG_LEN; then + ff_opts="-an -vcodec copy -f null -y /dev/null" + ffmpeg_cmd=($FFmpeg -i "$INFILE" $ff_opts) + ffmpeg_full_output=$( "${ffmpeg_cmd[@]}" 2>&1 ) + sed_var_time='x;$s/^.*time= *\([^ ]*\).*/\1/p' + sed_var_frames='{s/^.*frame= *\([^ ]*\).*/\1/p}' + V_DURATION=$(sed -n "$sed_var_time" <<< "$ffmpeg_full_output") + test_is_number ${V_DURATION//:} && V_DURATION=$(unformat_time $V_DURATION int) || \ + V_DURATION=0 # overwrite ID_VIDEO_FRAMES since we have a more accurate count now - ID_VIDEO_FRAMES=$(awk 'END{print $(NF-1)}' <<< "$MENCODER_STATS") - # if we failed to get a video bitrate earlier, use mencoder stats - if test $ID_VIDEO_BITRATE -eq 0; then - MENCODER_STATS_BR=$(awk -F: 'END{print $2}' <<< "$MENCODER_STATS" | awk '{print $1}') - # make sure it is a number - if test_is_number $MENCODER_STATS_BR; then - ID_VIDEO_BITRATE=${MENCODER_STATS_BR%.*}000 - fi + ID_V_FRAMES=$(sed -n "$sed_var_frames" <<< "$ffmpeg_full_output") + test_is_number "$ID_V_FRAMES" && ID_VIDEO_FRAMES=$ID_V_FRAMES + if $VERBOSE; then + echo "getting video length with ffmpeg" + echo "$ffmpeg_full_output" fi - $VERBOSE && echo "$MENCODER_STATS" - fi - # Use mplayer-reported length as a last resort (truncate floating-point) - test -z $V_DURATION && V_DURATION=$(echo $ID_LENGTH | sed 's/\.[0-9]*//') + # old stuff + fi + # try ffmpeg's estimate of duration first, then tcprobe's, then mplayers + if ! (( ${V_DURATION//:} )); then + # below from go|dfish on #sed, quits after 1st match (we have 2 matches) + V_DURATION=$(sed -n '/.*Duration: /{ s///; s/\..*//; p; q; }' "$SCRATCH_FILE") + if egrep -q '([0-9]+:[0-9][0-9]:[0-9][0-9])' <<< "$V_DURATION"; then + V_DURATION=$(unformat_time $V_DURATION int) + else + V_DURATION=0 + fi + if ! (( ${V_DURATION//:} )); then + V_DUR=$(sed -n '/.*duration=/{ s///; s/\..*//; p; q; }' "$SCRATCH_FILE") + # try ffprobe's (avprobe) output first + if (( ${vid_duration%.*} )); then + V_DURATION=${vid_duration%.*} + # try tcprobe if above fails, if installed, 'failing' silently otherwise + elif (( ${V_DUR%.*} )); then + egrep -q '([0-9]+:[0-9][0-9]:[0-9][0-9])' <<< "$V_DURATION" && \ + V_DURATION=$(unformat_time $V_DURATION int) + else + V_DURATION=0 + fi + fi + # Lastly try mplayer-reported length (secs) (truncate floating-point) + if ! (( ${V_DURATION} )); then + V_DURATION=$(sed 's/\.[0-9]*//' <<< "$ID_LENGTH") + (( V_DURATION )) || V_DURATION=0 + fi + fi + # now we have (hopefully) duration and audio bitrate, we can try other ways + # to get video bitrate if we don't have it yet, from the total bitate + # or from the file size. + # make sure of numerical values for audio and video bitrate, then subtract + if ! test_is_number $ID_VIDEO_BITRATE || ! (( ID_VIDEO_BITRATE )); then + TOTAL_AV_BITRATE=$(awk -F: '{gsub("kb/s", "")}; /Duration:.*bitrate:/ {print $6*1000;exit}' "$SCRATCH_FILE") + if test_is_number $TOTAL_AV_BITRATE && (( TOTAL_AV_BITRATE )); then + (( ID_AUDIO_BITRATE )) && test_is_number $ID_AUDIO_BITRATE && \ + ID_VIDEO_BITRATE=$(( TOTAL_AV_BITRATE - ID_AUDIO_BITRATE )) + #echo -e "Probed video bitrate not available, infering from total bitrate and audio bitrate\n" + else + # infer bitrate from file size and duration + v_size=$(( $(du -m "$INFILE" | awk '{ print $1 }') * 8192 )) + if (( ${V_DURATION%.*} )); then + ID_VIDEO_BITRATE=$(bc -l <<< "$v_size / $V_DURATION") + ID_VIDEO_BITRATE=$(( v_size / V_DURATION ))000 + #echo -e "Probed video bitrate not available, infering from file size and duration\n" + fi + fi + fi + # use 0 for unknown video bitrate, same as unknown audio bitrate + [[ $ID_VIDEO_BITRATE = 0 ]] && ID_VIDEO_BITRATE=0 + + # use {ff,av}probe info to infer frames count, from duration and fps + # if we already have ID_VIDEO_FRAMES from mplayer, this block does nothing + if test_is_number $vid_frames && ((vid_frames)); then + (( $ID_VIDEO_FRAMES == 0 )) && ID_VIDEO_FRAMES=$vid_frames + elif (( ${V_DURATION%.*} )) && (( ${ID_VIDEO_FPS/./} )); then + VIDEO_FRAMES=$(bc -l <<< "$V_DURATION * $ID_VIDEO_FPS") + if (( $ID_VIDEO_FRAMES == 0 )); then + ID_VIDEO_FRAMES=${VIDEO_FRAMES%.*} + #echo -e "Probed frame count not available, infering from duration and framerate\n" + fi + fi # TODO: WARN if video is less than one second! # Mplayer reports ac3 and mp2 incorrectly, so refer to numeric codes @@ -534,7 +646,7 @@ echo "---------------------------" echo " Codec: ${A_CODECS[j]}" if [[ ${tracks[j]} != Unsupported ]]; then - echo " Bitrate: ${A_BITRATES[j]}000 bits per second" + echo " Bitrate: ${A_BITRATES[j]} bits per second" echo " Sampling rate: ${A_SAMPRATES[j]} Hz" fi done @@ -568,8 +680,8 @@ # VCD/SVCD must be 44.1khz mp2 elif test "$ID_AUDIO_RATE" = "44100" && test "$ID_AUDIO_CODEC" = "mp2"; then - # SVCD can be 32-384 bps, 1-4 channels - if test "$ID_AUDIO_NCH" -le "4" && \ + # SVCD can be 32-384 bps, 1-4 channels - check 1st audio stream only + if test "${ID_AUDIO_NCH%%,*}" -le "4" && \ test "$ID_AUDIO_BITRATE" -ge "32000" && \ test "$ID_AUDIO_BITRATE" -le "384000"; then A_SVCD="$ID_AUDIO_NCH-channel $ID_AUDIO_BITRATE bps SVCD" @@ -630,6 +742,8 @@ esac # Find matching video profile(s) + # some mplayer versions report MPG2 instead of MPEG2 or hex + test "$ID_VIDEO_FORMAT" = "MPG2" && ID_VIDEO_FORMAT=MPEG2 # Test for VCD/DVD-VCD MPEG1 compliance if test "$ID_VIDEO_FORMAT" = "MPEG1" && test "$ID_VIDEO_BITRATE" -le "1856000"; then # VCD compliance @@ -858,7 +972,7 @@ # See what programs are available for doing identification MPLAYER=$(type -p mplayer) -FFMPEG=$(type -p ffmpeg) +FFMPEG=$(type -p $FFmpeg) TCPROBE=$(type -p tcprobe) @@ -874,6 +988,7 @@ "-fast" ) FAST=: ;; "-accurate" ) FAST=false ;; "-tabular" ) TABULAR=: ;; + "-keepfiles" ) KEEPFILES=: ;; "-isformat" ) shift MATCH_FORMAT="$1" @@ -904,5 +1019,5 @@ column -s "||" -t "$TABLE" fi -rm -rf "$TMP_DIR" +$KEEPFILES || rm -rf "$TMP_DIR" exit 0
View file
tovid-0.34.tar.bz2/src/makedvd -> tovid-0.35.tar.gz/src/makedvd
Changed
@@ -15,7 +15,7 @@ # # Project homepage: http://tovid.wikia.com # -# Copyright (C) 2005-2010 +# Copyright (C) 2005-2015 # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -44,15 +44,12 @@ EOF` USAGE=`cat << EOF -Usage: tovid dvd [OPTIONS] FILE.xml - or: tovid dvd [OPTIONS] DVD_DIR +Usage: tovid dvd [OPTIONS] DVD_DIR -With FILE.xml, containing dvdauthor XML as generated by 'makexml', -or DVD_DIR, a directory containing a DVD filesystem (VIDEO_TS, namely). +DVD_DIR: a directory containing a DVD filesystem (VIDEO_TS, namely). OPTIONS may be any of the following: - -author Create DVD filesystem from FILE.xml -burn Burn DVD filesystem from DVD_DIR -eject Eject the DVD tray after burning -device DEVFS_NAME DVD recorder device name (Default: /dev/dvdrw) @@ -228,6 +225,8 @@ # See what kind of file we're working with, and do the right thing # Author an XML file +# This first if block is no longer really needed as makexml has +# been removed from tovid but I will leave it here for now. if echo "$DISC_NAME" | grep -q -i '\.xml$'; then DVDAUTHOR_XML="$DISC_NAME" DO_AUTHOR=: @@ -339,7 +338,7 @@ export VIDEO_FORMAT=ntsc echo -e '\n***' echo "No default video format defined!!!" - echo "Was this xml created by a recent version of tovid/makexml?" + echo "Was this xml created by a recent version of tovid/todisc?" echo "Using default video format of 'ntsc'." echo "Run 'export VIDEO_FORMAT=\"pal\"' if this is wrong for your disc." echo -e '\n***' @@ -416,7 +415,7 @@ echo "Found $DISC_STATUS $DISC_TYPE. Please insert a usable DVD into $DVDRW_DEVICE." for COUNTER in {10..1}; do printf "Trying again in %2s seconds...\r" $((COUNTER * TIME_SCALE)) - sleep ${TIME_SCALE}s + sleep $TIME_SCALE done ((COUNT++)) echo
View file
tovid-0.34.tar.bz2/src/makempg -> tovid-0.35.tar.gz/src/makempg
Changed
@@ -1,5 +1,5 @@ #!/usr/bin/env bash -ME="[tovid]:" +ME="[makempg]:" . tovid-init 2>/dev/null || { echo -e "===============================================================\n" echo -e "'tovid-init' not found. Was tovid improperly installed?" @@ -16,7 +16,7 @@ # # Project homepage: http://tovid.wikia.com # -# Copyright (C) 2005-2010 +# Copyright (C) 2005-2015 # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -145,6 +145,7 @@ # Audio bitrate (for ac3 or mp2) AUD_BITRATE="224" # Don't generate an empty audio stream +NEWAUDIO_OPT=false GENERATE_AUDIO=false # Amplitude used when adjusting audio (-amplitude) AUDIO_AMPLITUDE="" @@ -297,7 +298,7 @@ yecho return else - eval "$@" 2>&1 | strings >> "$LOG_FILE" & + eval "$@" 2>&1 | $std_buf strings >> "$LOG_FILE" & PIDS="$PIDS $!" fi } @@ -319,8 +320,10 @@ # ****************************************************************************** function check_disk_space() { + # this function is very inaccurate, needs attention # Determine space available in current directory (in MB) - AVAIL_SPACE=$(df -mP . | awk 'NR != 1 {print $4;}') + # os compatibility patch from 'virtualestates' as per issue #152 + AVAIL_SPACE=$(df -P . | awk 'NR==1 {sub("-blocks", "", $2); blocksize=$2} NR!=1 {print int($4/1024*blocksize/1024)}') # Rough estimates of KB/sec for different formats K_PER_SEC=200 test "$TGT_RES" = "VCD" && K_PER_SEC=172 @@ -333,15 +336,15 @@ # based on original file size $SLICE && VIDEO_DURATION=$CLIP_LENGTH || VIDEO_DURATION=$V_DURATION if test "$VIDEO_DURATION" = "0"; then - CUR_SIZE=$(du -Dck \"$IN_FILE\" | awk 'END{print $1}') + CUR_SIZE=$(du -Dck "$IN_FILE" | awk 'END{print $1}') NEED_SPACE=$(expr $CUR_SIZE \* 2) - yecho "The encoding process will require about" # Estimate space based as kbps * duration else NEED_SPACE=$(expr $VIDEO_DURATION \* $K_PER_SEC \/ 500) - yecho "The encoding process is estimated to require $NEED_SPACE MB of disk space." fi - + # ffmpeg can do a+v 'at once' so half as much space needed + $USE_FFMPEG && ! $DO_NORM && ! [[ $ASYNC ]] && NEED_SPACE=$((NEED_SPACE/2)) + yecho "The encoding process is estimated to require $NEED_SPACE MB of disk space." yecho "You currently have $AVAIL_SPACE MB available in this directory." } @@ -560,7 +563,7 @@ "-downmix" ) DOWNMIX=: ;; - "-ffmpeg" ) + "-ffmpeg" | "-avconv" ) USE_FFMPEG=: ;; "-nofifo" ) @@ -740,7 +743,7 @@ PEAK_BITRATE=$(grep 'Peak bit-rate' "$LOG_FILE" | awk '{print $6}') if $USE_FFMPEG && ! $DO_NORM && ! $VIDEO_OK; then # get lines with frame= , and print last field with kbit/s removed - bitrates=$(awk -F= '/^frame=/ {gsub("kbits/s", ""); print $NF}' "$LOG_FILE") + bitrates=$(sed -n 's/kbits\/s//g;s/^.*bitrate= *\([^ ]*\).*/\1/p' "$LOG_FILE") # get highest value, and remove spaces with sed bitrates=$(sort -un <<< "$bitrates" | sed 's/^[ \t]*//;s/[ \t]*$//') # average the values. Add 000, so it is in bits. @@ -756,7 +759,7 @@ KB_PER_MIN=$(expr $FINAL_SIZE \* 60 \/ $V_DURATION \+ 1) ENC_TIME_RATIO=$(echo "scale = 2; $SCRIPT_TOT_TIME / $V_DURATION" | bc) if $USE_FFMPEG; then - BACKEND="ffmpeg" + BACKEND="$FFmpeg" else BACKEND="mpeg2enc" fi @@ -800,11 +803,11 @@ if ! $QUIET; then yecho "Your encoded video should be in the file(s) $OUT_FILENAME." echo - echo "You can author a disc with this video on it by running:" - echo " tovid xml $OUT_FILENAME -out MyDisc" - echo " tovid dvd MyDisc.xml" - echo "You can also use todisc or makemenu to create menus for your disc." - echo "See the tovid manual page ('man tovid') for more information." + echo "You can author a simple disc with this video on it by running:" + echo " tovid disc -no-menu \"$OUT_FILENAME\" -out MyDisc" + echo "Add -burn for a prompt to burn (-device and -speed optional)" + echo "Or use todisc (tovid disc) to create text-only or animated menus." + echo "See the manual ('man tovid') for more information and options." echo echo "Please report bugs to:" echo " http://code.google.com/p/tovid/issues/list" @@ -880,10 +883,26 @@ fi if ((USE_FILTERS)) && $USE_FFMPEG; then - usage_error "Sorry, you are using ffmpeg to encode + usage_error "Sorry, you are using $FFmpeg to encode video, either by choice or another option requires it. You can not use -filters with -ffmpeg" fi + +# see if ffmpeg is new enough to support -b:v etc +# remove this when 0.9x ffmpeg is the oldest tovid will support +# note ffmpeg is used for audio so this must run even when using mpeg2enc +if $FFmpeg -f rawvideo -pix_fmt yuv420p -s cif \ + -i /dev/zero -t 1 -r 30 -f rawvideo \ + -b:v 500k -y /dev/null > /dev/null 2>&1; then + VB=-b:v + AB=-b:a + CA=-c:a +else + VB=-b + AB=-ab + CA=-acodec +fi + # make sure we are not running from the gui and set some options ! $FROM_GUI && NOCONSOLE_CONTROLS="-noconsolecontrols" @@ -915,6 +934,16 @@ usage_error "Please provide an output name with the -out option." fi +# check that outfile does not contain a comma because of a mpeg2enc limitation +if ! $USE_FFMPEG && [[ "$OUT_PREFIX" = *,* || "$IN_FILE" = *,* ]]; then + exit_with_error "Comma illegal in -out and -in NAME (mpeg2enc limitation)" +fi +# check that outfile or infile don't use $$ or $[0-9] because of mpeg2 'bug' +if ! $USE_FFMPEG && [[ "$OUT_PREFIX" = *\$\$* || "$IN_FILE" = *\$\$* ]]; then + exit_with_error '"$$" illegal in -out and -in NAME (mpeg2enc limitation)' +elif ! $USE_FFMPEG && [[ "$OUT_PREFIX" = *\$[0-9]* || "$IN_FILE" = *\$[0-9]* ]]; then + exit_with_error '"$" followed by a digit illegal in -out and -in NAME (mpeg2enc limitation)' +fi # check that outfile is not a directory if test -d "$OUT_PREFIX"; then exit_with_error "Error: The specified output file is a directory. A filename must be specified." @@ -1066,7 +1095,7 @@ # If multiple CPUs are available, do multithreading in mpeg2enc if $MULTIPLE_CPUS; then - yecho "Multiple CPUs detected; mpeg2enc and ffmpeg will use multithreading." + yecho "Multiple CPUs detected; mpeg2enc and $FFmpeg will use multithreading." MTHREAD="--multi-thread 2" FF_THREAD="-threads 4" else @@ -1127,11 +1156,11 @@ # Check for available space and prompt if it's not enough # not needed if using ffmpeg to encode video and audio "at once" - if ($USE_FFMPEG && (! $DO_NORM || ! [[ $ASYNC ]])) || $PARALLEL; then + if $PARALLEL; then : else check_disk_space - if test "$AVAIL_SPACE" -lt "$NEED_SPACE" && ! test $FROM_GUI -o $NOASK ; then + if ((AVAIL_SPACE < NEED_SPACE)) && ! $FROM_GUI && ! $NOASK; then yecho "Available: $AVAIL_SPACE, needed: $NEED_SPACE" echo "It doesn't look like you have enough space to encode this video." echo "Of course, I could be wrong. Do you want to proceed anyway? (y/n)" @@ -1519,7 +1548,7 @@ yecho "I can't find any deinterlacing options to use. No deinterlacing" yecho "will be done on this video (but encoding will continue)." yecho "Encoding will resume in 5 seconds..." - sleep 5s + sleep 5 fi # Deinterlacing for ffmpeg FF_ILACE="-deinterlace" @@ -1609,9 +1638,9 @@ fi # ffmpeg's -vf aspect is more dependable than -aspect, if ffmpeg is new enough -FF_FILTERS=$(ffmpeg -filters 2>&1) +FF_FILTERS=$($FFmpeg -filters 2>&1) # newer ffmpeg's use setdar= and setsar= -if grep -qw ^setdar <<< "$FF_FILTERS"; then +if grep -qw setdar <<< "$FF_FILTERS"; then FF_ASPECT="setdar=" # somewhat older rev's used aspect= elif grep -qw ^aspect <<< "$FF_FILTERS"; then @@ -1620,14 +1649,24 @@ FF_ASPECT='-aspect ' fi # newer ffmpegs using filters use "-vf" -FF_HELP=$(ffmpeg -h 2>&1) +FF_HELP=$($FFmpeg -h full 2>&1) if grep -qw -- -vf <<< "$FF_HELP"; then VF="-vf" # somewhat older is "-vfilters" elif grep -qw -- -vfilters <<< "$FF_HELP"; then VF="-vfilters" else - VF="" + runtime_error "Your $FFmpeg is too old to support video filters" +fi +# newaudio was removed in ffmpeg 0.9 as it was redundant because of -map opt +grep -qw -- -newaudio <<< "$FF_HELP" && NEWAUDIO_OPT=true + +# we can't really parse which syntax to use for all filters, so here is a test +errors=$( $FFmpeg -i "$IN_FILE" -t 1 \ +-vf scale=w=720:h=352,pad=width=720:height=480:x=0:y=64,setdar=16/9 \ +-f null -y /dev/null 2>&1) +if grep -qE "Error.*\(width\|height\|setdar\|w=\|h=\)" <<< "$errors"; then + ff_legacy=1 fi # Anamorphic widescreen (16:9 output) @@ -1635,14 +1674,16 @@ # wasted on letterbox bars (or if the user requested -widetv output). if $ANAMORPH && { ((V_ASPECT_WIDTH >= 153)) || $WIDE_TV ; }; then TGT_ASPECT_WIDTH=177 - FF_ASPECT="${FF_ASPECT}16:9" + ((ff_legacy)) && asp=16:9 || asp=16/9 + FF_ASPECT="${FF_ASPECT}${asp}" ASPECT_FMT="--aspect 3" # For all others, use "non-anamorphic" (4:3 output) # Aspects from 133:100 to 153:100 have minimum pixel wastage # when letterboxed in 4:3 else TGT_ASPECT_WIDTH=133 - FF_ASPECT="${FF_ASPECT}4:3" + ((ff_legacy)) && asp=4:3 || asp=4/3 + FF_ASPECT="${FF_ASPECT}${asp}" ASPECT_FMT="--aspect 2" fi @@ -1703,10 +1744,6 @@ FORCE_FPSRATIO=$TGT_FPSRATIO yecho "Found 1000fps (wmv) source, setting input to $TGT_FPS fps." yecho "Use -fps to force a different input fps (see 'man tovid')" - # TODO: Instead, use a two-pass encoding (since mencoder can - # do -ofps) - # mencoder -ovc copy -oac copy -ofps $TGT_FPSRATIO $INFILE -o twopass - # then do normal encoding on twopass fi # If forced FPS was used, apply it @@ -1800,8 +1837,8 @@ done testfile="/tmp/$(date +%s).mpg" track_key=${AUDIO_TRACK[max_key]} - ffm_cmd=( ffmpeg -i "$IN_FILE" $FF_THREAD -ss 2 -ab 224k -ac 2 \ - -target ntsc-dvd -b 6000k -vframes 1 $VIDEO_MAP \ + ffm_cmd=( $FFmpeg -i "$IN_FILE" $FF_THREAD -ss 2 $AB 224k -ac 2 \ + -target ntsc-dvd $VB 6000k -vframes 1 $VIDEO_MAP \ -map ${AIDS[track_key-1]//./:} "$testfile") yecho "Running ${ffm_cmd[@]}" if ! "${ffm_cmd[@]}" >/dev/null 2>&1; then @@ -1836,14 +1873,16 @@ AUDIO_WAV_MAP=( "${AUDIO_WAV_MAP[@]}" -map $i:0 ) AUDIO_STREAM=( "${AUDIO_STREAM[@]}" "${TMP_DIR}/audio${i}.$AUD_SUF" ) STREAM_CHANS=( "${STREAM_CHANS[@]}" ${AUDIO_CHAN[track-1]} "${AUDIO_STREAM[i]}" ) - NEW_AUDIO[i]="-acodec ac3 -ab 224k ${AUDIO_CHAN[track-1]} -newaudio" + # -newaudio for ffmpeg versions prior to 0.9 + $NEWAUDIO_OPT && \ + NEW_AUDIO[i]="$CA ac3 $AB 224k ${AUDIO_CHAN[track-1]} -newaudio" AUDIO_WAV[i]="$TMP_DIR/audio${i}.wav" AUDIO_WAV_CHANS=( "${AUDIO_WAV_CHANS[@]}" ${AUDIO_CHAN[track-1]} "${AUDIO_WAV[i]}" ) done FF_CHANNEL_MAP="$VIDEO_MAP $AUDIO_MAP" # we don't need the 1st track for -newaudio - unset NEW_AUDIO[0] + $NEWAUDIO_OPT && unset NEW_AUDIO[0] ((${#AUDIO_TRACK[@]} > 1)) && OUTPUT_FILES="each file" && s=s fi @@ -1855,16 +1894,20 @@ # ****************************************************************************** if $USE_FFMPEG; then - FF_BITRATE="-b ${VID_BITRATE}k" - FF_SIZE="-s ${INNER_WIDTH}x${INNER_HEIGHT}" + FF_BITRATE="$VB ${VID_BITRATE}k" + if ((ff_legacy)); then + FF_SIZE="scale=${INNER_WIDTH}:${INNER_HEIGHT}" + else + FF_SIZE="scale=w=${INNER_WIDTH}:h=${INNER_HEIGHT}" + fi FF_CODEC="-f mpeg1video" FF_FPS="-r $TGT_FPS" FF_SAMPRATE="-ar $SAMPRATE" # try to get -quality 9 between quality 8 and 10 if ((VID_QUALITY == 9)); then FF_ADD_ARGS="-trellis 1" - ! ffmpeg -h 2>&1 | grep -q trellis && usage_error \ - "Your ffmpeg is too old to have the '-trellis' switch. Use a -quality setting other than '9'." + ! grep -q trellis <<< "$FF_HELP" && usage_error \ + "Your $FFmpeg is too old to have the '-trellis' switch. Use a -quality setting other than '9'." fi [[ $TARGET = "DVD-VCD" ]] && FF_ADD_ARGS="$FF_ADD_ARGS -g 12" # experiment FIXME @@ -1877,22 +1920,24 @@ (( FF_VPIX )) || (( FF_HPIX )) && PAD=1 # changed options: -pad{side} to -vf(ilters) pad= . if ((PAD)); then - if [[ $VF ]]; then + if ((ff_legacy)); then FF_PAD="pad=${TGT_WIDTH}:${TGT_HEIGHT}:${FF_HPIX}:${FF_VPIX}" else - ((FF_HPIX)) && FF_HPAD="-padleft $FF_HPIX -padright $FF_HPIX" - ((FF_VPIX)) && FF_VPAD="-padtop $FF_VPIX -padbottom $FF_VPIX" - FF_PAD="$FF_HPAD $FF_VPAD" - fi + FF_PAD="pad=width=${TGT_WIDTH}:height=${TGT_HEIGHT}:x=${FF_HPIX}:y=${FF_VPIX}" + fi fi # use single variable for current, or legacy ffmpeg: VF_FILTERS and OLD_OPTS if [[ $VF ]]; then # libavfilter is being used, FF_ASPECT always passed - VF_FILTERS="${FF_PAD},${FF_ASPECT}" + VF_FILTERS="${FF_SIZE},${FF_PAD},${FF_ASPECT}" VF_FILTERS="$VF ${VF_FILTERS#,}" # add -vf*, axe possible leading comma else # legacy ffmpeg OLD_OPTS="$FF_PAD $FF_ASPECT" fi + # Remove extraneous commas from filter command + if test -n "$VF_FILTERS"; then + VF_FILTERS=$(sed 's/,,/,/g;s/,$//' <<< "$VF_FILTERS") + fi # Target TV system test "$TVSYS" = "PAL" && FF_TARGET="-target pal" @@ -1915,12 +1960,12 @@ if $USE_FFMPEG && ! $DO_NORM && [[ -z "$AUDIO_SYNC" ]] && ! $GENERATE_AUDIO; then chan1=${AUDIO_TRACK[0]} yecho - yecho "Using ffmpeg to encode audio and video." + yecho "Using $FFmpeg to encode audio and video." - FF_BITRATE="-b ${VID_BITRATE}k -ab ${AUD_BITRATE}k ${AUDIO_CHAN[chan1-1]} " - FF_ENC_CMD="$PRIORITY ffmpeg -i \"$IN_FILE\" $FF_THREAD $CLIP_SEEK $FF_LENGTH $ASYNC $ASYNC1 \ - $FF_TARGET $FF_QUANT $FF_BITRATE $FF_ADD_ARGS $FF_FPS $FF_ILACE \ - $FF_SIZE $VF_FILTERS $OLD_OPTS $FF_CHANNEL_MAP" + FF_BITRATE="$VB ${VID_BITRATE}k $AB ${AUD_BITRATE}k ${AUDIO_CHAN[chan1-1]} " + FF_ENC_CMD="$PRIORITY $FFmpeg -i \"$IN_FILE\" $FF_THREAD $CLIP_SEEK $FF_LENGTH $ASYNC $ASYNC1 \ + $FF_TARGET $FF_QUANT $FF_ADD_ARGS $FF_ILACE \ + $VF_FILTERS $OLD_OPTS $FF_BITRATE $FF_CHANNEL_MAP" $OVERWRITE && FF_ENC_CMD="$FF_ENC_CMD -y " FF_ENC_CMD="$FF_ENC_CMD \"$OUT_FILENAME\" ${NEW_AUDIO[@]}" yecho "Encoding video and audio with the following command:" @@ -1931,7 +1976,7 @@ if $FAKE; then : else - file_output_progress "$OUT_FILENAME" "Encoding with ffmpeg" + file_output_progress "$OUT_FILENAME" "Encoding with $FFmpeg" wait fi yecho @@ -1962,14 +2007,12 @@ yecho "Found compliant audio and dumping the stream." precho "This sometimes causes errors when multiplexing; add '-force' to the tovid command line to re-encode if multiplexing fails." yecho "Copying the existing audio stream with the following command:" - AUDIO_CMD=($PRIORITY ffmpeg $FF_THREAD $CLIP_SEEK $FF_LENGTH -i "$IN_FILE" -vn -acodec copy $AUDIO_MAP "${STREAM_CHANS[@]}") + AUDIO_CMD=($PRIORITY $FFmpeg $FF_THREAD $CLIP_SEEK $FF_LENGTH -i "$IN_FILE" -vn $CA copy $AUDIO_MAP "${STREAM_CHANS[@]}") yecho "${AUDIO_CMD[@]}" #AUDIO_CMD="$PRIORITY mplayer $MPLAYER_OPTS \"$IN_FILE\" -dumpaudio -dumpfile \"$AUDIO_STREAM\"" run_audio_cmd() { "${AUDIO_CMD[@]}" >> "$LOG_FILE" 2>&1 & - #$PRIORITY ffmpeg $CLIP_SEEK $FF_LENGTH -i "$IN_FILE" -vn -acodec copy \ - #$AUDIO_MAP "${AUDIO_STREAM[@]}" >> "$LOG_FILE" 2>&1 } run_audio_cmd & PIDS="$PIDS $!" @@ -1994,7 +2037,7 @@ AUDIO_IN_FILE[1]="${AUDIO_WAV[0]}" #AUDIO_CMD="$PRIORITY mplayer $MPLAYER_OPTS -quiet -vc null -vo null $MP_AUDIOTRACK_CMD -ao pcm:waveheader:file=\"$AUDIO_WAV\" \"$IN_FILE\"" - AUDIO_CMD=( $PRIORITY ffmpeg -y $FF_THREAD $CLIP_SEEK $FF_LENGTH -i "$IN_FILE" $ASYNC1 $AUDIO_MAP -ar $SAMPRATE -acodec pcm_s16le "${AUDIO_WAV_CHANS[@]}" ) + AUDIO_CMD=( $PRIORITY $FFmpeg -y $FF_THREAD $CLIP_SEEK $FF_LENGTH -i "$IN_FILE" $ASYNC1 $AUDIO_MAP -ar $SAMPRATE $CA pcm_s16le "${AUDIO_WAV_CHANS[@]}" ) # Generate or dump audio yecho "Normalizing the audio stream${s}." @@ -2017,20 +2060,20 @@ yecho fi - AUDIO_ENC=( $PRIORITY ffmpeg ) + AUDIO_ENC=( $PRIORITY $FFmpeg ) if $GENERATE_AUDIO; then # Read input from /dev/zero to generate a silent audio file - AUDIO_ENC=( "${AUDIO_ENC[@]}" -f s16le -i /dev/zero -t $V_DURATION ) + AUDIO_ENC=( "${AUDIO_ENC[@]}" -f s16le -ar 48000 -i /dev/zero -t $V_DURATION ) yecho "Generating a silent audio stream with the following command:" else # Encode audio stream directly from the input file AUDIO_ENC=( "${AUDIO_ENC[@]}" -i "${AUDIO_IN_FILE[@]}" ) yecho "Encoding audio stream to $AUD_SUF with the following command:" fi - AUDIO_ENC=( "${AUDIO_ENC[@]}" -vn -ab ${AUD_BITRATE}k -ar $SAMPRATE ) + AUDIO_ENC=( "${AUDIO_ENC[@]}" -vn $AB ${AUD_BITRATE}k -ar $SAMPRATE ) ! $DO_NORM && AUDIO_ENC=( "${AUDIO_ENC[@]}" $CLIP_SEEK $FF_LENGTH $AUDIO_MAP ) - AUDIO_ENC=( "${AUDIO_ENC[@]}" -acodec $AUD_SUF) + AUDIO_ENC=( "${AUDIO_ENC[@]}" $CA $AUD_SUF) $DO_NORM && AUDIO_ENC=( "${AUDIO_ENC[@]}" "${AUDIO_WAV_MAP[@]}" ) AUDIO_ENC=( "${AUDIO_ENC[@]}" -y "${STREAM_CHANS[@]}" ) "${AUDIO_ENC[@]}" >> "$LOG_FILE" 2>&1 & @@ -2073,7 +2116,7 @@ # If existing video is OK, skip video encoding and just copy the stream if ! $FORCE_ENCODING && $VIDEO_OK; then - VID_COPY_CMD="mencoder -of rawvideo -nosound -ovc copy \"$IN_FILE\" -o \"$VIDEO_STREAM\"" + VID_COPY_CMD="$FFmpeg -i \"$IN_FILE\" -an -sn -vcodec copy -f rawvideo -o \"$VIDEO_STREAM\"" yecho "Copying existing video stream with the following command:" yecho "$VID_COPY_CMD" @@ -2093,9 +2136,9 @@ if $USE_FIFO; then mkfifo "$YUV_STREAM" || runtime_error "Cannot create fifo $YUV_STREAM" fi - VID_PLAY_CMD="$PRIORITY $MPLAYER $NOCONSOLE_CONTROLS -benchmark -nosound -noframedrop $SUBTITLES -vo yuv4mpeg:file=\"$YUV_STREAM\"${YUV4MPEG_ILACE} $VID_FILTER $MPLAYER_OPTS \"$IN_FILE\" $CLIP_SEEK $MP_FRAMES" + VID_PLAY_CMD="$PRIORITY $MPLAYER -nomsgcolor $NOCONSOLE_CONTROLS -benchmark -nosound -noframedrop $SUBTITLES -vo yuv4mpeg:file=\"$YUV_STREAM\"${YUV4MPEG_ILACE} $VID_FILTER $MPLAYER_OPTS \"$IN_FILE\" $CLIP_SEEK $MP_FRAMES" if $USE_FFMPEG ; then - VID_ENC_CMD="ffmpeg -i \"$IN_FILE\" $FF_THREAD $CLIP_SEEK $FF_LENGTH -an $FF_TARGET $FF_CODEC $FF_QUANT $FF_BITRATE $FF_ADD_ARGS $FF_ILACE $FF_SIZE $VF_FILTERS $OLD_OPTS -y \"$VIDEO_STREAM\"" + VID_ENC_CMD="$FFmpeg -i \"$IN_FILE\" $FF_THREAD $CLIP_SEEK $FF_LENGTH -an $FF_TARGET $FF_CODEC $FF_QUANT $FF_ADD_ARGS $FF_ILACE $VF_FILTERS $OLD_OPTS $FF_BITRATE -y \"$VIDEO_STREAM\"" else VID_ENC_CMD="cat \"$YUV_STREAM\" | $YUVDENOISE $ADJUST_FPS $PRIORITY mpeg2enc --sequence-length $DISC_SIZE --nonvideo-bitrate $NONVIDEO_BITRATE $MTHREAD $ASPECT_FMT $MPEG2_FMT $VID_FPS $VERBOSE $VID_NORM $MPEG2_QUALITY -o \"$VIDEO_STREAM\"" fi
View file
tovid-0.34.tar.bz2/src/set_chapters -> tovid-0.35.tar.gz/src/set_chapters
Changed
@@ -2,26 +2,21 @@ import sys import Tkinter as tk -from libtovid.guis.helpers import SetChapters +from libtovid.guis.helpers import SetChaptersGui from os import path if len(sys.argv) < 2: - print("Usage: set_chapters.py video") - exit() - -video = sys.argv[1] -if not path.exists(video): - print('Error: %s does not exist' %video) - exit() - -def print_chapters(): - if app.get_chapters(): - sys.stdout.write(app.get_chapters() + '\n') + video = None +else: + video = sys.argv[1] + if not path.exists(video): + print('Error: the video file "%s" does not exist' %video) + exit() root = tk.Tk() -app = SetChapters(root, '-menu', 'Mplayer', print_chapters, style='standalone') +app = SetChaptersGui(root, '-osdlevel 3', 'Set chapter points with Mplayer') app.run(video) app.pack() -root.mainloop() +app.mainloop()
View file
tovid-0.34.tar.bz2/src/titleset-wizard -> tovid-0.35.tar.gz/src/titleset-wizard
Changed
@@ -2,101 +2,182 @@ import os.path import shlex -import commands -import tkFont import re -from Tkinter import * -from tkMessageBox import * -from tkSimpleDialog import askstring -from tkFileDialog import asksaveasfilename -from subprocess import Popen, PIPE -from libtovid.metagui import Style -from libtovid.metagui.support import PrettyLabel, show_icons, get_photo_image -from libtovid.cli import _enc_arg, Command -from libtovid.util import trim from time import sleep from tempfile import mktemp from sys import argv, exit from base64 import b64encode from copy import deepcopy - -class Wizard(Frame): - """A frame to hold the wizard pages. It will also hold the commands - that will be processed and written out as a script. Its base frame - holds a frame common to all pages that displays an icon, title, and - status panel. It also has a bottom frame that contains the [Next] and - [Exit] buttons. It will hold a list of all of the wizard pages. +from subprocess import Popen, PIPE +from libtovid import xrange +from libtovid.cli import _enc_arg, Command +from libtovid.util import trim +from libtovid.metagui import Style +from libtovid.metagui.support import ( + PrettyLabel, show_icons, get_photo_image +) + +# Python 3 compatibility +try: + import Tkinter as tk + import tkFont + from tkSimpleDialog import askstring + from tkFileDialog import asksaveasfilename + from commands import getoutput, getstatusoutput + from tkMessageBox import ( + askyesno, showwarning, showinfo, showerror, askokcancel + ) +except ImportError: + import tkinter as tk + import tkinter.font as tkFont + from tkinter.simpledialog import askstring + from tkinter.filedialog import asksaveasfilename + from subprocess import getoutput, getstatusoutput + from tkinter.messagebox import ( + askyesno, showwarning, showinfo, showerror, askokcancel + ) + +def get_screen_info(icon): + """Get window manager's title bar height and screen height. + This function masquerades as a progress bar. + winfo_? includes the top panel if it exists, xwininfo just the titlebar. + Returns tuple: screen h, deco w, deco h. + """ + try: + import Tix + # Python 3 + except ImportError: + import tkinter.tix as Tix + import time + r = Tix.Tk() + r.withdraw() + top = Tix.Toplevel(r) + top.title('Loading ...') + top.geometry('+0+0') + show_icons(top, icon) + top.update_idletasks() + p = Tix.Meter(top, value=0.0) + p.pack() + for i in range(100): + time.sleep(0.01) + p.configure(value=(i/100.0)) + p.update_idletasks() + xid = top.wm_frame() + # xwininfo returns a geometry string like '+2+23': split it on '+' + # it tends to give just window decoration h, w rather than including a panel + Xwininfo = \ + getoutput("xwininfo -frame -id %s |awk '/Corners:/ {print $2}'" %xid) + X_x = Xwininfo.split('+')[1] + X_y = Xwininfo.split('+')[2] + # winfo_x() winfo_y() tend to give panel AND window decoration + TK_x = top.winfo_x() + TK_y = top.winfo_y() + # so subtract the xwininfo x dimension from winfo_x; same for the y dimensions + # if xwininfo gives a lesser value, assume it just window deco, and subtract it + # else default to the greater (or equal) value of winfo_x (same for y dimension) + if TK_x > int(X_x): + frame_width = TK_x - int(X_x) + else: + frame_width = TK_x + if TK_y > int(X_y): + frame_height = TK_y - int(X_y) + else: + frame_height = TK_y + screeninfo = top.winfo_screenheight(), frame_width, frame_height + r.destroy() + return screeninfo + + + +class Wizard(tk.Frame): + """A frame to hold the wizard pages. + It will also hold the commands that will be processed and written out + as a script. Its base frame holds a frame common to all pages that + displays an icon, title, and status panel. It also has a bottom frame + that contains the [Next] and [Exit] buttons. + It will hold a list of all of the wizard pages. master: the Tk() instance called by __main__ - icon: Path to an image file (gif) to display on the left frame text: The text for the wizard title above and/or below the icon Use \n to break title into above\nbelow. + icon: Path to an image file (gif) to display on the left frame + infile: an infile provided as a saved project, that will be loaded """ - def __init__(self, master, text, icon): - Frame.__init__(self, master) + def __init__(self, master, text, icon, infile=''): + tk.Frame.__init__(self, master) self.pages = [] - self.index = IntVar() + self.index = tk.IntVar() self.text = text self.icon = icon self.master = master self.root = self._root() self.commands = [] + self.screen_info = [] # for cancelling run_gui if exit is called - self.is_running = BooleanVar() + self.is_running = tk.BooleanVar() self.is_running.set(True) # for waiting on [Next>>>] being pushed to continue titleset loop - self.waitVar = BooleanVar() + self.waitVar = tk.BooleanVar() self.waitVar.set(False) - # pid for xterm, to allow clean exit - # need this to make sure we don't have zombie processes - self.xterm_is_running = BooleanVar() - self.check = '' - self.xterm_is_running.set(False) + # variable for name of final script + self.project = '' + # variable for possible pre-loaded script - + self.is_infile = False # bindings for exit self.root.protocol("WM_DELETE_WINDOW", self.confirm_exit) self.root.bind('<Control-q>', self.confirm_exit) self.root.title('Tovid titleset wizard') # button frame - self.button_frame = Frame(master) + self.button_frame = tk.Frame(master) self.button_frame.pack(side='bottom', fill='x', expand=1, anchor='se') - self.exit_button = Button(self.button_frame, text='Exit', + self.exit_button = tk.Button(self.button_frame, text='Exit', command=self.confirm_exit) self.exit_button.pack(side='left', anchor='sw') - self.next_button = Button(self.button_frame, text='Next >>', + self.next_button = tk.Button(self.button_frame, text='Next >>', command=self.next) self.next_button.pack(side='right', anchor='se') - self.prev_button = Button(self.button_frame, text='<< Back', + self.prev_button = tk.Button(self.button_frame, text='<< Back', command=self.previous) # frame for icon and status display - self.frame1 = Frame(master) + self.frame1 = tk.Frame(master) self.frame1.pack(side='left', anchor='nw', padx=10, pady=80) inifile = os.path.expanduser('~/.metagui/config') style = Style() - style.load(inifile) + # make sure ~/.metagui and the config file exist + if os.path.exists(inifile): + style.load(inifile) + print("Loading style from config file: '%s'" % inifile) + else: + print("Creating config file: '%s'" % inifile) + style.save(inifile) self.font = style.font self.draw() + # if a script is being loaded (infile), then assign to self.project + if infile: + self.is_infile = True + self.project = infile + def draw(self): # get fonts font = self.font self.lrg_font = self.get_font(font, size=font[1]+4, _style='bold') self.medium_font = self.get_font(font, size=font[1]+2) self.heading_font = self.get_font(font, size=font[1]+8, _style='bold') - fixed = '-misc-fixed-medium-r-normal--13-100-100-100-c-70-iso8859-1' - self.fixed_font = tkFont.Font(font=fixed) + #fixed = '-misc-fixed-medium-r-normal--13-100-100-100-c-70-iso8859-1' self.background = self.root.cget('background') if self.text: txt = self.text.split('\n') - app_label1 = Label(self.frame1, text=txt[0], font=self.heading_font) + app_label1 = tk.Label(self.frame1, text=txt[0], font=self.heading_font) app_label1.pack(side='top', fill='both', expand=1, anchor='nw') # icons and image if os.path.isfile(self.icon): img = get_photo_image(self.icon, 0, 0, self.background) self.img = img # Display the image in a label on all pages - img_label = Label(self.frame1, image=self.img) + img_label = tk.Label(self.frame1, image=self.img) img_label.pack(side='top', fill='both', expand=1, anchor='nw', pady=20) # If Tcl supports it, generate an icon for the window manager @@ -106,11 +187,12 @@ print('%s does not exist' % img_file) # if 2 lines of text for image, split top and bottom if self.text and len(txt) > 1: - app_label2 = Label(self.frame1, text=txt[1], font=self.lrg_font) + app_label2 = tk.Label(self.frame1, text=txt[1], font=self.lrg_font) app_label2.pack(side='top', fill='both', expand=1, anchor='nw') def next(self): - """Move to the next wizard page""" + """Move to the next wizard page. + """ index = self.index.get() try: self.pages[index].hide_page() @@ -124,11 +206,15 @@ self.pages[index].previous() def set_pages(self, page): - """Accept incoming list of wizard page instances""" + """Accept incoming list of wizard page instances. + """ self.pages.append(page) + def set_screen_info(self, iterable): + self.screen_info = iterable + def get_font(self, font_descriptor, name='', size='', _style=''): - """Get metagui font configuration + """Get metagui font configuration. """ font = [name, size, _style] for i in range(len(font_descriptor)): @@ -137,75 +223,67 @@ return tuple(font) def show_status(self, status): - """Show status label on all pages, with timeout + """Show status label on all pages, with timeout. """ if status == 0: text='\nOptions saved!\n' else: text='\nCancelled!\n' font = self.medium_font - status_frame = Frame(self.frame1, borderwidth=1, relief=RAISED) + status_frame = tk.Frame(self.frame1, borderwidth=1, relief=tk.RAISED) status_frame.pack(pady=40) - label1 = Label(status_frame, text=text, font=font, fg='blue') + label1 = tk.Label(status_frame, text=text, font=font, fg='blue') label1.pack(side='top') - label2 = Label(status_frame, text='ok', borderwidth=2, relief=GROOVE) + label2 = tk.Label(status_frame, text='ok', borderwidth=2, relief=tk.GROOVE) label2.pack(side='top') - self.root.after(1000, lambda: label2.configure(relief=SUNKEN)) + self.root.after(1000, lambda: label2.configure(relief=tk.SUNKEN)) self.root.after(2000, lambda: status_frame.pack_forget()) def confirm_exit(self, event=None): """Exit the GUI, with confirmation prompt. """ - mess = 'Xterm is still open: is todisc still running? ' + \ - 'If so, please ctrl-c in the terminal if you wish to quit. ' + \ - 'In any case, you will need to close the terminal ' + \ - 'by pressing <ENTER> in it.' - if self.xterm_is_running.get() == True: - showwarning(message=mess) - return if askyesno(message="Exit?"): # set is_running to false so the gui doesn't get run self.is_running.set(False) + # remove project file if we quit early and it exists and is empty + if os.path.exists(self.project): + if os.stat(self.project).st_size == 0: + print('removing empty file: %s' %self.project) + os.remove(self.project) # waitVar may cause things to hang, spring it self.set_waitvar() self.root.quit() # unused def kill_pid(self, pid): - """Test and kill xterm pid in case of premature exit""" + """Test and kill xterm pid in case of premature exit. + """ if not pid: return - test_pid = commands.getstatusoutput('kill -0 %s' %pid) + test_pid = getstatusoutput('kill -0 %s' %pid) if test_pid[0] == 0: cmd = ['kill', '%s' %pid] Popen(cmd, stderr=PIPE) def set_waitvar(self): - """Set a BooleanVar() so tk.wait_var can exit + """Set a BooleanVar() so tk.wait_var can exit. """ self.waitVar.set(True) -class WizardPage(Frame): - """Base class for the wizard pages. As such it contains everythig - common to all wizard pages. +class WizardPage(tk.Frame): + """Base class for the wizard pages. + As such it contains everythig common to all wizard pages. """ def __init__(self, master): - Frame.__init__(self, master) - Frame.pack(master) + tk.Frame.__init__(self, master) + tk.Frame.pack(master) self.master = master self.root = self._root() - # a temp file name for the final script name if it exists already - curdir = os.path.abspath('') - self.newname = mktemp(suffix='.bash', prefix='todisc_commands.', - dir=curdir) # get tovid prefix - tovid_prefix = commands.getoutput('tovid -prefix') + tovid_prefix = getoutput('tovid -prefix') self.tovid_prefix = os.path.join(tovid_prefix, 'lib', 'tovid') os.environ['PATH'] = self.tovid_prefix + os.pathsep + os.environ['PATH'] - # the script we will be using for options - cur_dir = os.path.abspath('') - self.script_file = cur_dir + '/todisc_commands.bash' # get script header shebang = '#!/usr/bin/env bash' _path = 'PATH=' + self.tovid_prefix + ':$PATH' @@ -214,9 +292,10 @@ identifier = '# tovid project script\n# tovid version %s' % _version self.header = '%s\n\n%s\n\n%s\n\n' % (shebang, identifier, _path ) # ititialize a frame, but don't pack yet - self.frame = Frame(self.master) + self.frame = tk.Frame(self.master) # initialize widgets, but don't show yet self.master.set_pages(self) + self.titlebar_width, self.titlebar_height = self.master.screen_info[1:] def show_page(self): wizard = self.master @@ -228,47 +307,79 @@ def hide_page(self): self.frame.pack_forget() - def run_gui(self, args=[], index='', script=''): - """Run the tovid GUI, collecting options, and saving to wizard + def get_screen_position(self): + """get real screen position, taking into account window decorations. + """ + r = self.root + r.update_idletasks() # make sure geometry is updated before we 'get' it + geo_x = r.winfo_rootx() - self.titlebar_width + geo_y = r.winfo_rooty() - self.titlebar_height + return '+%s+%s' %(geo_x, geo_y) + + def check_int(self, List): + """return list of ints from list of strings, checking 1st if castable. + """ + for index, item in enumerate(List): + try: + List[index] = int(item) + except ValueError: + return [] + return List + + def run_gui(self, args=[], index='', project=''): + """Run the tovid GUI, collecting options, and saving to wizard. """ title = 'load saved script' - script = 'todisc_commands.bash' - set_env = [] if index: os.environ['METAGUI_WIZARD'] = '%s' %index - cmd = ['todiscgui'] + args - todiscgui_cmd = Popen(cmd, stdout=PIPE) + self.root.update_idletasks() # update geometry before it is 'deiconified' + self.screen_pos = self.get_screen_position() + # these 2 are just convenience vars for shorter line length + script = self.master.project + position = self.screen_pos + # get modification time of the script, so we can see if it changes + mtime = os.path.getmtime(script) + #cmd = ['todiscgui'] + ['--position', self.screen_pos] + ['--project', self.master.project.get()] + args + cmd = ['todiscgui', '--position', position, '--project', script] + args + todiscgui_cmd = Popen(cmd, stdout=PIPE, stderr=PIPE) # sleep to avoid the 'void' of time before the GUI loads sleep(0.5) if self.root.state() is not 'withdrawn': self.root.withdraw() - status = todiscgui_cmd.wait() - if status == 200: - # if script doesn't exist prompt for load. - if os.path.exists(self.script_file): - script = self.script_file - else: - err = 'A problem has occured with saving your options. ' + \ - 'The saved script file was not found. ' + \ - 'Please submit a bug report' - showerror(message=err) - return + todiscgui_cmd.wait() + # hack to deiconify wizard at same position as the exiting tovid gui + for line in todiscgui_cmd.stderr.readlines(): + L = line.split(b'+') # python 3 compatibility (b'') + if b'gui position ' in L and len(L) == 3: + result = self.check_int(L[-2:]) + if result: + x = result[0]-self.master.screen_info[1] + y = result[1]-self.master.screen_info[2] + self.screen_pos = '+%d+%d' %(x, y) + break + + # if modification time changed, then the script was saved from the gui + if os.path.getmtime(script) > mtime: # Read lines from the file and reassemble the command todisc_opts = self.script_to_list(script) - os.remove(script) + # blank file: don't remove as we need it to get mtime in run_gui() + open(script, 'w').close() else: todisc_opts = [] + # set wizard screen position again, then update + self.root.geometry(self.screen_pos) + self.root.update_idletasks() return todisc_opts def page_controller(self): self.master.next() - def script_to_list(self, infile): - """File contents to a list, trimming '-from-gui' and header + def script_to_list(self, script): + """File contents to a list, trimming '-from-gui' and header. """ add_line = False command = '' - for line in open(infile, 'r'): + for line in open(script, 'r'): if line.startswith('-'): add_line = True if add_line and not line.startswith('-from-gui'): @@ -277,12 +388,13 @@ return shlex.split(command) def write_script(self): - """Write out the final script to todisc_commands.bash + """Write out the final script to project filename. """ commands = self.master.commands header = self.header - cmdout = open(self.script_file, 'w') - os.chmod(self.script_file, 0775) + cmdout = open(self.master.project, 'w') + # mode compatibility for 2.4 to 3.x python + os.chmod(self.master.project, int('755', 8)) # add the shebang, PATH, and 'todisc \' lines cmdout.writelines(header) # flatten the list @@ -299,7 +411,7 @@ cmdout.close() def trim_list_header(self, cmds): - """Trim header (items before 1st '-' type option) from a list + """Trim header (items before 1st '-' type option) from a list. """ # remove shebang, identifier and PATH try: @@ -329,7 +441,7 @@ return chunk def get_list_args(self, items, option): - """Get option arguments from a list (to next item starting with '-') + """Get option arguments from a list (to next item starting with '-'). """ try: index = items.index(option) @@ -347,7 +459,7 @@ return chunk def see_me(self, widget): - """Bring attention to widget by changing text colour + """Bring attention to widget by changing text colour. """ # 3000 and 4000 ms because show_status uses up 3000 already self.root.after(3000, lambda: widget.configure(foreground='blue')) @@ -356,7 +468,7 @@ def refill_listbox(self, listbox, opts): - """Repopulate the rerun listbox with option list titles + """Repopulate the rerun listbox with option list titles. """ if '-titles' in opts: new_titles = self.get_list_args(opts, '-titles') @@ -370,10 +482,11 @@ for i in xrange(numtitles): listbox.insert('end', new_titles[i]) - def rename_script(self): + # unused (note self.script_file also unused now) + def rename_script(self, path): # if todisc_commands.bash exists in current dir, prompt for rename rename_msg = 'The option file we will use:\n' + \ - '"todisc_commands.bash"\n' + \ + self.master.script.get() + '\n' + \ 'exists in the current directory.\n' + \ 'It will be renamed to:\n' + \ '"%s"' + \ @@ -387,14 +500,15 @@ class Page1(WizardPage): - """Wizard intro page""" + """Wizard intro page. + """ def __init__(self, master): WizardPage.__init__(self, master) # draw the page by default unless script file arg passed - if len(argv) < 2: + if not self.master.is_infile: self.draw() - index = self.master.pages.index(self) - self.master.index.set(index) + index = self.master.pages.index(self) + self.master.index.set(index) def draw(self): self.frame.pack(side='right', fill='both', expand=1, anchor='nw') @@ -430,7 +544,8 @@ class Page2(WizardPage): - """Wizard general options page""" + """Wizard general options page. + """ def __init__(self, master): WizardPage.__init__(self, master) @@ -438,6 +553,11 @@ self.frame.pack(side='right', fill='both', expand=1, anchor='nw') text = '''GENERAL OPTIONS + Please set a name for your 'project' in the box at the bottom of the page, + by pressing the "Browse" button, and browsing to the directory you want + to save it. This will be a bash script that can be run standalone, or + reloaded into the titleset-wizard for further editing. + When you press the "Next >>>" button at the bottom of the wizard, we will start the GUI and begin with general options applying to all titlesets. For example you may wish to have all menus share a common @@ -448,17 +568,31 @@ bottom of the GUI's main tab. Options you enter will be overridden if you use the same option again later for titlesets. - After making your selections, press [ Save to wizard ] in the GUI + In the GUI, after making your selections, press [ Save to wizard ]. - Press "Next >>>" to begin ... + Enter a project name, then press "Next >>>" ''' text = trim(text) self.label = PrettyLabel(self.frame, text, self.master.font) self.label.pack(fill='both', expand=1, anchor='nw') + # setting project name + self.project_label = tk.Label(self.frame, text='Project name', font=self.master.font, + justify='left', padx=10, pady=10) + self.project_label.pack(fill='both', expand=1, anchor='sw') + self.project_frame = tk.Frame(self.frame) + self.project_entry = tk.Entry(self.project_frame, width=50) + self.project_entry.insert(0, 'Press Browse Button') + self.project_entry.bind("<KeyPress>", lambda e: "break") + self.browse_button = tk.Button(self.project_frame, text="Browse...", + command=self.browse) + self.project_frame.pack(fill='both', expand=1, anchor='sw') + self.project_entry.pack(side='left') + self.browse_button.pack(side='right') def page_controller(self): - if os.path.exists(self.script_file): - self.rename_script() + if not self.master.project: + # here we need a popup telling user to enter a project name #FIXME + return wizard = self.master index = wizard.index.get() move = True @@ -469,16 +603,25 @@ move = False else: status = 0 - cmds = [l for l in cmds if l] + cmds = [L for L in cmds if L] wizard.commands.append(cmds) wizard.show_status(status) self.root.deiconify() if move: wizard.next() + def browse(self, e=None): + title = 'Type a filename' + filename = asksaveasfilename(parent=self, title=title, initialfile='my_project.tovid') + if filename: + self.project_entry.delete(0, 'end') + self.project_entry.insert(0, filename) + self.master.project = filename + open(filename, 'w').close() class Page3(WizardPage): - """Wizard root menu page""" + """Wizard root menu page. + """ def __init__(self, master): WizardPage.__init__(self, master) @@ -509,16 +652,16 @@ self.titlebox = TitleBox(self.frame, text="Root 'menu link' titles") def save_list(self): - """Save the current listbox contents + """Save the current listbox contents. """ # get a list of listbox lines temp_list = list(self.titlebox.get(0, 'end')) - return [ l for l in temp_list if l] + return [ L for L in temp_list if L] def page_controller(self): wizard = self.master run_cmds = list(self.titlebox.get(0, 'end')) - run_cmds = [l for l in run_cmds if l] + run_cmds = [L for L in run_cmds if L] if len(run_cmds) < 2: showerror(message=\ 'At least two titlesets (titles) must be defined') @@ -546,7 +689,8 @@ class Page4(WizardPage): - """Wizard titleset menu page""" + """Wizard titleset menu page. + """ def __init__(self, master): WizardPage.__init__(self, master) @@ -569,8 +713,8 @@ text1 = trim(text1) self.label1 = PrettyLabel(self.frame, text1, self.master.font) self.label1.pack(fill='both', expand=True, side='top', anchor='nw') - self.frame2 = Frame(self.frame, borderwidth=2, relief=GROOVE) - self.label2 = Label(self.frame2, text='', font=self.master.font, + self.frame2 = tk.Frame(self.frame, borderwidth=2, relief=tk.GROOVE) + self.label2 = tk.Label(self.frame2, text='', font=self.master.font, justify='left', padx=10, pady=10) self.label2.pack(fill='both', expand=True, side='top', anchor='nw') @@ -622,16 +766,17 @@ class Page5(WizardPage): - """Final wizard page. Here you can rerun options that have been saved - from the tovid GUI, and add or remove titlesets. You can also - choose to run the final project + """Final wizard page. + Here you can rerun options that have been saved from the tovid GUI, and + add or remove titlesets. You can also choose to run the final project. """ def __init__(self, master): WizardPage.__init__(self, master) self.curindex = 0 self.lastindex = 0 - # set commands and draw this page if script file arg passed - if len(argv) > 1: + # set commands and draw by default if script (infile) arg passed + # self.master.project.get() would be set to that file + if self.master.is_infile: self.set_project_commands() self.draw() index = self.master.pages.index(self) @@ -646,8 +791,8 @@ Edit or reorder your selections using the listbox below. (Note that menu link titles as shown in listbox are saved as titles in the "Root menu" options.) If you are happy with your saved - options, run the script now , or exit and run it later. - You can run it later with: + options, run the script now in an xterm, or exit and run it later. + You can run it with: bash %s @@ -662,32 +807,33 @@ tovid titlesets %s Edit your selections, or press [Run script now] or [Exit]. - ''' % (self.script_file, self.script_file) + ''' % (self.master.project, self.master.project) + text = trim(text) - self.heading_label = Label(self.frame, text='Finished!', - font=wizard.lrg_font) - self.label = PrettyLabel(self.frame, text, - wizard.font, height=18) + self.heading_label = tk.Label(self.frame, + text='Your script is ready to run!', font=wizard.lrg_font) + self.label = tk.Label(self.frame, text=text, + font=wizard.font, justify='left') self.heading_label.pack(fill='both', expand=1, anchor='nw', pady=5) self.label.pack(fill='both', expand=1, anchor='nw') - # create the listbox (note that size is in characters) + frame_text = "Edit items, or add, remove or drag/drop titlesets" - frame2 = LabelFrame(self.frame, text=frame_text) - button_frame = Frame(frame2) - button_frame.pack(side='bottom', fill=X, expand=1, anchor='sw') - button2 = Button(button_frame, text='Add titleset', + frame2 = tk.LabelFrame(self.frame, text=frame_text) + button_frame = tk.Frame(frame2) + button_frame.pack(side='bottom', fill=tk.X, expand=1, anchor='sw') + button2 = tk.Button(button_frame, text='Add titleset', command=self.add_titleset) button2.pack(side='left', anchor='w') - button1 = Button(button_frame, text='Edit', command=self.rerun_options) + button1 = tk.Button(button_frame, text='Edit', command=self.rerun_options) button1.pack(side='left', fill='x', expand=1) - button3 = Button(button_frame, text='Remove titleset', + button3 = tk.Button(button_frame, text='Remove titleset', command=self.remove_titleset) button3.pack(side='right', anchor='e') - self.listbox = Listbox(frame2, width=50, exportselection=0) + self.listbox = tk.Listbox(frame2, width=50, exportselection=0) self.listbox.pack(side='left', fill='both', expand=1) self.listbox.bind('<Double-Button-1>', self.rerun_options) # create a vertical scrollbar to the right of the listbox - yscroll = Scrollbar(frame2, command=self.listbox.yview, + yscroll = tk.Scrollbar(frame2, command=self.listbox.yview, orient='vertical') yscroll.pack(side='right', fill='y', anchor='ne') self.listbox.configure(yscrollcommand=yscroll.set) @@ -743,7 +889,7 @@ temp_list[index_b] = item_a except IndexError: # should not happen - print 'index out of range!' + print('index out of range!') # Set the updated list self.listbox.delete(0, 'end') self.listbox.insert(0, *temp_list) @@ -764,8 +910,9 @@ self.write_script() def set_index(self, Event=None): - """Called when item in listbox selected. Set curindex and change - cursor to double-arrow. lastindex==curindex if no drag occurs. + """Called when item in listbox selected. + Set curindex and change cursor to double-arrow. + lastindex==curindex if no drag occurs. """ self.curindex = self.listbox.nearest(Event.y) self.lastindex = self.curindex @@ -783,7 +930,7 @@ # used to repopulate titleset titles after adding new one def get_option(self, items, option): - """Get option and arguments from a list (to next item starting with '-') + """Get option and args from a list (to next item starting with '-'). The list is modified in place. """ try: @@ -868,10 +1015,11 @@ self.write_script() def mod_sublist(self, item='', *index): - """Modify commands sublist. If 2 indexes, just swap items. If one - index the default behavior is to delete the index from the sublist - and remove it from commands, but if item is passed, add it as a - new index instead. + """Modify commands sublist. + If 2 indexes, just swap items. + If one index the default behavior is to delete the index from the + sublist and remove it from commands, but if item is passed, + add it as a new index instead. """ wizard = self.master vmgm_cmds = [w for w in wizard.commands[1]] @@ -898,7 +1046,7 @@ wizard.commands.insert(1, vmgm_cmds) def rerun_options(self, Event=None, index=None): - """Run the gui with the selected options + """Run the gui with the selected options. """ # self.master is the WizardPage commands = self.master.commands @@ -913,7 +1061,7 @@ # the GUI doesn't understand the titleset type options remove = ['-vmgm', '-end-vmgm', '-titleset', '-end-titleset'] options = [ i for i in commands[index] if not i in remove ] - rerun_opts = self.run_gui(options, '%s' %(index+1)) + rerun_opts = self.run_gui(options, '%d' %(index+1)) if rerun_opts: status = 0 # trim header from todisc_cmds @@ -943,16 +1091,17 @@ def set_project_commands(self): in_contents = self.script_to_list(argv[1]) in_cmds = in_contents[:] - all = [self.get_chunk(in_cmds, '-vmgm', '-end-vmgm')] + _all = [self.get_chunk(in_cmds, '-vmgm', '-end-vmgm')] while '-titleset' in in_cmds: - all.append( self.get_chunk(in_cmds, '-titleset', '-end-titleset') ) - all.insert(0, in_cmds) - self.master.commands = all + _all.append( self.get_chunk(in_cmds, '-titleset', '-end-titleset') ) + _all.insert(0, in_cmds) + self.master.commands = _all def load_project(self): - """Load a saved project script for editing with the wizard and GUI + """Load a saved project script for editing with the wizard and GUI. """ - self.heading_label.configure(text='Editing a saved project') + script = os.path.abspath(self.master.project) + #self.heading_label.configure(text='Editing a saved project') error_msg = 'This is not a saved tovid project script. ' + \ 'Do you want to try to load it anyway?' if not '# tovid project script\n' in open(argv[1], 'r'): @@ -960,20 +1109,26 @@ quit() numtitles = len(self.master.commands[2:]) menu_titles = [] - l = self.master.commands[1] - menu_titles.extend(self.get_list_args(l, '-titles')) + L = self.master.commands[1] + menu_titles.extend(self.get_list_args(L, '-titles')) self.refill_listbox(self.listbox, menu_titles) self.listbox.selection_set('end') - # write out todisc_commands.bash in current dir - # if it exists in current dir, prompt for rename - if os.path.exists(self.script_file): - mess = '%s has been loaded for editing. Your ' %self.script_file + \ - 'new edits will be saved to the same file. Continue?' + # write out to project filename + if os.path.exists(script): + infile_prefix = os.path.basename(script) + backup = mktemp(prefix=infile_prefix + '.', dir='/tmp') + backup_prefix = os.path.basename(backup) + mess = '%s has been loaded for editing, ' %infile_prefix + \ + 'and will be used for new edits. A backup ' + \ + 'will be saved to /tmp .\n' + \ + 'Continue ?' if askokcancel\ (message=mess): pass else: quit() + from shutil import copyfile + copyfile(script, backup) self.write_script() class Page6(WizardPage): @@ -989,28 +1144,39 @@ wizard.prev_button.pack(side='right', anchor='se') text1='Running saved project' - self.label = Label(self.frame, text=text1, font=wizard.lrg_font) + self.label = tk.Label(self.frame, text=text1, font=wizard.lrg_font) self.label.pack(side='top', fill='both', expand=1, anchor='nw', pady=5) cmd_labelfont = wizard.get_font(wizard.font, _style='bold') - self.cmd_title = Label(self.frame, + self.cmd_title = tk.Label(self.frame, font=cmd_labelfont, text='\n\n\nThe command that will run:') self.cmd_title.pack(fill='both', expand=1) self.cmd_str = '' index = wizard.index.get() - self.cmd_label = Label(self.frame, text=self.cmd_str, justify='left', - font=wizard.fixed_font, wraplength=560, fg='white', bg='black') + try: + self.fixed_font = tkFont.Font(font=('TkFixedFont')) + self.fixed_font.configure(size=9) + xterm_font = [ '-fa', self.fixed_font.actual()['family']] + fsize = ['-fs', str(self.fixed_font.actual()['size'])] + self.xterm_cmd = ['xterm'] + fsize + xterm_font + # tcl/tk < 8.5: no freetype support or 'Standard fonts' like tkFixedFont + except tk._tkinter.TclError: + self.fixed_font = tkFont.Font(font='7x14') + xterm_font = ['-fn', '7x14'] + self.xterm_cmd = ['xterm'] + xterm_font + self.cmd_label = tk.Label(self.frame, text=self.cmd_str, justify='left', + font=self.fixed_font, wraplength=560, fg='white', bg='black') self.cmd_label.pack(fill='both', expand=1) - self.termtitle = Label(self.master, text='\nFocus mouse in terminal') - self.button_frame = Frame(self.frame, borderwidth=2, relief='groove') + self.termtitle = tk.Label(self.master, text='\nFocus mouse in terminal') + self.button_frame = tk.Frame(self.frame, borderwidth=2, relief='groove') self.button_frame.pack(side='bottom', fill='both', expand=1) - self.run_button = Button(self.button_frame, text='Run project now', + self.run_button = tk.Button(self.button_frame, text='Run project now', command=self.run_in_xterm) self.run_button.pack(side='left', fill='both', expand=1) - self.save_button = Button(self.button_frame, text='Save log', + self.save_button = tk.Button(self.button_frame, text='Save log', command=self.save_log) self.save_button.pack(side='left', fill='both', expand=1) # disable the save log button till xterm is run - self.save_button.configure(state='disabled') + #self.save_button.configure(state='disabled') def set_cmd_label(self): cmds = self.master.commands @@ -1018,7 +1184,7 @@ cmd = '' for line in all_lines: cmd += ' ' + line - prompt = commands.getoutput('printf "[${USER}@$(hostname -s) ] $ "') + prompt = getoutput('printf "[${USER}@$(hostname -s) ] $ "') # probably not necessary, but ... if 'not found' in prompt: prompt = '[me@mymachine ] $ ' @@ -1026,7 +1192,8 @@ self.cmd_label.configure(text=self.cmd) def previous(self): - """Move to the previous wizard page""" + """Move to the previous wizard page. + """ self.frame.pack_forget() wizard = self.master index = wizard.index.get() @@ -1052,57 +1219,28 @@ wizard.next_button.pack_forget() def run_in_xterm(self): - ''' run the final script in an xterm, completing the project ''' - self.frame.pack_forget() - self.master.prev_button.configure(state='disabled') - self.termtitle.pack(side='top') - self.container = Frame(self.master, container=1, height=600, width=600) - self.container.pack(side='right', fill='both', - padx=20, expand=1, anchor='nw') - lines = '80x44+0+0' - cmd = 'xterm -sb -si -fn %s -rv -sb -rightbar -g %s -e sh -c' \ - %(self.master.fixed_font, lines) - cmd = shlex.split(cmd) - try: - id = self.root.tk.call('winfo', 'id', self.container) - frame_id = '%s' %int(id, 16) - self.master.xterm_is_running.set(True) - except TclError, ValueError: - self.master.xterm_is_running.set(False) - frame_id = '' - help = commands.getoutput('xterm -help') - self.logfile = mktemp(suffix='.log', prefix='todisc_commands.', - dir='/tmp') - if re.search('-into ', help) and frame_id: - cmd.insert(1, frame_id) - cmd.insert(1, '-into') - tovid_cmd = """ - bash %s | tee -a %s - echo - echo "Press Enter to exit terminal" - read input - """ %(self.script_file, self.logfile) - cmd.append(tovid_cmd) - command = Popen(cmd, stderr=PIPE) - self.after(200, self.poll) - - def poll(self): - # return if container is not created yet, or xterm is not running - if not self.container or not self.master.xterm_is_running.get(): + """Run the final script in an xterm, completing the project. + """ + if not askyesno(message="Run in xterm now?"): + self.master.show_status(1) return - try: - # bogus call to container to see if it has been destroyed - self.container.winfo_class() - except TclError: - self.termtitle.pack_forget() - self.master.xterm_is_running.set(False) - self.frame.pack(fill='both', expand=1, anchor='nw') - self.master.prev_button.configure(state='normal') - self.log_contents = commands.getoutput('tr "\r" "\n" < %s' \ - %self.logfile) - os.remove(self.logfile) - self.save_button.configure(state='normal') - self.root.check = self.root.after(200, self.poll) + self.screen_pos = self.get_screen_position() + xterm_geo = '80x40' + self.screen_pos + cmd = \ + ['-sb', '-title', 'todisc', + '-g', xterm_geo, '-e', 'sh', '-c'] + self.xterm_cmd.extend(cmd) + wait_cmd = ';echo ;echo "Press Enter to exit terminal"; read input' + tovid_cmd = 'bash %s' % self.master.project + self.xterm_cmd.append(tovid_cmd + wait_cmd) + self.root.withdraw() + command = Popen(self.xterm_cmd, stderr=PIPE) + command.wait() + # without the following the position of restored window can jump around + self.root.geometry(self.screen_pos) + self.root.update_idletasks() # update geometry before it is 'deiconified' + self.root.deiconify() + def save_log(self, event=None): logfile = asksaveasfilename(initialfile='todisc_output.log') @@ -1111,25 +1249,24 @@ log.writelines(self.log_contents) # unfinished and unused -class Messagebox(Frame): +class Messagebox(tk.Frame): def __init__(self, master, use=None, text='', boolean_var=None): - Frame.__init__(self, master) + tk.Frame.__init__(self, master) self.master = master self.use = use - self.var = boolean_var + self.var = tk.boolean_var #self.overrideredirect(1) - self.top = Toplevel(self.master, use=use) + self.top = tk.Toplevel(self.master, use=use) text = text - label = Label(self.top, text=text, wraplength=400) + label = tk.Label(self.top, text=text, wraplength=400) label.pack() - button1 = Button(self.top, text='Yes', command=self.yes) - button2 = Button(self.top, text='No', command=self.no) + button1 = tk.Button(self.top, text='Yes', command=self.yes) + button2 = tk.Button(self.top, text='No', command=self.no) button1.pack(side='left') button2.pack(side='left') def yes(self, event=None): #self.var.set(True) - print 'from yes() return_code is: ', self.master.return_code.get() self.quit() return True @@ -1138,29 +1275,29 @@ self.quit() return False -class TitleBox(Frame): - """A Listbox in a LabelFrame with Entry associated with it +class TitleBox(tk.Frame): + """A Listbox in a LabelFrame with Entry associated with it. text: the label for the frame """ def __init__(self, master=None, text=''): - Frame.__init__(self, master) + tk.Frame.__init__(self, master) self.master = master self.text = text self.draw() def draw(self): # create the listbox (note that size is in characters) - frame1 = LabelFrame(self.master, text=self.text) + frame1 = tk.LabelFrame(self.master, text=self.text) frame1.pack(side='left', fill='y', expand=False) # use entry widget to display/edit selection - self.enter1 = Entry(frame1, width=50) + self.enter1 = tk.Entry(frame1, width=50) self.enter1.pack(side='bottom', fill='both', expand=False) - self.listbox = Listbox(frame1, width=50, height=12) + self.listbox = tk.Listbox(frame1, width=50, height=12) self.listbox.pack(side='left', fill='y', expand=False, anchor='nw') self.get = self.listbox.get # create a vertical scrollbar to the right of the listbox - yscroll = Scrollbar(frame1, command=self.listbox.yview, + yscroll = tk.Scrollbar(frame1, command=self.listbox.yview, orient='vertical') yscroll.pack(side='right', fill='y', anchor='ne') self.listbox.configure(yscrollcommand=yscroll.set) @@ -1172,7 +1309,7 @@ self.listbox.bind('<ButtonRelease-1>', self.get_list) def set_list(self, event): - """Insert an edited line from the entry widget back into the listbox + """Insert an edited line from the entry widget back into the listbox. """ try: index = self.listbox.curselection()[0] @@ -1193,7 +1330,7 @@ self.listbox.selection_set('end') def get_list(self, event): - """Read the listbox selection and put the result in an entry widget + """Read the listbox selection and put the result in an entry widget. """ try: # get selected line index and text @@ -1210,15 +1347,33 @@ # Execution if __name__ == '__main__': + args = argv[1:] + infile = '' + while args: + arg = args.pop(0) + # check for script to load: if its a file assume it is one (in) + if os.path.exists(arg): + infile = arg # get tovid prefix so we can find the app image file - tovid_prefix = commands.getoutput('tovid -prefix') + tovid_prefix = getoutput('tovid -prefix') tovid_prefix = os.path.join(tovid_prefix, 'lib', 'tovid') os.environ['PATH'] = tovid_prefix + os.pathsep + os.environ['PATH'] img_file = os.path.join(tovid_prefix, 'titleset-wizard.png') + root_height = 660 + # run a 'progress bar' to get info (tuple): + # screen height, title bar height, title bar width + screen_info = get_screen_info(img_file) # instantiate Tk and Wizard - root = Tk() - root.minsize(width=800, height=660) - app = Wizard(root, 'Tovid\nTitleset Wizard', img_file) + root = tk.Tk() + root.withdraw() + # shave height if we are dealing with a netbook resolution + if screen_info[0] < 660: + root_height = 600 + root.minsize(width=800, height=root_height) + app = Wizard(root, 'Tovid\nTitleset Wizard', img_file, infile=infile) + app.set_screen_info(screen_info) + root.update_idletasks() + root.deiconify() # instantiate pages page1 = Page1(app) page2 = Page2(app) @@ -1228,6 +1383,6 @@ page6 = Page6(app) # run it try: - mainloop() + root.mainloop() except KeyboardInterrupt: exit(1)
View file
tovid-0.34.tar.bz2/src/todisc -> tovid-0.35.tar.gz/src/todisc
Changed
@@ -15,7 +15,7 @@ # # Project homepage: http://tovid.wikia.com # -# Copyright (C) 2005-2010 +# Copyright (C) 2005-2015 # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -39,37 +39,50 @@ # grepper on irc.freenode.net SCRIPT_NAME=`cat << EOF + -------------------------------- tovid disc -Generate a DVD filesystem with animated thumbnail menus +Generate a DVD file-system with optional menus, from a list of multimedia files. +Menus can be moving or static thumbnails, or text. Encoding done automatically. + Version $TOVID_VERSION $TOVID_HOME_PAGE -------------------------------- + EOF` USAGE=`cat << EOF Usage: - - todisc [OPTIONS] \\\\ - -files File1.mpg File2.mpg ... \\\\ + tovid disc [OPTIONS] \\\\ + -files File1.mpg File2.avi ... \\\\ -titles "Title 1" "Title 2" ... \\\\ - -out OUT_PREFIX + -menu-title "Tovid Demo" \\\\ + -out OUT_DIRECTORY You can also do slideshows using -slides IMAGES rather than -files VIDEOS +General Options: + -no-ask, -no-warn, -keep-files, -jobs, -grid, -no-confirm-backup +Other quick examples: +Create 'text menu' DVD filesystem: + tovid disc -text-menu -files ... -titles .. -out OUT_DIRECTORY +Create DVD filesystem with no menu, encoding with ffmpeg and prompt for burn: + tovid disc -files *.mp4 -ffmpeg -no-menu -burn -out OUT_DIRECTORY +Create DVD compatible mpeg2 files using makempg (and ffmpeg) and then quit: + tovid disc -encode-only -ffmpeg -quality 8 -files *.avi (no -out required) See the tovid manual page ('man tovid') for additional documentation. EOF` # check that needed todisc deps are installed assert_dep "$todisc_deps" assert_dep strings "'strings' is part of binutils. In most distros the package -is called by the same name. http://www.gnu.org/software/binutils/ ." +is called binutils. http://www.gnu.org/software/binutils/ ." SCRIPT_START_TIME=`date +%s` # check if symlink in /tmp exists and use time stamped link if so WORK_DIR="/tmp/todisc-work" LOG_FILE=$(readlink -f todisc.log) -OUT_PREFIX="" +OUT_DIRECTORY="" TV_STANDARD=ntsc PIXEL_AR="10:11" MENU_LEN=( 20 ) @@ -78,8 +91,10 @@ SUBMENU_LEN=(10) MAX_MENU_LEN="" TARGET=dvd -FRAME_RATE=29.970 +FRAME_RATE=29.970 # for bc. mjpegtools and transcode convert this to 30000/1001 +ff_frame_rate="30000/1001" # ffmpeg needs to be explicitly told exact framerate VIDSIZE=720x480 +VF_SCALE=${VIDSIZE%x*}:${VIDSIZE#*x} MENU_TITLE="My Video Collection" STATIC=false SUB_MENU=false @@ -88,10 +103,10 @@ SM_TITLE_CLR="#EAEAEA" THUMB_BG_CLR=white TITLES_CLR="" -BUTTON_STYLE="rect" +BUTTON_STYLE="line" MIST_COLOUR=white MIST_OPACITY=60 -TITLE_STROKE="" +M_TITLE_STROKE="" SUBMENU_STROKE="none" BG_AUDIO="" BG_PIC="" @@ -147,24 +162,24 @@ USER_SM_AUDIO_SEEK=false SC_THUMB=: TEXTMENU=false -SC_TITLE_ALIGN=center -THUMB_TITLE_ALIGN=center +SC_TITLE_ALIGN="center" +EDGE_JUSTIFY=false ALIGN_OVERRIDE=false MULTILINE_TITLE=false SAFE_AREA=50 # undocumented: you can set this from CLI with -showcase-safe-area -SAFE_OFFSET=36 +SAFE_OFFSET=0 # we only add this offset if center title align, to keep onscreen ASPECT_RATIO=4:3 AR=1.333 ASPECT_ARG=all WIDE_SCREEN=false WIDESCREEN="nopanscan" +GROUP_ARR="" GROUPING=false TEXT_YSTART=$SAFE_AREA BUTTON_GRAVITY=north XGEO=0 YGEO=45 USER_GRAVITY=false -USER_GEO=false USER_SPLIT=false TITLE_GRAVITY=south SPACER=15 @@ -209,6 +224,7 @@ USER_AUDIOLENGTH=false BURN=false EJECT='' +BURN_PROG="makedvd" BURN_DEVICE="/dev/dvdrw" QUICK_MENU=false BG_CLR='#101010' @@ -249,27 +265,43 @@ JUSTIFY="center" CONTRAST_CLR='gray' NOMENU=false +ENCODE_ONLY=false SC_AR=133 THUMB_COLUMNS="" FAST_SEEK=false # ffmpeg: default:decode during seek (more accurate but slower) USER_THUMBS=false # is user providing images for the menu link thumbs ? -FRAME_SAFE=false # (-static) if true take the best of 9 frames. default: 1 frame -PIPE_FORMAT="-pix_fmt yuv420p -f yuv4mpegpipe" +FRAME_SAFE=false # (-static) if true take the best of 9 frames. default 1 frame +USE_V_TITLES_DECO=false +USE_M_TITLE_DECO=false +PIPE_FORMAT="" IMG_DEPTH="-depth 8" # when converting to png: ppmtoy4m needs 8 bit +AUDIO_EXT="ac3" +SAMPLERATE="48000" +AUDIO_OPTS="-ab 224k -ar $SAMPLERATE -acodec $AUDIO_EXT" +MPLEX_FORMAT="8" +FROM_GUI=false # needed to disable tput (colour output) in GUI TOVID_PREFIX=$(tovid -prefix) +use_transcode=: +yuv_correct="yuvcorrect -T NO_HEADER" ############################################################################## # Functions # ############################################################################## -# Y-echo: echo to two places at once (stdout and logfile) +# Y-echo: print to two places at once (stdout and logfile) # Output is preceded by the script name that produced it # Args: $@ == any text string -# If no args are given, echo a separator bar +# If no args are given, print a separator bar +# If empty string is the arg, print a newline # Use yecho if you want output to go to the logfile yecho() { - if test $# -eq 0; then + # arg supplied but empty (""): just print a newline + if [[ "${1+defined}" && -z $1 ]]; then + printf "\n" + [[ -e "$LOG_FILE" ]] && printf "\n" >> "$LOG_FILE" + # no arg supplied at all, just 'yecho': print \n[todisc]:\n + elif test $# -eq 0; then printf "\n%s\n\n" "$SEPARATOR" # If logfile exists, copy output to it (with pretty formatting) test -e "$LOG_FILE" && \ @@ -281,14 +313,6 @@ fold -bs >> "$LOG_FILE" fi } -# ****************************************************************************** -# Execute the given command-line string, with appropriate stream redirection -# Args: $@ == text string containing complete command-line -# Returns: Exit status of the subprocess -# To filter/prettify the subprocess output before writing it to the log file, -# set the LOG_FILTER variable before calling this function, to e.g. -# LOG_FILTER="sed 's/\r/\r\n/g'" # Replace LF with CR/LF -# ****************************************************************************** # Print script name, usage notes, and optional error message, then exit. # Args: $@ == text string(s) containing error message and help @@ -304,27 +328,109 @@ fi exit 1 } -warning_message() + +# Usage: continue_in [SECONDS] +continue_in() { - local MESSAGE=( "$@" ) - yecho $SEPARATOR - for ((i=0; i<$#; i++)) ; do printf "%s" "${MESSAGE[i]}"; done | - format_output | tee -a "$LOG_FILE" - echo | tee -a "$LOG_FILE" - yecho "$SEPARATOR" + yecho "" + (($1)) && LAST=$1 || LAST=5 + for ((i=LAST; i>=0; i--)); do + ((i==0)) && count='' || count="continuing in $i seconds ..." + spin $count + ((i>0)) && sleep 1 + done +} + +info_message() +{ + local MESSAGE=$(sed "s/ */ /g;s/^ *//" <<< "$@" | fold -w 60 -bs) + printgreen "*** Note: ***" + print2log "$MESSAGE" + while read -r line; do + printf "%s\n" "$line" + done <<< "$MESSAGE" + printgreen "*************" +} + +# print to log, formated with leading/trailing spaces removed +# and prefixed with the script name. [todisc]: +# with no args it just prints [todisc]:, with "" as arg it prints newline +print2log() +{ + local MESSAGE=$(sed "s/ */ /g;s/^ *//" <<< "$@" | fold -w 60 -bs) + # if "" passed in as arg (ie. defined but empty, print a blank line + if [[ "${1+defined}" && -z $1 ]]; then + printf "\n" >> "$LOG_FILE" + # otherwise print [todisc]: $line for each line of input + else + while read -r line; do + printf "%s %s\n" "$ME" "$line" >> "$LOG_FILE" + done <<< "$MESSAGE" + printf "\n" >> "$LOG_FILE" + fi +} + +# pipe stdout to log prefixed by "[name]:", and ending in newline. 2 opt args +# arg 1: [name to prefix each line of output] +# arg 2: [fold] fold lines appropriately. Usually you don't fold program stdout. +# uses stdbuf (coreutils) if present so stdin is line buffered +pipe2log() +{ + if [[ $1 ]]; then + name="[$1]: " + else + name="[${0##*/}]: " + fi + if [[ $2 && $2 = format ]]; then + cols=$(( 79 - $(wc -c <<< $name) )) + ((cols)) || cols=60 + format="fold -w $cols -bs" + else + format="cat" + fi + $std_buf tr "\015" "\012" < /dev/stdin | $std_buf tr -d "\033" | $format | \ + while read line; do + printf "%s %s\n" "$name" "$line" + done >> "$LOG_FILE" + printf "\n" >> "$LOG_FILE" +} + +printgreen() +{ + $FROM_GUI || tput setaf 2 + printf "%s\n" "$@" | sed "s/ */ /g;s/^ *//" + print2log "$@" + $FROM_GUI || tput sgr0 + printf "" +} + +printred() +{ + $FROM_GUI || tput setaf 1 + printf "%s\n" "$@" | sed "s/ */ /g;s/^ *//" + print2log "$@" + $FROM_GUI || tput sgr0 + printf "" } titlesafe_error() { - echo "***** WARNING *****" - yecho "thumb title is $1 pixels from screen edge" + (($1 > SAFE_AREA)) && preposition='off the' || preposition='from' + yecho "" + printred "***** WARNING *****" + yecho "video title is $1 pixels $preposition screen edge" yecho "Part of the title may not be visible on your tv screen" yecho "Perhaps use a smaller -titles-fontsize, or shorten \"${TITLES[i]}\"" - $SHOWCASE && [[ -z $SHOWCASE_FILE ]] && \ - yecho "You may also use '-showcase-titles-align east' since you are not - using a -showcase FILE." - echo "****************************" - $WARN && sleep 5 + # no need to test $SHOWCASE: default montage will never be offscreen + if [[ -z $SHOWCASE_FILE && ! $SC_TITLE_ALIGN = east ]]; then + yecho \ + "You may also use '-showcase-titles-align east' since you are not + using a -showcase FILE." + elif ((NUM_FILES >= SPLIT)); then # two columns + : # insert message here for east offscreen stuff #fixme + fi + yecho "****************************" + $WARN && continue_in 5 } format_output() @@ -344,25 +450,38 @@ # TODO: Check for font availability? } -vid_length() -{ - check_frames="" - [[ -n $2 ]] && check_frames=$2 && check_frames="-frames $check_frames" - echo "Using mencoder to get length of $1" >> "$LOG_FILE" - L=$(mencoder -nosound -mc 0 -oac pcm -ovc copy $check_frames \ - -o /dev/null "$1" 2> /dev/null) - awk 'END{print $(NF-3)}' <<< "$L" - # awk '{for (i=0; i<NF; i++) { if ($i=="secs") {print $(i-1); break} } }' \ - # <<< "$L" -} -audio_length() -{ - # optional 2nd arg is maximum length checked in file (seconds) - end="" - [[ -n $2 ]] && end="-endpos $2" - mplayer -nomsgcolor -noconsolecontrols -vo null -ao pcm:fast:file=/dev/null $end "$1" \ - 2>&1 | tr '\r' '\n' | grep ^A: | tail -1 | sed s/^.*A:// | awk '{print $1}' +# get the length of a stream +# usage: stream_length STREAM [type, duration] +# type is either video or audio, duration is the max length to test +# last 2 args are optional: defaults 'video' and the whole stream. +stream_length() +{ + local end="" + local stream_type=video + local ff_opts="-an -vcodec copy" + [[ -n $2 ]] && stream_type=$2 + [[ -n $3 ]] && end="-t $3" + sed_var="{s/^.*time= *\([^ ]*\).*/\1/p}" + stream_name=$stream_type + if [[ $stream_type = 'audio' ]]; then + ff_opts="-vn -acodec copy" + # workaround for avconv which is broken atm wrt getting m2v framerate right + # overload stream_type to have another meaning, + elif [[ $stream_type = 'm2v' ]]; then + sed_var="{s/^.*frame= *\([^ ]*\).*/\1/p}" + stream_name=video + fi + print2log "Using $FFmpeg to get accurate $stream_name length of $1" + local len=$($FFmpeg -i "$1" $end $ff_opts -f null -y /dev/null 2>&1 | + sed -n "$sed_var" | tail -n 1) + # sed -n 's/^.*time= *\([^ ]*\).*/\1/p' | tail -n 1) + if [[ $stream_type = 'm2v' ]]; then + bc_math "$len / $FRAME_RATE" + else + unformat_time $len # no need for echo, prints to stdout + fi } + cleanup() { #TODO make a kill_pid function to avoid repetition below @@ -439,9 +558,12 @@ yecho "todisc encountered an error:" yecho " $@" echo - echo "The error should be shown above, also check the contents of + echo "See above message, and also you can check the contents of $LOG_FILE to see what went wrong." |format_output - echo "See the tovid website ($TOVID_HOME_PAGE) for possible further info." + echo "See the tovid website ($TOVID_HOME_PAGE) for further help options." + echo "Latest fixes for ffmpeg api changes go in svn tovid." + echo "So you should try that if you get ${FFmpeg##*/} errors in the log." + echo "See subversion section: http://tovid.wikia.com/wiki/Installing_tovid" echo "Sorry for the inconvenience!" echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" cleanup @@ -476,18 +598,21 @@ # usage: bc_math "expression" [int] bc_math() { + OLC_ALL=$LC_ALL + LC_ALL=C bc_out=$(bc <<< "scale=3;$1" 2>/dev/null) if [[ -n $2 && $2 = "int" ]]; then echo ${bc_out%.*} else printf "%.03f" $bc_out fi + LC_ALL=$OLC_ALL } confirm_preview() { confirm_msg="type 'yes' to continue, or press <ENTER> to exit: " - yecho + yecho "" if $SWITCHED || $TITLESET_MODE || $VMGM_ONLY; then echo "If doing titlesets or switched menus and you wish to exit " echo "without seeing more previews, then type: 'exit', else you will " @@ -496,12 +621,12 @@ confirm_msg="Type yes to continue, press <ENTER> to abort but see " confirm_msg="$confirm_msg other previews, or type 'exit' to quit." fi - echo "If you are happy with the preview, $confirm_msg" + echo -e "If you are happy with the preview, \n$confirm_msg" read input echo if [ ! -z "$input" -a "$input" = "yes" ]; then yecho "Preview OK, continuing." - yecho + yecho "" else yecho "Preview not OK, exiting." #echo -n "Deleting symlink in /tmp . . . " @@ -513,7 +638,7 @@ #echo -n "Deleting "$REAL_WORK_DIR" . . . " rm -fr "$REAL_WORK_DIR" fi - yecho + yecho "" echo echo "Some configuration options to try, if things look bad:" echo "Color:" @@ -541,12 +666,10 @@ { SPIN_CHARS=".oOo" SPINNER="${SPIN_CHARS:SP++%${#SPIN_CHARS}:1}" - # Print spaces to overwrite previous line - echo -ne "\r " + echo -ne "\r$(printf %60s)" # print spaces to overwrite previous line echo -ne "\r$@ " } -#EXPAND="expand=-6:-6," get_framed_pics() { mplayer -ss $MPLAYER_SEEK_VAL -vo $VOUT -noconsolecontrols \ @@ -567,69 +690,82 @@ { awk 'END{print NR}' "$LOG_FILE" } + +# unused +get_ffmpeg_version() +{ +local test_version=$1 +ff_ver=$($FFmpeg -version 2>&1 | awk '{ gsub(",", ""); if(NR == 1) print $3 }') +(( ${ff_ver:2:1} == test_version )) 2>/dev/null +} + +is_video() +{ +file -biL "$1" |grep -qw video || return 1 +} check_filetype() { fstats=$(file -L "$1" | awk '{ $1 = ""; print }') if [[ $fstats =~ "image" || $fstats =~ "bitmap" ]]; then - TYPE="image" + file_type="image" CONVRT=: - if [[ $fstats = *JPEG* || $fstats = *PNG || $fstas = *PPM* ]]; then + if [[ $fstats = *JPEG* || $fstats = *PNG || $fstats = *PPM* ]]; then CONVRT=false fi - elif mencoder \ - -endpos 2 -oac pcm -ovc copy "$1" -o /dev/null >/dev/null 2>&1; then - TYPE=video + elif is_video "$1"; then + file_type=video else - TYPE=unknown + file_type=unknown fi } get_stats() { -unset IN_STATS FILES_IN -this_set=$1 -if [[ $this_set = "group" ]]; then - unset TOT IN_STATS FILES_IN - TOT=${#grouping[@]} # || TOT=${#IN_FILES[@]} - IN_STATS=( "${group_idvid_stats[@]}" ) - FILES_IN=( "${grouping[@]}" ) -else - TOT=${#IN_FILES[@]} - IN_STATS=( "${idvid_stats[@]}" ) - FILES_IN=( "${IN_FILES[@]}" ) -fi -for ((i=0; i<TOT; i++)); do - VCODEC="$(awk -F= '/ID_VIDEO_FORMAT/ {print $2}' <<< "${IN_STATS[i]}")" - V_BR="$(awk -F= '/ID_VIDEO_BITRATE/ {print $2}' <<< "${IN_STATS[i]}")" - ACODEC="$(awk -F= '/ID_AUDIO_CODEC/ {print $2}' <<< "${IN_STATS[i]}")" - A_BR="$(awk -F= '/ID_AUDIO_BITRATE/ {print $2}' <<< "${IN_STATS[i]}")" - if [ -z "$A_BR" ]; then - A_BR="No audio found" - fi - V_LENGTH=${VID_LEN[i]} - [[ $this_set = "group" ]] && V_LENGTH=${GROUP_VID_LEN[i]} - FPS="$(awk -F= '/ID_VIDEO_FPS/ {print $2}' <<< "${IN_STATS[i]}")" - yecho - if [[ $this_set = "group" ]] && ((i == 0)); then - echo; echo ". . . Grouped file stats . . ."; echo - yecho - fi - [[ $this_set = "group" ]] && echo -e "Stats for" \ - $(readlink -f "${FILES_IN[i]}") "\n" || \ - echo -e "Stats for" "${FILES_IN[i]}" "\n" - echo -e \ - " video codec: " \ - "$VCODEC" "\n" \ - "video bitrate: " "$V_BR" "bits per second" "\n" \ - "framerate: " "$FPS" "fps" "\n" \ - "audio codec: " \ - "$ACODEC" "\n" \ - "audio bitrate: " \ - "$A_BR" "bits per second" "\n" \ - "video length: " \ - "$V_LENGTH" "seconds" |tee -a "$LOG_FILE" -done + unset IN_STATS FILES_IN + this_set=$1 + if [[ $this_set = "group" ]]; then + unset TOT IN_STATS FILES_IN + TOT=${#grouping[@]} # || TOT=${#IN_FILES[@]} + IN_STATS=( "${group_idvid_stats[@]}" ) + FILES_IN=( "${grouping[@]}" ) + else + TOT=${#IN_FILES[@]} + IN_STATS=( "${idvid_stats[@]}" ) + FILES_IN=( "${IN_FILES[@]}" ) + fi + for ((i=0; i<TOT; i++)); do + VCODEC="$(awk -F= '/ID_VIDEO_FORMAT/ {print $2}' <<< "${IN_STATS[i]}")" + V_BR="$(awk -F= '/ID_VIDEO_BITRATE/ {print $2}' <<< "${IN_STATS[i]}")" + ACODEC="$(awk -F= '/ID_AUDIO_CODEC/ {print $2}' <<< "${IN_STATS[i]}")" + A_BR="$(awk -F= '/ID_AUDIO_BITRATE/ {print $2}' <<< "${IN_STATS[i]}")" + if [ -z "$A_BR" ]; then + A_BR="No audio found" + fi + V_LENGTH=${VID_LEN[i]} + [[ $this_set = "group" ]] && V_LENGTH=${GROUP_VID_LEN[i]} + FPS="$(awk -F= '/ID_VIDEO_FPS/ {print $2}' <<< "${IN_STATS[i]}")" + yecho "" + if [[ $this_set = "group" ]] && ((i == 0)); then + print2log ""; print2log ". . . Grouped file stats . . ." + yecho "" + fi + [[ $this_set = "group" ]] && print2log "Stats for \ + $(readlink -f "${FILES_IN[i]}")" || \ + print2log "Stats for" "${FILES_IN[i]}" + echo -e \ + " video codec: " \ + "$VCODEC" "\n" \ + "video bitrate: " "$V_BR" "bits per second" "\n" \ + "framerate: " "$FPS" "fps" "\n" \ + "audio codec: " \ + "$ACODEC" "\n" \ + "audio bitrate: " \ + "$A_BR" "bits per second" "\n" \ + "video length: " \ + "$V_LENGTH" "seconds" |pipe2log + done + } test_compliance() { @@ -647,8 +783,14 @@ # slide mpg's go in $WORK_DIR, and are moved to BASEDIR later if recursing # for video files: files are named $IN_FILE.enc.mpg unset FILES_TO_ENCODE ENC_IN_FILES CHECK_IN_FILES + # get user's config options for makempg from the tovid.ini file + makempg_ini_opts=$(tovid mpg | awk '/Read options/{getline;print}') group_set=false - if [[ $1 = "group" ]]; then + if $ENCODE_ONLY; then + # encoding all files as -encode-only was used + CHECK_IN_FILES=() + FILES_TO_ENCODE=( "${IN_FILES[@]}" ) + elif [[ $1 = "group" ]]; then group_set=: unset x a CHECK_IN_FILES=( "${grouping[@]}" ) @@ -670,7 +812,7 @@ OUTFILE="$WORK_DIR/${TSET_NUM}-$((i+1)).mpg" fi - spin "Checking compliance of file $((i+1))" + print2log "Checking compliance of file $((i+1))" # if file tested as an image when we were verifying input files if [[ $is_image = "yes" ]]; then $group_set && grp_use_image2mpeg2[i]="yes" || @@ -691,48 +833,51 @@ ENC_IN_FILES=("${ENC_IN_FILES[@]}" "${IN_FILE}.enc.mpg") fi done + echo $DEBUG && etime=$(date +%s) && get_elapsed "compliance check" if test "${#FILES_TO_ENCODE[@]}" -gt 0; then TGT_CAPS=$(tr a-z A-Z <<< "$TARGET") TV_STND_CAPS=$(tr a-z A-Z <<< "$TV_STANDARD") - echo - yecho "Encode input files" + print2log "Encode input files" if ! $SINGLE_SLIDESHOW; then - echo - yecho "Some of the -files you provided are not \ - $TV_STND_CAPS $TGT_CAPS-compliant:" - echo " " + if $ENCODE_ONLY; then + yecho "Encoding the following files to \ + $TV_STND_CAPS $TGT_CAPS format:" + else + yecho "Some of the -files you provided are not \ + $TV_STND_CAPS $TGT_CAPS-compliant:" + fi + print2log "" fi if test ${#FILES_TO_ENCODE[@]} -lt 12 && ! $SINGLE_SLIDESHOW; then + printgreen '-------------' for i in "${FILES_TO_ENCODE[@]}"; do this_file=$(readlink -f "$i") test -n "$this_file" && yecho " $this_file" done + printgreen '-------------' fi # this ugly list of OR's are cases we want automatic encoding # all switched runs except the 1st, if -no-ask, if single slideshow # or if all input files are images if { $SWITCHED && [[ $MENU_NUM -ne 2 ]] ; } \ - || $NOASK || [[ ${TOVID_OPTS[@]} = *-noask* ]] || \ + || $NOASK || [[ ${TOVID_OPTS[@]} = *-noask* ]] || $ENCODE_ONLY || \ [[ ${#NO_PROMPT_FILES[@]} = ${#FILES_TO_ENCODE[@]} ]]; then - yecho " " echo "Encoding files to $TV_STND_CAPS $TGT_CAPS-compliant format." - echo "(This may take a long time)" ENCODE="yes" else - yecho " " + yecho "" yecho "I can encode them for you, but it may take a long time." yecho "Encoding will ensure that your disc is fully compliant;" yecho "you may skip this, but your disc may not be playable." yecho "Please type 'yes' if you want the files to be encoded:" read ENCODE - fi - if test -n "$ENCODE" && test "$ENCODE" = 'yes'; then - if ! $SINGLE_SLIDESHOW; then - yecho - yecho "Converting files to $TGT_CAPS format" - yecho + if [[ $ENCODE = "yes" ]]; then + ! $SINGLE_SLIDESHOW && yecho \ + "Converting files to $TGT_CAPS format" fi + fi + if [[ $ENCODE = 'yes' ]]; then for i in "${!FILES_TO_ENCODE[@]}"; do IN=$(readlink -f "${FILES_TO_ENCODE[i]}") if $group_set; then @@ -762,12 +907,26 @@ fi # AUDIO_FADE=false # do not fade silence FIXME ??? else # not an image file - outfile goes beside infile - THIS_FILE=$(readlink -f "${FILES_TO_ENCODE[i]}") - yecho "Converting $THIS_FILE" + #THIS_FILE=$(readlink -f "${FILES_TO_ENCODE[i]}") + if [[ -e "$IN.enc.mpg" ]]; then + if ! grep -w -- -overwrite <<< \ + "$makempg_ini_opts ${script_args[@]}"; then + : #FIXME echo to terminal what makempg would do ? + fi + fi + yecho "Converting $IN" echo - countdown 3 + continue_in 3 TOVID_WORKING_DIR=$WORKING_DIR makempg $NO_ASK \ - -$TV_STANDARD -$TARGET -in "$IN" -out "${IN}.enc" "${TOVID_OPTS[@]}" + -$TV_STANDARD -$TARGET -in "$IN" -out "${IN}.enc" \ + "${TOVID_OPTS[@]}" + wait + if [[ -e "${IN}.enc.mpg" ]]; then + ! $ENCODE_ONLY && yecho "Using ${IN}.enc.mpg for this DVD" + else + runtime_error "There appears to be a problem creating \ + the DVD compatible mpeg. See $LOG_FILE for details" + fi # for grouped files replace symlink in $WORK_DIR $group_set && [[ -L "${FILES_TO_ENCODE[i]}" ]] && \ ln -sf "${IN}.enc.mpg" "${FILES_TO_ENCODE[i]}" @@ -783,17 +942,19 @@ KEEP_FILES=: runtime_error "Could not encode file: $IN" fi - #yecho + #yecho "" done # Replace IN_FILES with ENC_IN_FILES (with .enc extension) # for grouped files the mpeg already replaced the group symlink ! $group_set && IN_FILES=("${ENC_IN_FILES[@]}") else - yecho - yecho "Not re-encoding. I will proceed with menu generation, but" - yecho "your authored disc will not be fully $TGT_CAPS-compliant." - yecho + if $ENCODE_ONLY; then + info_message "Not re-encoding." + else + info_message "Not re-encoding. I will proceed with menu generation, but + your authored disc will not be fully $TGT_CAPS-compliant." + fi fi fi } @@ -804,7 +965,7 @@ VIDEO_IN="$1" VIDEO_IN_SEEK="$2" video_type=$3 - yecho + yecho "" yecho "$VIDEO_IN is not compliant - re-encoding \ $(bc <<< "$VIDEO_IN_SEEK + ${MENU_LEN[MENU_NUM-1]}" 2>/dev/null) second slice to DVD compliant file" @@ -819,9 +980,9 @@ return fi fi - yecho + yecho "" yecho "Converting files to $TGT_CAPS format with 'makempg'" - countdown + continue_in 5 makempg $NO_ASK -in "$VIDEO_IN" \ -slice 0-$(bc <<< "$VIDEO_IN_SEEK + ${MENU_LEN[MENU_NUM-1]}" 2>/dev/null) \ -${TV_STANDARD} -${TARGET} -in "$VIDEO_IN" \ @@ -834,7 +995,7 @@ [[ $video_type = background ]] && BG_VIDEO="${VIDEO_IN}.enc.mpg" fi SUPPORT_VIDEOS=( "${SUPPORT_VIDEOS[@]}" "${VIDEO_IN}.enc.mpg" ) - yecho + yecho "" } mk_workdir() @@ -982,13 +1143,18 @@ { IN_IMAGE="$1" OUT_MPEG="$2" + # need to set VIDSIZE here as pal VIDSIZE assignment is later in script + [ $TV_STANDARD = "pal" ] && VIDSIZE=720x576 + VF_SCALE=${VIDSIZE%x*}:${VIDSIZE#*x} # remove symlinks, as otherwise we overwrite symlink target - IMAGE_ENC_CMD=(ffmpeg -f image2 $LOOP -vframes $vlength \ - -i "$IN_IMAGE" -s $VIDSIZE -f s16le -ar 48000 -i /dev/zero -t $alength \ + IMAGE_ENC_CMD=($FFmpeg -f image2 $LOOP \ + -i "$IN_IMAGE" -f s16le -ar 48000 -i /dev/zero -t $alength \ -ar $SAMPLERATE -ac 2 -ab 224k -target ${TV_STANDARD}-${TARGET} \ - -aspect $ASPECT_RATIO -y "$OUT_MPEG") - echo "Running ${IMAGE_ENC_CMD[@]}" | format_output >> "$LOG_FILE" - "${IMAGE_ENC_CMD[@]}" 2>&1 |strings >> "$LOG_FILE" + $VF scale=${VF_SCALE},${ASPECT} -y -vframes $vlength "$OUT_MPEG") + print2log "" + print2log "Running ${IMAGE_ENC_CMD[@]}" + print2log "" + "${IMAGE_ENC_CMD[@]}" 2>&1 | pipe2log fmpeg } switched_menu_mode() @@ -1003,6 +1169,7 @@ -basedir "$BASEDIR" -menu_num $((i+1)) -showcase "${FILES[i]}"" todisc "$@" -switched-mode $IS_TITLESET -basedir "$WORK_DIR" \ -menu_num $((i+1)) -todisc_pids "$TODISC_PIDS" -showcase "${FILES[i]}" + yecho done yecho yecho "Working on switched menu 1" @@ -1034,9 +1201,9 @@ fi MC_CMD=(todisc -slides "${IN_SLIDES[@]}" $mix_range \ $NO_CONFIRM_BACKUP ${encopt[@]} $sld_tranition $background_carousel \ - $showcase_carousel -out "$OUT_PREFIX" -carousel_menu_mode -basedir \ + $showcase_carousel -out "$OUT_DIRECTORY" -carousel_menu_mode -basedir \ "$WORK_DIR" $menulen -carousel_num $((c+1)) -todisc_pids "$TODISC_PIDS") - yecho + yecho "" yecho "Running ${MC_CMD[@]}" "${MC_CMD[@]}" } @@ -1205,7 +1372,8 @@ DVDAUTHOR_XML="$BASEDIR/dvdauthor.xml" VMGM_PRE=" if ( g5 eq 0 ) g5=1;" VMGM_PRE="$VMGM_PRE\n if ( g6 eq 0 ) g6=1; button = g6 * 1024;" - egrep -qw -- "-switched-menu[s]" <<< "${args[@]}" && \ + # switch is now singular (-switched-menu) OR plural (-switched-menus) + egrep -q -- "-switched-menu" <<< "${args[@]}" && \ VMGM_PRE="$VMGM_PRE\n if (g1 eq 0) g1=1;" $DO_INTRO && INTRO_PRE=" if (g2==1) jump cell 2; " $SKIP_VMGM_MENU && VMGM_PRE="$VMGM_PRE\n if ( g3 eq 0 ) g3=1 ;" @@ -1324,7 +1492,7 @@ ################### end titleset options testing ######################### if [[ -z ${VMGM_OPTS[@]} ]]; then - yecho + #yecho yecho "You have not supplied -vmgm OPTIONS -end-vmgm" yecho "At a minumum you should have: \ '-vmgm -titles "Title one" "Title two" -end-vmgm'" @@ -1344,8 +1512,8 @@ fi yecho "Making a generic vmgm menu for you - \ you may wish to cancell out and change this." - yecho - $VMGM_MENU && $WARN && sleep 15 + yecho "" + $VMGM_MENU && $WARN && continue_in 15 else unset vmgmtitles get_menu_titles "${VMGM_OPTS[@]}" @@ -1356,12 +1524,11 @@ fi ################### end titleset options testing ######################### # VMGM menu - yecho - yecho "Making a VMGM menu with the following command:" + print2log "Making a VMGM menu" vmgm_menu_cmd=(todisc "${GEN_OPTS[@]}" -basedir "$WORK_DIR" -vmgm_only \ -textmenu -todisc_pids "$TODISC_PIDS" $NO_CONFIRM_BACKUP \ -title_count "$num_titles" $vmgm_playall "${VMGM_OPTS[@]}") - yecho "Running: ${vmgm_menu_cmd[@]}" + print2log "Running: ${vmgm_menu_cmd[@]}" INITIALDIR="$BASEDIR" if ! "${vmgm_menu_cmd[@]}" ; then cleanup && exit 1; fi # TITLESET menus @@ -1385,8 +1552,8 @@ yecho yecho "Working on the menu for titleset number $tset" yecho - $WARN && sleep 5 - yecho "Running: ${titleset_cmd[@]}" + $WARN && continue_in 5 + print2log "Running: ${titleset_cmd[@]}" if ! "${titleset_cmd[@]}"; then cleanup && exit 1; fi yecho ;; @@ -1395,7 +1562,7 @@ done echo -e "</dvdauthor>" >> "$DVDAUTHOR_XML" yecho "Running dvdauthor to create final DVD structure" - dvdauthor -x "$DVDAUTHOR_XML" 2>&1 | tee -a "$LOG_FILE" + dvdauthor -x "$DVDAUTHOR_XML" 2>&1 | pipe2log dvdauthor if [[ ${PIPESTATUS[0]} -ne 0 ]]; then dvdauthor_error fi @@ -1420,7 +1587,9 @@ burn_disc() { - BURN_CMD=(tovid dvd -burn -device $EJECT "$BURN_DEVICE" \ + BURN_TGT="$OUT_DIR" + BURN_TGT_STR="DVD directory" + BURN_CMD=(tovid dvd -burn -device "$BURN_DEVICE" $EJECT \ $BURN_SPEED \"$BURN_TGT\") yecho echo "You have indicated you want to burn the $BURN_TGT_STR" @@ -1431,9 +1600,12 @@ if [ ! -z "$input" -a "$input" = "yes" ]; then echo "Proceeding to burn, continuing." echo - $BURN_PROG -burn -device "$BURN_DEVICE" \ - $BURN_SPEED "$BURN_TGT" | tee -a "$LOG_FILE" 2>&1 - if ((${PIPESTATUS[0]}==0)); then + # probably could do redirection using exec and such, but this is simple + $BURN_PROG -device "$BURN_DEVICE" \ + $BURN_SPEED "$BURN_TGT" | tee "$WORK_DIR/makedvd.log" + pipe_status=${PIPESTATUS[0]} + pipe2log makedvd < "$WORK_DIR/makedvd.log" + if ((pipe_status==0)); then echo "Your ${BURN_TGT_STR/ *} should be ready" else echo "There was a problem burning the ${BURN_TGT_STR/ *}" @@ -1449,80 +1621,88 @@ thanks_goodbye() { - echo - echo $SEPARATOR SCRIPT_TIME=$(format_seconds $SECONDS) - echo "todisc took $SCRIPT_TIME to finish on $CPU_MODEL $CPU_SPEED mhz" - echo $SEPARATOR - echo "Your new DVD should be in $OUT_DIR" - echo "You can preview them in gxine with this command:" - echo " gxine \"dvd:/$OUT_DIR\"" - echo "If you are satisfied with the results, you can burn a disc with:" - echo " tovid dvd -burn \"$OUT_DIR\"" + goodbye=`cat << EOF + + $SEPARATOR + todisc took $SCRIPT_TIME to finish on + $CPU_MODEL $CPU_SPEED mhz + $SEPARATOR + + Your new DVD should be in $OUT_DIR + You can preview them in gxine with this command: + $(printf "%s\t" "gxine \"dvd:/$OUT_DIR\"") + Or in vlc with this command: + $(printf "%s\t" "vlc \"$OUT_DIR\"") + If you are satisfied with the results, you can burn a disc with: + $(printf "%s\t" "tovid dvd -burn \"$OUT_DIR\"") + + Thanks for using tovid! +EOF` echo - echo "Thanks for using todisc." + sed 's/^ //g' <<< "$goodbye" | tee -a "$LOG_FILE" } -# usage mk_return_button (mk_play_button) COLOUR1 COLOUR2 OUTBUTTON +# usage mk_return_button (mk_play_button) COLOUR1 COLOUR2 outbutton # ex. for menu button ( not spumux ): # mk_return_button "#C6C6C6" black "$WORK_DIR/Main.png" mk_return_button() { - COLR1="$1" - COLR2="$2" - TYPE=$3 - OUTBUTTON="$4" - if [[ $TYPE = "spu" ]]; then - CLR1="none" - elif [[ $TYPE = "default" ]]; then - CLR1="$COLR1" + colr1="$1" + colr2="$2" + local auth_type=$3 + outbutton="$4" + if [[ $auth_type = "spu" ]]; then + clr1="none" + elif [[ $auth_type = "default" ]]; then + clr1="$colr1" fi - MK_RTN_CMD=(convert -size 100x80 xc:none \ - -strokewidth 1 -stroke "$COLR2" -fill "$CLR1" \ + mk_rtn_cmd=(convert -size 100x80 xc:none \ + -strokewidth 1 -stroke "$colr2" -fill "$clr1" \ -draw 'rectangle 0,0 70,62' \ - -fill "$COLR2" -stroke none \ + -fill "$colr2" -stroke none \ -draw "polyline 40,10 40,50 10,30 40,10" \ -draw "polyline 60,10 60,50 30,30 60,10" \ - -fill "$COLR2" -draw "rectangle 6,10 10,50" \ - -resize 30% -trim +repage +antialias "$OUTBUTTON") - echo -e "\nRunning ${MK_RTN_CMD[@]}\n" |format_output - "${MK_RTN_CMD[@]}" - mogrify -channel A -threshold 50% "$OUTBUTTON" - RTN_BTN_DIM=$(get_image_dim "$OUTBUTTON") - rtn_btn_width=$(awk -Fx '{print $1}' <<< $RTN_BTN_DIM ) - rtn_btn_height=$(awk -Fx '{print $2}' <<< $RTN_BTN_DIM ) + -fill "$colr2" -draw "rectangle 6,10 10,50" \ + -resize 30% -trim +repage +antialias "$outbutton") + print2log "Running ${mk_rtn_cmd[@]}" + "${mk_rtn_cmd[@]}" + mogrify -channel A -threshold 50% "$outbutton" + rtn_btn_dim=$(get_image_dim "$outbutton") + rtn_btn_width=$(awk -Fx '{print $1}' <<< $rtn_btn_dim ) + rtn_btn_height=$(awk -Fx '{print $2}' <<< $rtn_btn_dim ) } mk_play_button() { - COLR1="$1" - COLR2="$2" - TYPE=$3 - OUTBUTTON="$4" - if [[ $TYPE = "spu" ]]; then - CLR1="none" - elif [[ $TYPE = "default" ]]; then - CLR1="$COLR1" - fi - #-fill "$COLR2" -draw "line 40,10 40,50" \ - # -fill "$COLR2" -draw "rectangle 36,10 40,50" \ - MK_PLAY_CMD=(convert +antialias -size 100x80 xc:none \ - -strokewidth 2 -stroke "$COLR2" -fill "$CLR1" \ + colr1="$1" + colr2="$2" + local auth_type=$3 + outbutton="$4" + if [[ $auth_type = "spu" ]]; then + clr1="none" + elif [[ $auth_type = "default" ]]; then + clr1="$colr1" + fi + #-fill "$colr2" -draw "line 40,10 40,50" \ + # -fill "$colr2" -draw "rectangle 36,10 40,50" \ + mk_play_cmd=(convert +antialias -size 100x80 xc:none \ + -strokewidth 2 -stroke "$colr2" -fill "$clr1" \ -draw 'rectangle 22,0 92,62' \ - -fill "$COLR2" -stroke none \ + -fill "$colr2" -stroke none \ -draw "polyline 40,10 40,50 80,30 40,10" \ - -resize 30% -trim +repage "$OUTBUTTON") - echo -e "\nRunning ${MK_PLAY_CMD[@]}\n" |format_output >> "$LOG_FILE" - "${MK_PLAY_CMD[@]}" - PLAY_BTN_DIM=$(get_image_dim "$OUTBUTTON") - play_btn_width=$(awk -Fx '{print $1}' <<< $PLAY_BTN_DIM ) - play_btn_height=$(awk -Fx '{print $2}' <<< $PLAY_BTN_DIM ) + -resize 30% -trim +repage "$outbutton") + print2log "Running ${mk_play_cmd[@]}" + "${mk_play_cmd[@]}" + play_btn_dim=$(get_image_dim "$outbutton") + play_btn_width=$(awk -Fx '{print $1}' <<< $play_btn_dim ) + play_btn_height=$(awk -Fx '{print $2}' <<< $play_btn_dim ) } check_menufile() { - yecho + yecho "" if test -f "$MENU_FILE"; then echo "Menu file $MENU_FILE created" echo @@ -1535,54 +1715,38 @@ quick_menu() { funct_arg=$1 - unset LEFTPAD TOPPAD RIGHTPAD BOTTOMPAD # is it a preview or main run of menu creation if [[ -n $funct_arg && $funct_arg = "preview" ]]; then QM_MENU_TIME=2 && QM_PREVIEW=: else QM_MENU_TIME=${MENU_LEN[MENU_NUM-1]} && QM_PREVIEW=false fi - # test for filters and vhook - filters=$(ffmpeg -filters 2>/dev/null) - if grep -q -w '^movie' <<< "$filters" && \ - grep -q -w '^crop' <<< "$filters"; then - echo "libavfilter overlay and crop filters are present" - use_overlay_filter=: - $use_overlay_filter && echo "Using libavfilter for -quick-menu" - elif grep -q ^-vhook <<< "$(ffmpeg -h 2>&1)"; then - # find out where vhook lives for ffmpeg - local config=$(ffmpeg -version 2>&1 | grep -- --prefix=) - config=${ffmpeg_prefix//*--prefix=} - ffmpeg_prefix=${config// *} - # empty var means no --prefix passed, use default prefix of /usr/local - ffmpeg_prefix=${ffmpeg_prefix:-/usr/local} - imlib2_vhook="${ffmpeg_prefix}/lib/vhook/imlib2.so" - if [[ -s "$imlib2_vhook" ]]; then - use_vhooks=: - else - yecho "!!!!! $imlib2_vhook not found, can not continue !!!!!" + # test for filters presense in ffmpeg + # ffmpeg has really poor support for scripts so we can't do something + # sane like grep for ^movie or ^crop. + # using these ugly repeated grep calls because they are easier to + # understand/maintain than an awk command. + if ! ((filter_test_completed)); then + filters=$($FFmpeg -filters 2>/dev/null) + if grep -w 'movie' <<< "$filters" | grep -q -v 'amovie' && + grep -w 'crop' <<< "$filters" | grep -q -v 'cropdetect'; then + print2log "libavfilter movie filter present, using for -quick-menu" + use_overlay_filter=: + else + # exit if missing a needed video filter + runtime_error \ + "Missing ${FFmpeg##*/} filters + (movie or crop) -quick-menu impossible." fi fi - # FIXME this will not be needed when the overlay filter is in SVN proper - if ! $use_vhooks && ! $use_overlay_filter; then - runtime_error "You are not able to use -quick-menu: - you must use the experimental ffmpeg with libavfilter - or an older (0.52 for example) version of ffmpeg with vhooks. - See this post for details on installing ffmpeg with filters: - http://ubuntuforums.org/showthread.php?p=9021636" - fi + # ensure the filter test is only run once + filter_test_completed=1 if $QUICKMENU_IS_SHOWCASE; then - yecho - yecho "resizing and padding showcase file: $SHOWCASE_VIDEO" - LEFTPAD=$SC_X - TOPPAD=$SC_Y - RIGHTPAD="-padright \ - $(( ${VIDSIZE%%x*} - $LEFTPAD - ${SHOWCASE_SIZE%%x*} ))" - BOTTOMPAD="-padbottom \ - $(( ${VIDSIZE##*x} - $TOPPAD - ${SHOWCASE_SIZE##*x} ))" - LEFTPAD="-padleft $SC_X" - TOPPAD="-padtop $SC_Y" + if ! $NOASK; then + yecho "" + yecho "resizing and padding showcase file: $SHOWCASE_VIDEO" + fi local VF_PADX=$SC_X local VF_PADY=$SC_Y QM_FRAMESIZE=$SHOWCASE_SIZE @@ -1603,24 +1767,22 @@ qm_post_seek=$qm_seek && unset qm_pre_seek fi - $QM_PREVIEW && yecho "Creating a quick-menu preview image" - # pad/resize if needed, use overlay filter (or vhook) to add menu graphics + $QM_PREVIEW && ! $NOASK && yecho "Creating a quick-menu preview image" + # pad/resize if needed, use overlay filter to add menu graphics # framing (if showcase) by ntsc-safe black bg - ! $QM_PREVIEW && yecho if ! $QM_PREVIEW; then - yecho "Using ffmpeg to add titles and background" + yecho "" + yecho "Using $FFmpeg to add titles and background" fi if $use_overlay_filter; then + local qw=${QM_FRAMESIZE%x*} + local qh=${QM_FRAMESIZE#*x} + # vhook uses the next var for scaling, but overlay does not + unset QM_FRAMESIZE local overlay="$WORK_DIR/quick_menu_bg.png" - local PADDING="$VF pad=720:480:$VF_PADX:$VF_PADY" - local aspect="" - overlay_filter="movie=$overlay [wm];[in][wm] overlay=0:0:1 [wm2]" + local PADDING="$VF scale=${qw}:${qh},pad=$VF_SCALE:${VF_PADX}:${VF_PADY}" + overlay_filter="movie=$overlay [wm];[in][wm] overlay=0:0 [wm2]" ffmpeg_filter=($VF "$overlay_filter; [wm2] setdar=4:3 [out]") - elif $use_vhooks; then - local PADDING="$TOPPAD $BOTTOMPAD $LEFTPAD $RIGHTPAD" - local aspect="-aspect 4:3" - local PAD_CLR="-padcolor $BG_CLR" - ffmpeg_filter=(-vhook "$imlib2_vhook -x 0 -y 0 -i $WORK_DIR/quick_menu_bg.png") fi # no padding needed for background video, just resizing $QUICKMENU_IS_BACKGROUND && PADDING="" @@ -1628,59 +1790,62 @@ yuvout="$WORK_DIR/out.yuv" rm -f "$yuvout" && mkfifo "$yuvout" # run the commands to make the final menu m2v video - PAD_CMD=(ffmpeg -r $FRAME_RATE -async 1 $qm_pre_seek \ - -t "$QM_MENU_TIME" -i "$QUICK_MENU_FILE" $qm_post_seek \ - -s $QM_FRAMESIZE -an $PADDING -r $FRAME_RATE \ + PAD_CMD=($FFmpeg -async 1 $qm_pre_seek \ + -i "$QUICK_MENU_FILE" $qm_post_seek -t "$QM_MENU_TIME" \ + -an $PADDING -r $ff_frame_rate \ $PAD_CLR -f yuv4mpegpipe -vcodec rawvideo -y "$yuvout") - QUICKMENU_CMD=(ffmpeg -s $VIDSIZE -f yuv4mpegpipe \ - -i "$yuvout" -an -f mpeg2video -r $FRAME_RATE \ - -tvstd $TV_STANDARD -b 7000k -maxrate 8000k -bufsize 224KiB \ - $aspect "${ffmpeg_filter[@]}" -y "$WORK_DIR/intro.m2v") - $QM_PREVIEW && yecho - yecho "Running ${PAD_CMD[@]}"|fold -bs - echo "${QUICKMENU_CMD[@]}" | fold -bs | tee -a "$LOG_FILE" - "${PAD_CMD[@]}" < /dev/null > "${LOG_FILE}-1.tmp" 2>&1 & - "${QUICKMENU_CMD[@]}" < /dev/null > "${LOG_FILE}-2.tmp" 2>&1 & + # removed-s $VIDSIZE from following cmd, don't think it needs it + # check if I need to add a scale filter, perhaps comma sep at end. + # http://forum.videohelp.com/threads/338494-Multiple-filter-problem-with-ffmpeg-help-please + QUICKMENU_CMD=($FFmpeg -f yuv4mpegpipe \ + -i "$yuvout" -an -f mpeg2video -r $ff_frame_rate \ + $VB 7000k -maxrate 8000k -bufsize 224KiB \ + "${ffmpeg_filter[@]}" -y "$WORK_DIR/intro.m2v") + echo "Running ${PAD_CMD[@]}" > "${LOG_FILE}-1.tmp" + "${PAD_CMD[@]}" < /dev/null >> "${LOG_FILE}-1.tmp" 2>&1 & + echo "Running ${QUICKMENU_CMD[@]}" > "${LOG_FILE}-2.tmp" + "${QUICKMENU_CMD[@]}" < /dev/null >> "${LOG_FILE}-2.tmp" 2>&1 & ffmpeg_pid=$! - yecho - while ps -p $ffmpeg_pid >/dev/null; do - sleep 1 - [[ -s "$WORK_DIR/intro.m2v" ]] && txt="Writing" || txt="Seeking" - spin $txt $SPINNER - done + if ! $QM_PREVIEW; then + while ps -p $ffmpeg_pid >/dev/null; do + sleep 1 + [[ -s "$WORK_DIR/intro.m2v" ]] && txt="Writing" || txt="Seeking" + spin $txt $SPINNER + done + fi wait - yecho + ! $QM_PREVIEW && yecho "" # remove control characters and seeking lines - strings "${LOG_FILE}-1.tmp" | sed '/time=10000000000.00/d' >> "$LOG_FILE" - strings "${LOG_FILE}-2.tmp" | sed '/time=10000000000.00/d' >> "$LOG_FILE" + [[ -e ${LOG_FILE}-1.tmp ]] && \ + cat "${LOG_FILE}-1.tmp" | sed '/time=10000000000.00/d' | pipe2log ${FFmpeg##*/} + [[ -e ${LOG_FILE}-2.tmp ]] && \ + cat "${LOG_FILE}-2.tmp" | sed '/time=10000000000.00/d' | pipe2log ${FFmpeg##*/} if [[ ! -s "$WORK_DIR/intro.m2v" ]]; then runtime_error "There was a problem creating the menu video $funct_arg" fi rm -f "${LOG_FILE}*.tmp" - ! $QM_PREVIEW && yecho + ! $QM_PREVIEW && yecho "" # create preview images if called for, taking largest of 10 images if $QM_PREVIEW; then - FFMPEG_CMD=(ffmpeg -i "$WORK_DIR/intro.m2v" -an -vframes 10 \ + FFMPEG_CMD=($FFmpeg -i "$WORK_DIR/intro.m2v" -an -vframes 10 \ -f image2 -y "$outdir"/%06d.$IMG_FMT) - yecho "Running ${FFMPEG_CMD[@]}" | strings - "${FFMPEG_CMD[@]}" 2>&1 | strings >> "$LOG_FILE" + print2log "Running ${FFMPEG_CMD[@]}" + "${FFMPEG_CMD[@]}" 2>&1 | pipe2log ${FFmpeg##*/} # take the largest image (best quality?) of a 10 frame sampling largest_img=$(get_largest 6 10 "$outdir" ) mv "$largest_img" "$PREVIEW_IMG" - yecho "Removing temporary preview files" + print2log "Removing temporary preview files" rm -f "$WORK_DIR/intro.m2v" rm -f "$WORK_DIR"/showcase/*.$IMG_FMT "$WORK_DIR"/bg/*.$IMG_FMT fi - $QM_PREVIEW && yecho + $QM_PREVIEW && yecho "" } # 3x1 and 4x1 tile only for default arrangement tile_warning() { - yecho - echo "-tile-3x1 and -tile-4x1 are not showcase options. Disabling" - yecho - $WARN && sleep 5 + info_message "-tile-3x1 and -tile-4x1 are not showcase options. Disabling" + $WARN && continue_in 5 } dvdauthor_error() { @@ -1721,30 +1886,34 @@ make_dummy() { - yecho "Creating a blank mpeg for the vmgm menu" convert -resize $VIDSIZE! xc:"#101010" "$WORK_DIR/dummy.jpg" - ENC_CMD1=(jpeg2yuv -v 1 -f $FRAME_RATE -I p -n 1 -l 30 \ + [[ $TV_STANDARD = "ntsc" ]] && local len=30 || local len=25 + ENC_CMD1=(jpeg2yuv -v 1 -f $FRAME_RATE -I p -n 1 -l $len \ -L 1 -b1 -j "$WORK_DIR/dummy.jpg") - ENC_CMD2=(ffmpeg -f yuv4mpegpipe -i - -an -r $FRAME_RATE -s $VIDSIZE \ - -tvstd $TV_STANDARD $FFMPEG_OPTS -y "$WORK_DIR/dummy.m2v") - echo "Running: ${ENC_CMD1[@]} | ${ENC_CMD2[@]}" | - format_output | tee -a "$LOG_FILE" - if ! ${ENC_CMD1[@]} 2>> "$LOG_FILE" | - ${ENC_CMD2[@]} 2>&1 |strings >> "$LOG_FILE"; then - runtime_error - fi - VMGM_TIME=$(vid_length "$WORK_DIR/dummy.m2v") - yecho - BGAUDIO_CMD=(ffmpeg -f s16le -ar 48000 -i /dev/zero -t $VMGM_TIME \ + ENC_CMD2=($FFmpeg -f yuv4mpegpipe -i - -an -r $ff_frame_rate \ + $FFMPEG_OPTS -vf scale=${VF_SCALE},${ASPECT} -y "$WORK_DIR/dummy.m2v") + print2log "Running: ${ENC_CMD1[@]} | ${ENC_CMD2[@]}" + ${ENC_CMD1[@]} 2>> "${LOG_FILE}.tmp" | + ${ENC_CMD2[@]} 2>&1 |pipe2log ${FFmpeg##*/} + [[ -e ${LOG_FILE}.tmp ]] && cat "${LOG_FILE}.tmp" | pipe2log jpeg2yuv + rm -f "${LOG_FILE}.tmp" + ! [[ -s "$WORK_DIR/dummy.m2v" ]] && \ + runtime_error "There was a problem creating a dummy vmgm video" + local VMGM_TIME=1 # use one second as dummy.m2v or either 30 or 25 frames + BGAUDIO_CMD=($FFmpeg -f s16le -ar 48000 -i /dev/zero -t $VMGM_TIME \ $AUDIO_OPTS -y "$WORK_DIR/dummy.$AUDIO_EXT") - yecho "${BGAUDIO_CMD[@]}" - "${BGAUDIO_CMD[@]}" 2>&1 | strings >> "$LOG_FILE" - ! [[ -s "$WORK_DIR/dummy.$AUDIO_EXT" ]] && runtime_error + print2log "Creating silent audio stream." + print2log "${BGAUDIO_CMD[@]}" + "${BGAUDIO_CMD[@]}" 2>&1 | pipe2log ${FFmpeg##*/} + ! [[ -s "$WORK_DIR/dummy.$AUDIO_EXT" ]] && runtime_error \ + "There was a problem creating audio for the dummy vmgm menu" MPLEX_CMD=(mplex -V -f $MPLEX_FORMAT -o "$BASEDIR/dummy.mpg" \ "$WORK_DIR/dummy.$AUDIO_EXT" "$WORK_DIR/dummy.m2v") - echo "Running: ${MPLEX_CMD[@]}" |fold -bs >> "$LOG_FILE" - ! "${MPLEX_CMD[@]}" 2>&1 |strings >> "$LOG_FILE" && runtime_error + print2log "Running: ${MPLEX_CMD[@]}" + "${MPLEX_CMD[@]}" 2>&1 |pipe2log mplex + ((${PIPESTATUS[0]} != 0)) && runtime_error \ + "There was a problem muxing the audio and video with mplex" } verify_infiles() { @@ -1762,7 +1931,7 @@ IN_FILE="${in_files[i]}" if test -s "$IN_FILE"; then check_filetype "$IN_FILE" - if [[ $TYPE = "image" ]]; then + if [[ $file_type = "image" ]]; then IMG_STATS=( $(identify -ping -format "%z %w %h" "$IN_FILE") ) DEPTH=${IMG_STATS[0]} IMG_WIDTH=${IMG_STATS[1]} @@ -1796,13 +1965,11 @@ # also convert if not PNG or JPEG or wrong aspect ratio # test IN_FILES for preview - group files tested later if [[ $DEPTH = 16 || $PAD_IMG = "yes" ]] || $CONVRT ; then - echo "Converting $IN_FILE to proper image format" \ - >> "$LOG_FILE" + print2log "Converting $IN_FILE to proper image format" IMG_CMD=(convert "$IN_FILE" -depth 8 "${CROP_CMD[@]}" \ -quality 01 "$OUTPNG") - format_output <<< "${IMG_CMD[@]}" \ - >> "LOG_FILE" - "${IMG_CMD[@]}" |format_output >> "$LOG_FILE" 2>&1 + print2log "${IMG_CMD[@]}" + "${IMG_CMD[@]}" 2>&1| pipe2log imagemagick # replace IN_FILES[i] OR group symlink if [[ $verify_type = "infiles" ]]; then IN_FILES[i]=$OUTPNG @@ -1830,8 +1997,7 @@ grp_file_is_image[i]="yes" fi spin checking "${IN_FILE##*/}" - elif mencoder -quiet -oac pcm -ovc copy \ - -frames 0 -o /dev/null "$IN_FILE" &>/dev/null; then + elif is_video "$IN_FILE"; then checkfile="${IN_FILE##*/}" spin checking "$checkfile" else @@ -1841,6 +2007,7 @@ usage_error "Sorry, $IN_FILE does not exist or is empty" fi done + echo } # contrasting 'undercolor' for -background from given font colour @@ -1943,22 +2110,23 @@ transition_slide() { - TYPE=$1 + local fade_type=$1 + local value index=$2 outppm="$WORK_DIR/animenu/$(printf %06d%s $index .ppm)" - if [[ $TYPE = "crossfade" ]]; then - local VALUE=$(bc -l <<< "scale=2; ($fade_slide + 1) * $fade_incr") >&2 - fade_cmd=(composite -blend $VALUE -depth 8 "$overlay_ppm" \ + if [[ $fade_type = "crossfade" ]]; then + value=$(bc -l <<< "scale=2; ($fade_slide + 1) * $fade_incr") >&2 + fade_cmd=(composite -blend $value -depth 8 "$overlay_ppm" \ "$base_ppm" "$outppm") - elif [[ $TYPE = "fadein" ]]; then - local VALUE=$(bc -l <<< "scale=2; $fade_slide * $fade_incr") >&2 + elif [[ $fade_type = "fadein" ]]; then + value=$(bc -l <<< "scale=2; $fade_slide * $fade_incr") >&2 fade_cmd=(composite -depth 8 "$base_ppm" "$WORK_DIR/black.ppm" \ - -blend ${VALUE}% "$outppm") - elif [[ $TYPE = "fadeout" ]]; then - local VALUE=$(bc -l <<< "scale=2;100 - (($fade_slide + 1) * $fade_incr)") >&2 - (( $(bc <<< "$VALUE < 0") == 1 )) && local VALUE=0 + -blend ${value}% "$outppm") + elif [[ $fade_type = "fadeout" ]]; then + value=$(bc -l <<< "scale=2;100 - (($fade_slide + 1) * $fade_incr)") >&2 + (( $(bc <<< "$value < 0") == 1 )) && value=0 fade_cmd=(composite -depth 8 "$base_ppm" "$WORK_DIR/black.ppm" \ - -blend ${VALUE}% "$outppm") + -blend ${value}% "$outppm") fi "${fade_cmd[@]}" >/dev/null } @@ -1966,10 +2134,10 @@ # this function does a loop with transition_slide() ... combine them into 1 ? do_transitions() { - TYPE=$1 + local fade_type=$1 fade_slide=0 for ((i=0; i<=fade_frames; i++)); do - transition_slide $TYPE $i & + transition_slide $fade_type $i & transition_pids="$transition_pids $!" ((num_procs++)) if ((num_procs == max_procs || i == fade_frames-1)); then @@ -1978,7 +2146,7 @@ fi let fade_slide=fade_slide+1 done - if [[ $TYPE = "fadeout" ]] && ((f == ${#MIX_IN[@]}-1)); then + if [[ $fade_type = "fadeout" ]] && ((f == ${#MIX_IN[@]}-1)); then for p in {0..12}; do cp "$WORK_DIR/black.ppm" \ "$WORK_DIR/animenu/$(printf %06d%s $((p +i)) .ppm)" >&2 @@ -2024,7 +2192,7 @@ -bordercolor grey60 -border 1 \ -rotate ${randir}${angle} \ -background black \( +clone -shadow 60x4+4+4 \) +swap \ - -background none -flatten \ + +repage -background none -flatten \ "$WORK_DIR/tnail${i%.*}.png" stack_files[i]=$WORK_DIR/tnail${i%.*}.png @@ -2048,23 +2216,6 @@ { echo -e "\nIt took $(format_seconds $((etime-stime)) ) for the $1\n" } -# make sure correct sample size option for sox is used -# getting sox version is inconsistent, so just run test command -get_sox_arg() -{ -if cat /dev/zero 2>/dev/null | nice -n 0 sox -t raw -c 2 -r 48000 -w -s - \ -"$WORK_DIR/foo.wav" trim 0 1 &>/dev/null; then - echo -w -elif cat /dev/zero 2>/dev/null | nice -n 0 sox -t raw -c 2 -r 48000 -2 -s - \ -"$WORK_DIR/foo.wav" trim 0 1 &>/dev/null; then - echo -2 -else - runtime_error "Your sox appears to be incompatible with this program. " \ - "Attempted to create a wav file using the -w option, then the -2 option" -fi -rm -f "$WORK_DIR/foo.wav" - -} # Usage: check_maskshape SHAPE. Returns 1 if SHAPE not found. check_maskshape() @@ -2087,7 +2238,7 @@ if [[ $mask_type == "thumb" ]]; then local BLUR_CMD=( "${THUMB_BLUR_CMD[@]}" ) else - local BLUR_CMD=( "${SC_BLUR_CMD[@]]}" ) + local BLUR_CMD=( "${SC_BLUR_CMD[@]}" ) fi MASK="$WORK_DIR/${shape}_${mask_type}_mask.png" @@ -2173,14 +2324,6 @@ convert - -resize $THUMB_SIZE! $MASK ;; "blob") - echo $SEPARATOR - echo "Running convert -size 100x60 xc:none -fill white \ - -draw \"circle 41,39 44,57 circle 59,39 56,57 circle 50,21 50,3\" miff:- | - convert - -trim +repage -bordercolor none -border 10x10 miff:- | - ${BLUR_CMD[@]} | ${BLUR_CMD[@]} | ${BLUR_CMD[@]} | ${BLUR_CMD[@]} | - convert - -resize $THUMB_SIZE! $MASK" | format_output - echo $SEPARATOR - convert -size 100x60 xc:none -fill white \ -draw "circle 41,39 44,57 circle 59,39 56,57 circle 50,21 50,3" miff:- | convert - -trim +repage -bordercolor none -border 10x10 miff:- | @@ -2206,15 +2349,31 @@ esac } +# wait for file to appear +# name and timeout are optional: defaults to basename of FILE and 12 secs +# usage: wait_for file [name] [timeout] wait_for() { - # wait for file to appear - while true; do - if test -e $1; then + local check_file=$1 + local filename=${check_file##*/} + # default timeout of 10 seconds + local timeout=${3:-10} + timeout=$((timeout * 10)) + local name=${2:-$filename} + x=0 + while ((x<timeout)); do + if test -e "$check_file"; then return fi + # print a message after 2 seconds: will only run when there is a problem + if ((x==20)); then + echo Waiting $(( (timeout / 10) - 2)) seconds for $name to appear ... + fi sleep .1 + ((x++)) done + unset x + return 1 } # HACK: transcode produces some scary output when run from python @@ -2224,7 +2383,7 @@ transcode shown below if it shows transcode finishing the last image. \ These harmless 'broken pipe' messages from transcode appear to be a \ subtle bug in transcode when running it (or a script) from python. \ - \n****\n" | sed "s/ */ /g;s/^ *//" |fold -bs >> "$LOG_FILE" + \n****\n" | sed "s/ */ /g;s/^ *//" | pipe2log todisc format } # get the largest PNG (1st match sequentially if more than one are same size) @@ -2248,6 +2407,16 @@ echo $result } +# tip from Steven M. Schultz +# https://www.mail-archive.com/mjpeg-users@lists.sourceforge.net/msg03511.html +# an alternative to yuvcorrect -T NO_HEADER +remove_header() +{ +read junk +cat +return 0 +} + ############################################################################## # End of Functions # ############################################################################## @@ -2268,7 +2437,7 @@ egrep -q 'titleset-mode|switched-mode|menu-only|carousel_menu_mode' <<< "$@" \ && NONAME=: -! $NONAME && yecho $"$SCRIPT_NAME" +! $NONAME && echo $"$SCRIPT_NAME" while test $# -gt 0; do DO_SHIFT=: @@ -2291,6 +2460,9 @@ for f in ${!ARGS_ARRAY[@]}; do FILENAMES[f]=${ARGS_ARRAY[f]} filenames[f]=$(readlink -f "${ARGS_ARRAY[f]}") + if [[ ! -e ${filenames[f]} ]]; then + usage_error "${filenames[f]} does not exist" + fi done if $incoming_slides; then SLIDESHOW=( ${SLIDESHOW[@]} : ) # is this a slideshow ? @@ -2306,6 +2478,9 @@ unset group groupkey grp x for ((i=0; i<${#ARGS_ARRAY[@]}; i++)); do grp[x++]=$(readlink -f "${ARGS_ARRAY[i]}") + if [[ ! -e "${ARGS_ARRAY[i]}" ]]; then + usage_error "${ARGS_ARRAY[i]} does not exist" + fi done unset x [[ -z ${FILES[@]} ]] && ss_index=0 || ss_index=${#FILES[@]} @@ -2313,7 +2488,7 @@ FILES[ss_index]=$(readlink -f "${ARGS_ARRAY[0]}") GROUP_IN_FILES=( "${GROUP_IN_FILES[@]}" "${grp[@]}" ) groupkey=${#FILES[@]} - GROUP[groupkey-1]=${#grp[@]} + GROUP_ARR[groupkey-1]=${#grp[@]} ((groupkeys++)) # create symlinks to ease substitution later for c in ${!grp[@]}; do @@ -2360,7 +2535,7 @@ ((${ARGS_ARRAY[0]})) 2>/dev/null || usage_error "Arguments to \ -group must be preceeded by a positive integer. See 'man tovid'" groupkey=$(( ${ARGS_ARRAY[0]} - 1)) - GROUP[groupkey]=${#grp[@]} + GROUP_ARR[groupkey]=${#grp[@]} # temporary till I finish submenu groups TODO is_vidgroup[groupkey]=1 # create symlinks to ease substitution later @@ -2405,10 +2580,14 @@ "-nomenu" | "-no-menu" ) NOMENU=: ;; + "-encode-only" ) + ENCODE_ONLY=: + NOMENU=: + ;; "-out" ) shift - OUT_PREFIX="$1" - OUT_PREFIX=${OUT_PREFIX%/} + OUT_DIRECTORY="$1" + OUT_DIRECTORY=${OUT_DIRECTORY%/} ;; "-no-ask" | "-noask" ) NOASK=: @@ -2456,17 +2635,17 @@ [[ -n $wsarg ]] && WIDESCREEN=$wsarg || WIDESCREEN="nopanscan" WIDE_SCREEN=: ;; - "-showcase-safe-area" ) + "-safe-area" | "-showcase-safe-area" ) ADV_OPT=( "${ADV_OPT[@]}" "$1" ) shift SAFE_AREA="$1" - let SAFE_OFFSET="86-SAFE_AREA" USER_SAFE_AREA=: ;; "-align" ) ADV_OPT=( "${ADV_OPT[@]}" "$1" ) shift BUTTON_GRAVITY=$1 + BUTTON_GRAVITY=$(tr A-Z a-z <<< $BUTTON_GRAVITY) # West => west [[ $BUTTON_GRAVITY = "centre" ]] && BUTTON_GRAVITY="center" USER_GRAVITY=: ;; @@ -2756,9 +2935,14 @@ shift get_listargs "$@" arg=${ARGS_ARRAY[0]} + [[ -n $arg && $arg = 0 ]] && usage_error "Using '0' as an arg for -textmenu not allowed - + use -align east (northeast, southeast) for 1 right-aligned column" [[ -n $arg ]] && SPLIT=$arg && USER_SPLIT=: TEXTMENU=: ;; + "-edge-justify") + EDGE_JUSTIFY=: + ;; "-text-start" ) ADV_OPT=( "${ADV_OPT[@]}" "$1" ) shift @@ -2767,9 +2951,10 @@ "-showcase-titles-align" ) shift SC_TITLE_ALIGN="$1" + SC_TITLE_ALIGN=$(tr A-Z a-z <<< $SC_TITLE_ALIGN) # West => west [[ SC_TITLE_ALIGN = "centre" ]] && SC_TITLE_ALIGN="center" ;; - "-title-gap" ) + "-titles-gap" | "-title-gap" ) ADV_OPT=( "${ADV_OPT[@]}" "$1" ) shift SPACER=$1 @@ -2872,6 +3057,7 @@ (( ${SC_BLUR%.*} >= 2 )) && SC_BLUR=2 SC_USER_BLUR=1 ;; + "-menu-title-colour" | "-menu-title-color" | \ "-title-colour" | "-title-color" ) shift TITLE_CLR="$1" @@ -2888,13 +3074,13 @@ shift SM_TITLE_CLR="$1" ;; - "-title-stroke" ) + "-menu-title-stroke" | "-title-stroke" ) shift - TITLE_STROKE="$1" + M_TITLE_STROKE="$1" ;; "-titles-stroke" ) shift - TITLES_STROKE="$1" + V_TITLES_STROKE="$1" ;; "-submenu-stroke" ) shift @@ -2904,7 +3090,7 @@ shift test_is_number $1 && TITLES_OPACITY="$1" ;; - "-title-opacity" ) + "-menu-title-opacity" | "-title-opacity" ) shift test_is_number $1 && TITLE_OPACITY="$1" ;; @@ -2936,12 +3122,24 @@ shift SELECT_CLR="$1" ;; + "-menu-title-font-deco" | "-title-font-deco" | \ + "-menu-title-fontdeco" | "-title-fontdeco") + shift + USE_M_TITLE_DECO=: + M_TITLE_FONT_DECO=($1) + ;; + "-titles-font-deco" | "-titles-fontdeco" ) + shift + USE_V_TITLES_DECO=: + V_TITLES_FONT_DECO=($1) + ;; -thumb-text-col* | "-thumb-font" | "-thumb-fontsize" ) # removed usage_error \ - "The $1 option has been renamed. Now use: -titles-${1##*-}" + "The $1 option now renamed. Try: -titles-${1##*-} or check manual" ;; *-stroke-col* ) # removed - usage_error "The $1 option has been renamed. Now use: ${1%-*}" + usage_error \ + "The $1 option now renamed. Try: ${1%-*} or check manual" ;; "-text-mist" ) MIST=: @@ -3068,11 +3266,11 @@ shift MENU_TITLE="$1" ;; - "-menu-font" ) + "-menu-title-font" | "-title-font" | "-menu-font" ) shift MENU_FONT=$(get_font "$1") ;; - "-menu-fontsize" ) + "-menu-title-fontsize" | "-title-fontsize" | "-menu-fontsize" ) shift MENU_FONTSIZE="$1" ;; @@ -3119,6 +3317,8 @@ shift USER_SC_GEO=: SHOWCASE_GEO=$1 + ! grep -q "+[0-9]*+[0-9]*" <<< $SHOWCASE_GEO && usage_error \ + "-showcase-geo argument must be the position geometry in form +X+Y" ;; "-submenu-audio-seek" ) # not implemented yet shift @@ -3131,6 +3331,7 @@ USER_TITLE_GEO=: shift TITLE_GRAVITY=$1 + # centre => center ... no other direction has re in it :) TITLE_GRAVITY=${TITLE_GRAVITY/re/er} ;; "-menu-title-offset" ) @@ -3272,6 +3473,9 @@ done USER_THUMBS=: ;; + "-from-gui" ) + FROM_GUI=: + ;; "-config" | "-ntscfilm" | "-dvd-vcd" | "-half-dvd" | "-kvcd" | \ "-kvcdx3" | "-kvcdx3a" | "-kdvd" | "-bdvd" | "-704" | "-normalize" | \ "-amplitude" | "-overwrite" | "-panavision" | "-force" | "-fps" | \ @@ -3279,8 +3483,8 @@ "-abitrate" | "-priority" | "-deinterlace" | "-progressive" | \ "-interlaced" | "-interlaced_bf" | "-type" | "-fit" | "-discsize" | \ "-parallel" | "-mkvsub" | "-autosubs" | "-subtitles" | "-update" | \ - "-mplayeropts" | "-audiotrack" | "-downmix" | "-ffmpeg" | "-nofifo" | \ - "-from-gui" | "-noask" | "-slice" | "-async" | "-quiet" | \ + "-mplayeropts" | "-audiotrack" | "-downmix" | "-ffmpeg" | "-avconv" | \ + "-nofifo" | "-from-gui" | "-noask" | "-slice" | "-async" | "-quiet" | \ "-fake" | "-keepfiles" ) # remove this warning for tovid 0.33 TODO if [[ $1 = "-subtitles" ]]; then @@ -3299,6 +3503,12 @@ else TOVID_OPTS+=( "$1" "$(readlink -f "$2")" ) fi + elif [[ $1 == '-mplayeropts' ]]; then + # -mplayeropts can start with a '-' so just get entire string. + # TODO allow using -mplayeropts for each video, use "" for none + # [[ "${2+defined}" && -z $2 ]] ... MPLAYER_OPTS+=("") + TOVID_OPTS+=("$1" "$2") + shift else TOVID_OPTS+=( "$1" ) shift @@ -3319,6 +3529,10 @@ # get script pid so we can kill the parent if doing recursive todisc's TODISC_PIDS="$TODISC_PIDS $$" + ######################################################################## + ### Setup and error checks (Critical 1st, Warnings after log created ### + ######################################################################## + # make sure dvd-slideshow is installed if user passed -use-dvd-slideshow $USE_DVD_SLIDESHOW && assert_dep dvd-slideshow \ "The program dvd-slideshow was not found - you can get it from @@ -3377,27 +3591,6 @@ # for switched menus the 1st menu (MN) made is the 2nd, not the 1st { $SWITCHED_MODE || $SWITCHED_MENUS ; } && MN=2 || MN=1 -if [[ ${#TITLES[@]} -eq 0 ]]; then - if [[ $MENU_NUM = $MN ]] && ! $NOMENU \ - && ! $SINGLE_SLIDESHOW && ! $DO_TITLESETS && $MONTAGE_MENU; then - yecho - yecho "You did not provide any titles with -titles" - yecho "Using the basename of each file provided (minus the extension)." - yecho - ((sshows < 1)) && $WARN && sleep 5 - fi - for i in ${!FILES[@]}; do - TITLE=${FILES[i]##*/} - TITLES[i]=" ${TITLE%%.*} " - done -fi -if ! $TITLESET_MODE && ! $DO_TITLESETS && $QUICK_NAV && ! $VMGM_ONLY; then - QUICK_NAV=false - yecho - yecho "No -quick-nav unless doing titlesets ... disabling this option" - $WARN && sleep 5 - yecho -fi if $DO_TITLESETS && ! $VMGM_MENU && ! $QUICK_NAV; then usage_error \ "You can not use -no-vmgm if doing titlesets unless using -quick-nav" @@ -3417,20 +3610,39 @@ SC_TITLE_ALIGN="west" SHOWCASE=: fi +# usage error on mispellings for *align* options +case $BUTTON_GRAVITY in + north|south|east|west|northwest|northeast|southwest|southeast|center) + : + ;; + *) + usage_error "$BUTTON_GRAVITY is an incorrect argument for '-align'" + ;; +esac +case $SC_TITLE_ALIGN in + west|east|center) + : + ;; + *) + usage_error "$SC_TITLE_ALIGN is an incorrect argument for \ + '-showcase-titles-align'" + ;; +esac if $TEXTMENU; then SHOWCASE=: IMG_FMT="png" - SC_TITLE_ALIGN="west" + # default -align for textmenu is northwest, not north + ! $USER_GRAVITY && BUTTON_GRAVITY="northwest" +elif $SHOWCASE; then + ! $USER_GRAVITY && BUTTON_GRAVITY="northwest" # with thumbs, use defaults fi # incompatible slideshow options with -switched-menus if { $CAROUSEL_IS_BG || $CAROUSEL_IS_SHOWCASE ; } && $SWITCHED_MENUS; then $CAROUSEL_IS_BG && OPT="-background-slideshow" || OPT="-showcase-slideshow" - yecho - yecho "$OPT uses slides from ALL slideshows, so its use with + info_message "$OPT uses slides from ALL slideshows, so its use with \ -switched-menus makes no sense. Removing this option for you." - yecho CAROUSEL_IS_SHOWCASE=false; CAROUSEL_IS_BG=false - $WARN && sleep 10 + $WARN && continue_in 5 fi # slideshows are animated by default like rest of todisc if ((sshows>=1)); then @@ -3443,6 +3655,15 @@ SLIDE_FADE=: fi fi + +# you can not use submenus with slideshows +if ((num_slideshows>0)) && $SUB_MENU; then + usage_error "You can not use submenus with slideshows. If you have + a mixed menu of videos and slideshows, but want submenus for the videos, + you will have to put the videos in a separate titleset instead." +fi + + #if $DO_CAROUSEL && $SHOWCASE && ! { $SWITCHED_MODE || $SWITCHED_MENUS ; } && \ # ! $CAROUSEL_IS_BG && ! $CAROUSEL_IS_SHOWCASE && ((sshows<=1)); then # yecho @@ -3461,10 +3682,10 @@ : ${BASEDIR:="$WORK_DIR"} # Make sure -out was provided and it is valid -if test -n "$OUT_PREFIX"; then - OUT_DIR=$(readlink -f "$OUT_PREFIX") +if test -n "$OUT_DIRECTORY"; then + OUT_DIR=$(readlink -f "$OUT_DIRECTORY") if [[ ! -d ${OUT_DIR%/*} ]]; then - OUT_PATH=$(readlink -m "$OUT_PREFIX") + OUT_PATH=$(readlink -m "$OUT_DIRECTORY") usage_error "The -out path ${OUT_PATH%/*}/ does not exist" fi if egrep -q '<|>|&' <<< "$OUT_DIR"; then @@ -3476,7 +3697,7 @@ Please change the directory you gave as an -out argument." fi else - usage_error "Please provide an output name with -out" + ! $ENCODE_ONLY && usage_error "Please provide an output name with -out" fi ### dvdauthor stuff # for xml, if -intro was used @@ -3517,13 +3738,6 @@ [[ -z $NR_AMT ]] && NR_AMT=200 NR="$NR $NR_AMT" fi -# check for -loop or -loop_input -ffmpeg_help=$(ffmpeg -h 2>&1) -if grep -q -- '^-loop ' <<< "$ffmpeg_help"; then - LOOP="-loop 1" -else - LOOP="-loop_input" -fi # assign values for slides # blurs @@ -3553,139 +3767,267 @@ # allow -thumb-frame-size (otherwise unused for 3D thumbs) to set -raise ((USER_THUMB_FRAME_SIZE)) && RAISE="-raise $THUMB_FRAME_SIZE" +# centre aligned titles under showcase thumbs need extra safe room +if [[ $SC_TITLE_ALIGN = center ]]; then + SAFE_OFFSET=36 + $USER_SAFE_AREA && SAFE_OFFSET=$((86-SAFE_AREA)) +fi # honour -noask for functions and called scripts that use them $NOASK && NO_ASK="-noask" -# Warn if thumb labels have more than 16 characters -if ! $SHOWCASE; then - for ((i=0; i<${#TITLES[@]}; i++)); do - val=${#TITLES[i]} - [ -z "$MAX_CHARS" ] || ((val > MAX_CHARS)) && MAX_CHARS=$val && key=$i - done - if [[ ${#TITLES[@]} -gt 6 \ - && $MAX_CHARS -gt 16 ]] && ! $SINGLE_SLIDESHOW; then - yecho - yecho "WARNING! Some titles are longer than 16 characters; \ - they may be chopped off." - yecho - #echo "\"${TITLES[key]}\" is too long; please use a shorter title." - #exit 1 - fi + +##################################### +# backend checks # +#################################### + +# transcode is needed for making animated submenu, else we can use just ffmpeg +hash transcode 2>/dev/null || use_transcode=false +# todisc should run if mjpegtools not installed, assumes -ffmpeg for 'tovid mpg' +hash yuvcorrect 2>/dev/null || yuv_correct=remove_header +#$ANI_SUB_MENU && assert_dep transcode "transcode is required for making +# animated submenus" +if $use_transcode; then + # transcode version >= 1.1.0 mandated + _transcode_version=$(transcode -v 2>&1| awk '{gsub("v", ""); print $2}') + _baseline_version=1.1.0 + if ! test_version $_transcode_version $_baseline_version; then + test -f "$LOG_FILE" && rm -f "$LOG_FILE" + runtime_error \ + "transcode version 1.1.0 or newer required to run this script (todisc). + If you must use version $_transcode_version use tovid 0.34 or older." + fi + # stock debian transcode and probably others missing export_yuv4mpeg module + if ! ls -1 $( tcmodinfo -p )/export*.so |grep -q yuv4mpeg; then + test -f "$LOG_FILE" && rm -f "$LOG_FILE" + _url="http://tovid.wikia.com/wiki/Known_bugs#tovid_is_broken_on_Debian" + runtime_error \ + "your transcode is missing the yuv4mpeg export module. See $_url" + fi +fi +# ffmpeg - minimum version: 0.7, which has necessary filters +ffmpeg_help=$($FFmpeg -h full 2>&1) +ff_filters=$($FFmpeg -filters 2>/dev/null | awk 'f;/Filters:/{f=1}') +# if no filters present show a runtime error and exit +[[ "$ff_filters" ]] || \ + runtime_error "Your ${FFmpeg##*/} is too old ! No filter support." +# newer ffmpeg's use setdar= and setsar= +if grep -qw setdar <<< "$ff_filters"; then + ASPECT="setdar=4:3" # for menu. Always 4:3 aspect +# somewhat older rev's used aspect= +elif grep -qw ^aspect <<< "$ff_filters"; then + ASPECT="aspect=4:3" fi -# backend checks -# transcode version >= 1.1.0 mandated -_transcode_version=$(transcode -v 2>&1| awk '{gsub("v", ""); print $2}') -_baseline_version=1.1.0 -if ! test_version $_transcode_version $_baseline_version; then - runtime_error \ - "transcode version 1.1.0 or newer is required to run this script (todisc). - If you must use version $_transcode_version use tovid 0.34 or older." +# check for -loop or -loop_input (-loop from 0.9 onwards) +if grep -q -- '^-loop ' <<< "$ffmpeg_help"; then + LOOP="-loop 1" +else + LOOP="-loop_input" fi -# ffmpeg has been buggy with setting AR with -aspect, use -vf aspect if present +# switch form video filters: -vf or -vfilters # "-vf" was "-vfilters" briefly, check -FF_HELP=$(ffmpeg -h 2>&1) -if grep -qw -- -vf <<< "$FF_HELP"; then +if grep -qw -- -vf <<< "$ffmpeg_help"; then VF="-vf" # somewhat older is "-vfilters" -elif grep -qw -- -vfilters <<< "$FF_HELP"; then +elif grep -qw -- -vfilters <<< "$ffmpeg_help"; then VF="-vfilters" +else # this should not run as we would have exited checking for -filters above + runtime_error "Your ffmpeg is too old: missing video filters" fi -# ffmpeg's -vf aspect is more dependable than -aspect, if ffmpeg is new enough -FF_FILTERS=$(ffmpeg -filters 2>&1) -# newer ffmpeg's use setdar= and setsar= -if grep -qw ^setdar <<< "$FF_FILTERS"; then - ASPECT="$VF setdar=4:3" # for menu. Always 4:3 aspect - SS_ASPECT="$VF setdar=4:3" # for slideshows. Always 4:3 aspect -# somewhat older rev's used aspect= -elif grep -qw ^aspect <<< "$FF_FILTERS"; then - ASPECT="$VF aspect=4:3" - SS_ASPECT="$VF aspect=4:3" + +# ffmpeg will not allow setting -pix_fmt before the -i if > 0.8.x +make_dummy +if $FFmpeg -pix_fmt yuv420p -t 0.13 -i "$WORK_DIR/dummy.mpg" \ + -f null -y /dev/null >/dev/null 2>&1; then + PIPE_FORMAT="-pix_fmt yuv420p -f yuv4mpegpipe" else - ASPECT="-aspect 4:3" - SS_ASPECT="-aspect 4:3" + PIPE_FORMAT="-f yuv4mpegpipe" fi - +# -acodec, -vcodec, -b and -ab now use per stream options (-b:v) +if $FFmpeg -i "$WORK_DIR/dummy.mpg" -t 0.13 \ + -b:v 500k -f null -y /dev/null >/dev/null 2>&1; then + VB=-b:v + AB=-b:a + CA=-c:a +else + VB=-b + AB=-ab + CA=-acodec +fi +rm -f "$WORK_DIR/dummy.mpg" + +##################################### +# end backend checks # +##################################### + # set some vars for switched menus so we know where we are $SWITCHED_MODE && SWITCHED_MENUS=false { $SWITCHED_MODE || $SWITCHED_MENUS ; } && SWITCHED=: +# check if user passed a usable thumb or showcase shape +if [[ -n $THUMB_SHAPE ]]; then + if ! check_maskshape $THUMB_SHAPE; then + usage_error "Please supply a usable thumb shape with + -thumb-shape option. You gave \"$THUMB_SHAPE\"" + fi + +fi +# -user-thumbs is only compatible with static thumbs (-static) +if $USER_THUMBS && ! $STATIC; then + if $SWITCHED_MENUS; then + usage_error "If doing switched menus -user-thumbs can only be used + with a static menu (-static)" + else + usage_error "-user-thumbs option is for static buttons only (-static)" + fi +fi + +# check for legal -button-style option +case $BUTTON_STYLE in + line|text|text-rect|rect) + : + ;; + *) + usage_error "\"$BUTTON_STYLE\" is not a -button-style arg" + ;; +esac +# transparent border around text so rect spumux outline can fit +if [[ $BUTTON_STYLE = "text-rect" ]]; then + TEXT_BORDER="-bordercolor Transparent -border 8x8" +fi + +# If output directory already exists, print a message and exit +if test -e "$OUT_DIR"; then + echo "Cleaning up created dirs" + yecho + echo "A file or directory named \"$OUT_DIR\" already exists." + echo "Please use a different -out name, " + echo "or (re)move the existing file or directory." + rm -rf "$REAL_WORK_DIR" + rm -f "$WORK_DIR" + exit 1 +fi +# Remove any existing log file, and print headers, unless recursing +if ! $SWITCHED_MODE && ! $TITLESET_MODE && \ +! $MK_CAROUSEL_MODE && ! $VMGM_ONLY; then + test -f "$LOG_FILE" && rm -f "$LOG_FILE" + echo + # script details for the log file + PATTERN=$(for ((i=1; i<=79; i++)); do echo -n \*; done) + printf "%s\n%s\n%s\n\n\n" "$PATTERN" \ + "todisc from the tovid suite ($TOVID_VERSION) - log for `date`" \ + "$PATTERN" >> "$LOG_FILE" + script_args=( ${0##*/} "${args[@]}" ) + #for i in "${script_args[@]}"; do printf "%s %s\n" "$ME" "$i"; done + # do some locale debugging + printf "\n%s%s\n" "$ME" "You are using the following locale settings:" >> "$LOG_FILE" + locale_env=( $(locale) ) + for v in "${locale_env[@]}"; do printf "%s %s\n" "$ME" "$v"; done >> "$LOG_FILE" + printf "\n\n" >> "$LOG_FILE" +fi +# put command line into log for debugging - changes with recursive todisc calls +_args=( todisc "${args[@]}" ) +for i in "${_args[@]}"; do printf "%s %s\n" "$ME" "$i"; done >> "$LOG_FILE" +print2log "" + ########################################################################## + ########## More setup, and non-critical info + warning messages ########## + ########################################################################## + +# information about -titles option in case user doesn't know +if [[ ${#TITLES[@]} -eq 0 ]]; then + if [[ $MENU_NUM = $MN ]] && ! $NOMENU \ + && ! $SINGLE_SLIDESHOW && ! $DO_TITLESETS && $MONTAGE_MENU; then + info_message "You did not provide any titles with -titles. Using the \ + basename of each file provided (minus the extension)." + ((sshows < 1)) && $WARN && continue_in 5 + fi + for i in ${!FILES[@]}; do + title=${FILES[i]##*/} + TITLES[i]=" ${title%%.*} " + done + unset title +fi +if ! $SINGLE_SLIDESHOW; then + for i in ${!FILES[@]}; do + if [[ ! ${TITLES[i]} && $BUTTON_STYLE != "rect" ]]; then + notitles=1 + fi + done + if ((notitles)); then + $USER_BSTYLE && notit_mess="You can not use \"$BUTTON_STYLE\" button + style with no titles. " || notit_mess="You have no titles. " + info_message "$notit_mess Setting button style to 'rect' style for you" + BUTTON_STYLE=rect + TITLES_CLR=none + V_TITLES_STROKE=none + $WARN && continue_in 5 + fi +fi +if ! $TITLESET_MODE && ! $DO_TITLESETS && $QUICK_NAV && ! $VMGM_ONLY; then + QUICK_NAV=false + info_message "No -quick-nav unless doing titlesets ... disabling this option" + $WARN && continue_in 5 +fi +# Warn if thumb labels have more than 16 characters +if ! $SHOWCASE && ! $ENCODE_ONLY && ! $NOMENU; then + for ((i=0; i<${#TITLES[@]}; i++)); do + val=${#TITLES[i]} + [ -z "$MAX_CHARS" ] || ((val > MAX_CHARS)) && MAX_CHARS=$val && key=$i + done + if [[ ${#TITLES[@]} -gt 6 \ + && $MAX_CHARS -gt 16 ]] && ! $SINGLE_SLIDESHOW; then + info_message "WARNING! Some titles are longer than 16 characters; \ + they may be chopped off." + $WARN && continue_in 5 + #echo "\"${TITLES[key]}\" is too long; please use a shorter title." + #exit 1 + fi +fi # warn about change in -thumb-mist option if $FEATHER && ! $USE_FEATHER_MASK; then - yecho - yecho "Note: feathered thumb shapes no longer have mist background + info_message "Note: feathered thumb shapes no longer have mist background by default. Use -thumb-mist [COLOR] to get the old behavior" - yecho - $WARN && sleep 5 + $WARN && continue_in 5 fi # # sanity checks for button style ( -button-style ) for menu buttons # - # use a suitable button style if ! $SINGLE_SLIDESHOW; then for ((i=0; i<${#FILES[@]}; i++)); do if test $(wc -l <<< "$(echo -e "${TITLES[i]}")") -gt 1; then MULTILINE_TITLE=: - if $FEATHER && [ $THUMB_SHAPE != "normal" ]; then - # multiline titles not suitable for text buttons - BUTTON_STYLE="text-rect" - elif $TEXTMENU; then - [[ $BUTTON_STYLE != "line" ]] && BUTTON_STYLE="text-rect" - else - [[ $BUTTON_STYLE != "text-rect" ]] \ - && ! $USER_BSTYLE && BUTTON_STYLE="rect" - fi fi done + # multiline titles not suitable for text buttons + if $MULTILINE_TITLE && [[ $BUTTON_STYLE = "text" ]]; then + BUTTON_STYLE="line" + info_message "'text' button style not suitable for multi-line + titles, using 'line' style instead" + $WARN && continue_in 3 + fi - # disallow spaces in thumb titles for text button style + # remove multiple spaces in video titles for text button style if [ "$BUTTON_STYLE" = "text" ]; then for ((i=0; i<${#TITLES[@]}; i++)); do T=$(sed 's/^[ \t]*//;s/[ \t]*$//' <<< "${TITLES[i]}") if grep " " <<< "$T" >/dev/null; then - echo "Sorry, a maximum of one consecutive space is allowed + info_message "Sorry, a maximum of one consecutive space is allowed in titles for text buttons. \"${TITLES[i]}\" has more than - one consecutive space in it" |fold -bs - exit 1 + one consecutive space in it. Removing the extra spaces for you." + new_title=$("s/^ *//;s/ *$//;s/ \{1,\}/ /g" <<< "${TITLES[i]}") + TITLES[i]="$new_title" + $WARN && continue_in 5 fi done fi fi if { $TEXTMENU || $QUICK_MENU ; } && [[ $BUTTON_STYLE = "rect" ]]; then - if $MULTILINE_TITLE; then - BUTTON_STYLE="text-rect" - else - BUTTON_STYLE="line" - fi + BUTTON_STYLE="line" if ((MENU_NUM==2)) || { ! $SWITCHED_MODE && ! $SWITCHED_MENUS ; }; then if $USER_BSTYLE; then - yecho - yecho "Using button style '$BUTTON_STYLE' instead of 'rect' + info_message "Using button style '$BUTTON_STYLE' instead of 'rect' for textmenu menu" - yecho - $WARN && sleep 10 - fi - fi -fi -# allow multiline titles in submenu -if [[ -n "$SM_TITLES" ]]; then - for i in ${!SM_TITLES[@]}; do - if [[ $(echo -e "${SM_TITLES[i]}" |wc -l) -gt 1 ]]; then - SM_TITLES[i]="$(echo -e "${SM_TITLES[i]}")" + $WARN && continue_in 3 fi - done -fi -# check if user passed a usable thumb or showcase shape -if [[ -n $THUMB_SHAPE ]]; then - if ! check_maskshape $THUMB_SHAPE; then - usage_error "Please supply a usable thumb shape with - -thumb-shape option. You gave \"$THUMB_SHAPE\"" - fi - -fi -if [[ -n $SHOWCASE_SHAPE ]]; then - if ! check_maskshape $SHOWCASE_SHAPE; then - usage_error "Please supply a usable showcase shape with - -showcase-shape option. You gave \"$SHOWCASE_SHAPE\"" fi fi if [[ -n ${ROTATE_ARRAY[@]} ]]; then @@ -3693,50 +4035,50 @@ if [[ $BUTTON_STYLE = *rect* ]]; then BUTTON_STYLE="line" if $USER_BSTYLE; then - yecho - echo "'*rect' button styles with rotated thumbs don't play well" - echo "with spumux buttons. Setting button style to " - echo "'line'. You may also use 'text' style" - echo "Quit now if you wish to exit and examine your options" - yecho - $WARN && sleep 10 + info_message "'*rect' button styles with rotated thumbs don't + play well with spumux buttons. Setting button style to + 'line'. You may also use 'text' style. + Quit now if you wish to exit and examine your options" + $WARN && continue_in 10 fi fi fi fi -if ! $SINGLE_SLIDESHOW; then - for i in ${!FILES[@]}; do - if [[ ! ${TITLES[i]} && $BUTTON_STYLE != "rect" ]]; then - usage_error "You can not use \"$BUTTON_STYLE\" button style if - you have no titles. Use 'rect' style instead" - fi - done -fi # # end of button-style checks # - -# transparent border around text so rect spumux outline can fit -if [[ $BUTTON_STYLE = "text-rect" ]]; then - TEXT_BORDER="-bordercolor Transparent -border 8x8" +if [[ -n $SHOWCASE_SHAPE ]]; then + # if -wave also (incompatible), disable -showcase-shape and give warning + if [[ -n $WAVE ]]; then + info_message "-showcase-shape incompatible with -wave, \ + disabling -showcase-shape for you" + SHOWCASE_SHAPE="" + $WARN && continue_in 3 + else + ! check_maskshape $SHOWCASE_SHAPE && \ + usage_error "Please supply a usable showcase shape with + -showcase-shape option. You gave \"$SHOWCASE_SHAPE\"" + fi fi -# If output directory already exists, print a message and exit -if test -e "$OUT_DIR"; then - echo "Cleaning up created dirs" - yecho - echo "A file or directory named \"$OUT_DIR\" already exists." - echo "Please use a different -out name, " - echo "or (re)move the existing file or directory." - rm -rf "$REAL_WORK_DIR" - rm -f "$WORK_DIR" - exit 1 +# allow multiline titles in submenu +if [[ -n "$SM_TITLES" ]]; then + for i in ${!SM_TITLES[@]}; do + if [[ $(echo -e "${SM_TITLES[i]}" |wc -l) -gt 1 ]]; then + SM_TITLES[i]="$(echo -e "${SM_TITLES[i]}")" + fi + done fi -# Remove any existing log file unless recursing -if ! $SWITCHED_MODE && ! $TITLESET_MODE && \ -! $MK_CAROUSEL_MODE && ! $VMGM_ONLY; then - test -f "$LOG_FILE" && rm -fv "$LOG_FILE" +# copy symlinks for -group hack +if $GROUPING && $TITLESET_MODE; then + find "$WORK_DIR"/ -name \*group\*.mpg -exec cp -P {} "$BASEDIR" \; fi +# carousel's are made BEFORE switched menus - so don't do them in switched mode +$SWITCHED_MODE && DO_CAROUSEL=false + +# save value of default chapters +! $USER_CHAPTERS && (( ${#CHAPTERS[@]} == 1 )) && default_chapters=${CHAPTERS[0]} + # see if imagemagick supports -vignette for the oval shape if [[ $THUMB_SHAPE == "vignette" || $SHOWCASE_SHAPE == "vignette" ]]; then if ! convert -help 2>&1 | egrep -q -- "-vignette"; then @@ -3744,81 +4086,123 @@ [[ $SHOWCASE_SHAPE == "vignette" ]] && SHOWCASE_SHAPE="oval" ! ((USER_BLUR)) && BLUR=3 ! ((SC_USER_BLUR)) && SC_BLUR=3 - warning_message \ - "INFO: -vignette option not available in your imagemagick version. + info_message \ + "Note: -vignette option not available in your imagemagick version. You should upgrade it. Using 'oval' mask shape instead which is similar. Setting the blur to 3 unless you used '-blur' (thumbs) or '-showcase-blur' (showcase file)" - $WARN && sleep 5 + $WARN && continue_in 5 fi fi # see if advanced options were used and give warning if so if [[ -n "${ADV_OPT[@]}" ]] && ! $SWITCHED_MODE; then - yecho - yecho "***** WARNING *****" + yecho "" + printgreen "*** Note: ***" yecho "You have used the following advanced options:" yecho "${ADV_OPT[@]}" | format_output - yecho "With these options it is possible to create a menu where things \ - overlap or are offscreen, or that has other problems, so please check it \ - with the preview. These are things that todisc tries to avoid normally, \ - so if you have problems, please leave them out." - yecho - $WARN && sleep 15 -fi - -# copy symlinks for -group hack -if $GROUPING && $TITLESET_MODE; then - find "$WORK_DIR"/ -name \*group\*.mpg -exec cp -P {} "$BASEDIR" \; + yecho "With these options it is possible to create a menu where things " + yecho "overlap or are offscreen, or that has other problems, " + yecho "so please check it with the preview." + printgreen "***************" + yecho "" + $WARN && continue_in 7 fi -# carousel's are made BEFORE switched menus - so don't do them in switched mode -$SWITCHED_MODE && DO_CAROUSEL=false - -# save value of default chapters -! $USER_CHAPTERS && (( ${#CHAPTERS[@]} == 1 )) && default_chapters=${CHAPTERS[0]} - -# script details for the log file -PATTERN=$(for ((i=1; i<=79; i++)); do echo -n \*; done) -printf "%s\n%s\n%s\n\n\n" "$PATTERN" \ -"todisc from the tovid suite ($TOVID_VERSION) - log for `date`" \ -"$PATTERN" >> "$LOG_FILE" -# put the command line into the log file to aid debugging -printf "%s\n%s\n" todisc "${args[@]}" | sed "s/ */ /g;s/^ *//" | fold -bs >> "$LOG_FILE" -# do some locale debugging -echo -e "\nYou are using the following locale settings:" >> "$LOG_FILE" -locale >> "$LOG_FILE" 2>&1 -echo >> "$LOG_FILE" # check aspect ratios of infiles so thumbs are in aspect without -aspect passed -if ((inc_files)) && [[ -z "$V_ASPECT" ]]; then - yecho - yecho "Determining aspect ratio of videos" +# this is done before makempg converts non-compliant files so it is really only +# useful to get a preview +if ((inc_files && MENU_NUM == 1)) && [[ ! "$V_ASPECT" ]] \ + && ! $VMGM_ONLY && ! $ENCODE_ONLY; then + yecho "Determining aspect ratio of videos for the preview." + yecho "" + yecho "If SURE of ratios skip this step with '-aspect ASPECT' \ + (but it is best if you always run it first to check)." + #$WARN && continue_in 3 + echo + cur_aspect="" for ((i=0; i<${#FILES[@]}; i++)); do - ! $SINGLE_SLIDESHOW && yecho "Checking aspect ratios: ${FILES[i]}" - stats[i]=$(idvid -terse -fast "${FILES[i]}" 2>/dev/null | - awk -F= '/V_ASPECT_WIDTH=/ {print $2}' 2>/dev/null) - cur_aspect=${stats[i]} - if ((cur_aspect)); then - [[ $cur_aspect = 133 ]] && ASPECT_RATIO=4:3 - [[ $cur_aspect = 177 ]] && ASPECT_RATIO=16:9 - yecho "Aspect ratio of $ASPECT_RATIO found. - Videos in this menu (titleset) will be done using that ratio." - ((cur_aspect==177||cur_aspect==133)) && break + curfile=${FILES[i]} + ! $SINGLE_SLIDESHOW && print2log "Checking aspect ratios: ${FILES[i]##*/}" + # check if image, then check aspect ratio of image if so + check_filetype "$curfile" + if [[ $file_type = 'image' ]]; then + stat=133 + elif [[ $file_type = 'video' ]]; then + stat=$(idvid -terse -fast "${FILES[i]}" 2>/dev/null | + awk -F= '/V_ASPECT_WIDTH=/ {print $2}' 2>/dev/null) + else + usage_error "Sorry could not identify file ${FILES[i]}" + fi + #if [[ $(file -L "$curfile" | awk '{ $1 = ""; print }') =~ image ]]; then + # stat=133 + #elif mencoder -quiet -oac pcm -ovc copy \ + # -frames 0 -o /dev/null "${FILES[i]}" &>/dev/null; then + # it is a video, check aspect ratio + # stat=$(idvid -terse -fast "${FILES[i]}" 2>/dev/null | + # awk -F= '/V_ASPECT_WIDTH=/ {print $2}' 2>/dev/null) + #else + # usage_error "Sorry could not identify file ${FILES[i]}" + #fi + # exit from the loop + # save list of files without reported aspect ratio for a warning + { [[ $stat = 0 ]] || ! test_is_number $stat; } && warn_files[i]=${FILES[i]} + stats[i]=${stat:-0} + # round up to 177 or down to 133 in the same way as makempg does for + # padding, so we know what aspect it will be after conversion + if (( ${stats[i]} > 153 )); then + ar_stats[i]=177 + # exit with usage error if videos are 16:9 and a slideshow is included + if ((sshows >=1)); then + usage_error \ + "Slides are encoded using 4:3 aspect ratio. You can not mix \ + 16:9 videos with a slideshow in the same titleset" + fi else - yecho "No aspect ratio was determined. Videos in ths menu - (titleset) will be done using a ratio of 4:3" + ar_stats[i]=133 fi -done - yecho -fi - -# -user-thumbs is only compatible with static thumbs (-static) -if $USER_THUMBS && ! $STATIC; then - if $SWITCHED_MENUS; then - usage_error "If doing switched menus -user-thumbs can only be used - with a static menu (-static)" - else - usage_error "-user-thumbs option is for static buttons only (-static)" + #if [[ -n $cur_aspect ]] && [[ ${ar_stats[i]} != $cur_aspect ]]; then + # # if we have a value for cur_aspect and it differs from new value + # if [[ ${ar_stats[i]} != $cur_aspect ]]; then + # we may have this already if the value was 0, but no harm done + # warn_files[i]=${FILES[i]} + # fi + #fi + cur_aspect=${ar_stats[i]} + # unset stat so we can test it again + unset stat + done + # count the most frequent occurence in ar_stats of 133 or 177. + # They should all be the same!, but user can still continue if he wants + ws=$(grep 177 <<< "$(printf '%s\n' ${ar_stats[@]})" |wc -l) + lb=$(grep 133 <<< "$(printf '%s\n' ${ar_stats[@]})" |wc -l) + ((ws > lb)) && ar=177 || ar=133 + # set the global var for aspect ratio + { [[ $ar = 177 ]] && ASPECT_RATIO=16:9; } || ASPECT_RATIO=4:3 + + # warn about files that have a differing aspect ratio + for i in ${!ar_stats[@]}; do + if ! grep -q $ar <<< ${ar_stats[i]}; then + warn_files[i]=${FILES[i]} + fi + done + if [[ -n ${warn_files[@]} ]]; then + yecho + printred "*** CRITICAL WARNING ***" + yecho "The following files differ from the $ASPECT_RATIO aspect ratio + we are using, even if they are to be re-encoded by makempg here." + echo + printf "\"%s\"\n" ${warn_files[@]} + echo + yecho "You can not mix different aspect ratios in the same menu. + They need to be put in a separate titleset. You may want to quit + at the preview and re-examine the situation." + printred "*************" + yecho + yecho "Press <ENTER> to continue" + read input fi + print2log "" + print2log "Videos in this titleset will be done using aspect of $ASPECT_RATIO." fi ################################################ @@ -3905,16 +4289,14 @@ # set some vars for the last run of switched menus (non-recursive ) $SWITCHED_MENUS && SHOWCASE_FILE=${FILES[0]} -yecho -yecho "Creating work directories" -yecho +print2log "Creating work directories" # create an array of grouped files. if $GROUPING; then unset grp for ((i=1; i<=${#FILES[@]}; i++)); do - if [[ -n ${GROUP[i-1]} ]]; then - for ((j=1; j<=${GROUP[i-1]}; j++)); do + if [[ -n ${GROUP_ARR[i-1]} ]]; then + for ((j=1; j<=${GROUP_ARR[i-1]}; j++)); do if [[ -e $WORK_DIR/${TSET_NUM}-group-${i}-${j}.mpg ]]; then grouping[grp++]=$WORK_DIR/${TSET_NUM}-group-${i}-${j}.mpg fi @@ -3923,34 +4305,40 @@ done fi -# if no bg supplied, use template.png so we can add a frame (-quick-menu only) +## if no bg supplied, use template.png so we can add a frame (-quick-menu only) +# near-black background causes ffmpeg's movie/overlay filter to act weirdly +if [[ $BG_CLR = '#101010' || $BG_CLR = black ]] && [[ -z $BACKGROUND ]] && $QUICK_MENU; then + SUB_CLRS+=("$BG_CLR:'#000030' ('black' bg for quick menu is problematic)") + BG_CLR='#000030' + #BG_CLR='#101028' +fi # check that NTSC menu uses safe colours if [[ $TV_STANDARD = "ntsc" ]]; then get_safe_colour $SFRAME_CLR && FRAME_CLR=$SAFE_CLR get_safe_colour $TITLE_CLR && TITLE_CLR=$SAFE_CLR get_safe_colour $SM_TITLE_CLR && SM_TITLE_CLR=$SAFE_CLR - get_safe_colour $TITLE_STROKE && TITLE_STROKE=$SAFE_CLR + get_safe_colour $M_TITLE_STROKE && M_TITLE_STROKE=$SAFE_CLR get_safe_colour $SUBMENU_STROKE && SUBMENU_STROKE=$SAFE_CLR get_safe_colour $CHAPTER_STROKE && CHAPTER_STROKE=$SAFE_CLR get_safe_colour $TITLES_CLR && TITLES_CLR=$SAFE_CLR get_safe_colour $HLIGHT_CLR && HLIGHT_CLR=$SAFE_CLR get_safe_colour $SELECT_CLR && SELECT_CLR=$SAFE_CLR get_safe_colour $BG_CLR && BG_CLR=$SAFE_CLR - get_safe_colour $TITLES_STROKE && TITLES_STROKE=$SAFE_CLR + get_safe_colour $V_TITLES_STROKE && V_TITLES_STROKE=$SAFE_CLR get_safe_colour $SUBMENU_BG_CLR && SUBMENU_BG_CLR=$SAFE_CLR get_safe_colour $THUMB_FRAME_CLR && THUMB_FRAME_CLR=$SAFE_CLR echo if [[ -n ${SUB_CLRS[@]} ]]; then - echo "*** Note: ***" + printgreen "*** Note: ***" echo "Some of the colors you passed in are not NTSC color safe. " echo "The following substitutions were made for you:" for i in ${!SUB_CLRS[@]}; do echo "${SUB_CLRS[i]/:*} ===> ${SUB_CLRS[i]/*:}" done - echo "*************" + printgreen "*************" echo - $WARN && sleep 5 + $WARN && continue_in 5 fi fi @@ -3961,9 +4349,9 @@ # check file type of background file and assign to BG_VIDEO or BG_IMAGE if [[ -n $BACKGROUND ]]; then check_filetype "$BACKGROUND" - if [[ $TYPE = "image" ]]; then + if [[ $file_type = "image" ]]; then BG_PIC="$BACKGROUND" - elif [[ $TYPE = "video" ]]; then + elif [[ $file_type = "video" ]]; then BG_VIDEO="$BACKGROUND" else usage_error "Sorry, can not identify "$BACKGROUND"" @@ -3972,7 +4360,7 @@ if [[ -n ${SM_BACKGROUND[@]} ]]; then for smbg in ${!SM_BACKGROUND[@]}; do check_filetype "${SM_BACKGROUND[smbg]}" - if [[ $TYPE != "image" ]]; then + if [[ $file_type != "image" ]]; then usage_error "-submenu-background takes image files only" fi done @@ -3982,9 +4370,9 @@ if $SHOWCASE; then if [[ -n ${SHOWCASE_FILE[@]} ]]; then check_filetype "${SHOWCASE_FILE[@]}" - if [[ $TYPE = "image" ]]; then + if [[ $file_type = "image" ]]; then SHOWCASE_IMG=${SHOWCASE_FILE[@]} - elif [[ $TYPE = "video" ]]; then + elif [[ $file_type = "video" ]]; then SHOWCASE_VIDEO=${SHOWCASE_FILE[@]} else usage_error "Can not identify showcase file: "${SHOWCASE_FILE[@]}"" @@ -3996,11 +4384,11 @@ fi # find out the aspect ratio of the showcase file if [[ -n $SHOWCASE_VIDEO ]]; then - SC_AR=$(idvid -fast -terse "$SHOWCASE_VIDEO" 2>/dev/null | + SC_AR=$( idvid -fast -terse "$SHOWCASE_VIDEO" 2>> $LOG_FILE | awk -F= '/V_ASPECT_WIDTH/ {print $2}' 2>/dev/null) elif [[ -n $SHOWCASE_IMG && $SHOWCASE_IMG != "dummy" ]]; then SC_AR=$(identify -ping -format %wx%h "$SHOWCASE_IMG") - SC_AR=$(bc_math "${SC_AR/x*} / ${SC_AR/*x}" ) + SC_AR=$( bc_math "(${SC_AR/x*} / ${SC_AR/*x}) * 100" int ) fi # now the showcase image is id'ed, we can find out what kind of quick menu @@ -4016,7 +4404,6 @@ if $QUICK_MENU && ! $QUICKMENU_IS_SHOWCASE && ! $QUICKMENU_IS_BACKGROUND; then if ! $SWITCHED; then yecho - yecho "***** WARNING *****" if { $DO_TITLESETS || $TITLESET_MODE ; }; then yech=yecho else @@ -4038,7 +4425,7 @@ BUTTON_STYLE="rect" SHOWCASE=false fi - $WARN && sleep 10 + $WARN && continue_in 10 fi fi $QUICKMENU_IS_BACKGROUND && SHOWCASE_IMG="" @@ -4047,7 +4434,7 @@ # quick-menu needs TEXTMENU=: , and does its own showcase and bg with ffmpeg TEXTMENU=: SC_THUMB=false - STATIC=: #FIXME + STATIC=: fi if [[ $SC_FRAMESTYLE = "glass" ]] && [[ -z $SHOWCASE_IMG && -z $SHOWCASE_VIDEO ]]; then yecho @@ -4086,8 +4473,9 @@ if ! $VMGM_ONLY; then for i in "${FILES[@]}"; do IN_FILES=("${IN_FILES[@]}" "$(readlink -f "$i")") - (( ${#FILES[@]} < 12 )) && echo "Adding: $i" || spin "Adding: ${i##*/}" + spin "Adding: ${i##*/}" done + echo fi $VMGM_ONLY && V_TOTAL=$(( ${#TITLES[@]} - 1 )) || V_TOTAL=${#IN_FILES[@]} @@ -4096,11 +4484,36 @@ $DO_CAROUSEL && MONTAGE_MENU=false # switch title position when appropriate so it doesn't get covered up -! $USER_TITLE_GEO && [[ $BUTTON_GRAVITY = *south* ]] && TITLE_GRAVITY="north" -if [[ $BUTTON_GRAVITY = *east* || $BUTTON_GRAVITY = *west* ]]; then - ! $USER_GEO && XGEO=45 && YGEO=45 - ! $SHOWCASE && ! $USER_TITLE_GEO && TITLE_GRAVITY=north +! $USER_TITLE_GEO && [[ $BUTTON_GRAVITY = south* ]] && TITLE_GRAVITY="north" +# not sure why YGEO is 45, probably from when -align didn't affect montage +#if [[ $BUTTON_GRAVITY = *east || $BUTTON_GRAVITY = *west ]]; then +if ! $SHOWCASE; then # XGEO/YGEO for montage style only + # montage adds spacing to edge of montage so subtract it. This is a + # HACK, it would have been better to -trim +repage but I don't feel + # like testing each of the myrid combos to make sure it works okay + safe_area=$(( SAFE_AREA - 12 )) + case $BUTTON_GRAVITY in + northeast|southeast|northwest|southwest) + if $USER_GRAVITY; then + XGEO=$safe_area && YGEO=$safe_area + else + XGEO=45 && YGEO=45 + fi + ;; + east|west) + # move to REAL center if -align centers the montage vertically + YGEO=0 && XGEO=$SAFE_AREA + ;; + center) + YGEO=0 && XGEO=0 + ;; + esac +else # for showcase, move Y position to true north or south at safe area edge + : + #[[ $BUTTON_GRAVITY = north* ]] && TEXT_YSTART=$SAFE_AREA + #[[ $BUTTON_GRAVITY = south* ]] && TEXT_YSTART=$(( ${VIDSIZE/*x} - SAFE_AREA)) fi + ! $SHOWCASE && \ [[ $BUTTON_GRAVITY = "center" ]] && ! $USER_TITLE_GEO && TITLE_GRAVITY="north" @@ -4137,10 +4550,22 @@ #CHAPTERS=( ${CHAPTERS%%+*} ) # in case of grouped chapters # allow user to pass HH:MM:SS chapters $USER_CHAPTERS && CHAPT_ARRAY=( ${CHAPTERS[@]} ) +if $USER_CHAPTERS; then + C=( ${CHAPTERS[@]} ) + if ((${#C[@]} == 1)) && ((${#C[@]} != ${#FILES[@]})); then + for i in ${!FILES[@]}; do + CHAPT_ARRAY[i]=${C[0]} + done + else + CHAPT_ARRAY=( ${CHAPTERS[@]} ) + fi +fi + + # if arbitrary grouped chapters passed, make an array of them if $GROUPING && $USER_CHAPTERS; then for i in ${!IN_FILES[@]}; do - if [[ -n ${GROUP[i]} ]]; then + if [[ -n ${GROUP_ARR[i]} ]]; then group_arbitrary_chapters[i]=${grouped_user_chapters[i]//+/ } else group_arbitrary_chapters[i]="" @@ -4223,6 +4648,11 @@ # get normal CHAPTERS VAR,i.e.: 'how many chapters' # Check if 1st is 00:00:00 and all chapters have HH:MM:SS format if $USER_CHAPTERS; then + if [[ ${#FILES[@]} -ne ${#CHAPTERS[@]} ]]; then + usage_error "Please give the same number of chapter point strings as + videos when using HH:MM:SS form chapters. You gave ${#FILES[@]} + videos but only ${#CHAPTERS[@]} chapter point strings." + fi for i in ${!CHAPT_ARRAY[@]}; do unset newchapts [[ ${CHAPTERS[i]} != *:* ]] && usage_error \ @@ -4242,13 +4672,12 @@ for ((i=0; i<${#CHAPTERS[@]}; i++)); do if ((${CHAPTERS[i]} == 0)) && ! ${SLIDESHOW[i]}; then if ! $USER_CHAPTERS; then - [[ -z ${GROUP[i]} ]] && usage_error \ + [[ -z ${GROUP_ARR[i]} ]] && usage_error \ "-chapters 0 is only for grouped videos (each video is a chapter)" - CHAPTERS[i]=$(( ${GROUP[i]} + 1 )) && nochapt[i]=1 + CHAPTERS[i]=$(( ${GROUP_ARR[i]} + 1 )) && nochapt[i]=1 fi fi done -echo # if using chapter titles, they must equal the combined total for all files if [[ -n ${CHAPTER_TITLES[@]} ]]; then @@ -4273,6 +4702,24 @@ fi fi +# allow using todisc for just encoding mpegs, then exiting +if $ENCODE_ONLY; then + check_compliance + if (( ${#FILES_TO_ENCODE[@]} > 1 )); then + for f in "${FILES_TO_ENCODE[@]}"; do + [[ -s "$f" ]] && arr+=("${f}.enc.mpg") + done + #((${#arr[@]} > 0)) && printf "%s\n%s.enc.mpg" \ + if ((${#arr[@]} > 0)); then + printf "\n%s\n" "Here are your encoded files:" + printgreen '-------------' + printf "%s\n" "${arr[@]}" + printgreen '-------------' + fi + fi + cleanup + exit 0 +fi # a quick way to allow user to make a dvd with no menus if $NOMENU; then cd "$WORK_DIR" @@ -4284,7 +4731,7 @@ for i in "${!IN_FILES[@]}"; do ln -s "${IN_FILES[i]}" "$WORK_DIR/$(printf %03d%s%s $i .mpg)" idvid_stats[i]=$(idvid -terse "${IN_FILES[i]}" 2>/dev/null) - # run mencoder to get the length if using arbitrary chapters + # run stream_length to get the length if using arbitrary chapters if $USER_CHAPTERS; then chapter_points[i]=${CHAPT_ARRAY[i]} else @@ -4292,7 +4739,7 @@ : # we don't need file length or chapters if not making chapters else yecho "Getting video lengths" - VID_LEN[i]=$(vid_length "${IN_FILES[i]}" ) + VID_LEN[i]=$(stream_length "${IN_FILES[i]}" ) chapter_points[i]=$(make_chapters ${VID_LEN[i]} ${CHAPTERS[i]} ) fi fi @@ -4318,11 +4765,9 @@ fi nomenu_cmd+=("${IN_FILES[i]}") done - yecho - echo Running: "${nomenu_cmd[@]}" -o "$OUT_DIR" | format_output - yecho - "${nomenu_cmd[@]}" -o "$OUT_DIR" | tee -a "$LOG_FILE" 2>&1 - dvdauthor -o "$OUT_DIR" -T + print2log "Running: ${nomenu_cmd[@]} -o $OUT_DIR" + "${nomenu_cmd[@]}" -o "$OUT_DIR" 2>&1| pipe2log + dvdauthor -o "$OUT_DIR" -T 2>&1 |pipe2log thanks_goodbye $BURN && burn_disc cleanup @@ -4340,14 +4785,14 @@ if $USER_THUMBS && $FRAME_SAFE; then FRAME_SAFE=false echo "-frame-safe and -user-thumbs incompatible, disabling -frame-safe" - sleep 5 + $WARN && continue_in 5 fi -yecho "Creating pics directories..." +print2log "Creating pics directories..." for ((i=0; i<=NUM_FILES; i++)); do mkdir -p "$REAL_WORK_DIR/pics/$i" done -yecho "${#FILES[@]} pics directories created" +print2log "${#FILES[@]} pics directories created" # textmenu is static unless there is an animated background or showcase video if $TEXTMENU && [[ -z $SHOWCASE_VIDEO && -z $BG_VIDEO ]]; then STATIC=:; fi @@ -4380,10 +4825,6 @@ ${#ROTATE_ARRAY[@]} thumb rotate values." fi fi -# if -wave passed, usage error if -showcase-shape also passed -#if [[ -n $WAVE && -n $SHOWCASE_SHAPE ]]; then -# usage_error "You can not use both -wave and a -showcase-shape" -#fi # if Fading menu, and no BG IMAGE OR VIDEO, fade thumbs right in after title if $MENU_FADE; then @@ -4463,7 +4904,6 @@ alength=$(bc_math "4 / $FRAME_RATE") # 0.16 or 0.133 # float < 1 must begin with 0 [[ -n ${alength/*.} && -z ${alength/.*} ]] && alength=0${alength} - echo echo "Verifying that input files are video or image files" verify_infiles infiles if [[ ${#file_is_image[@]} -eq ${#FILES[@]} && $inc_files -gt 0 ]]; then @@ -4474,17 +4914,14 @@ echo echo "Verifying that grouped input files are video or image files" verify_infiles group - echo fi - echo fi -echo # some vars for slide mix # this is only called when todisc running recursively to make ani slideshows # DO_CAROUSEL is set to false when the self recursion is complete # this happens earlier in the script. if $DO_CAROUSEL; then - if [[ -n ${GROUP[@]} ]] && ! $MK_CAROUSEL_MODE; then + if [[ -n ${GROUP_ARR[@]} ]] && ! $MK_CAROUSEL_MODE; then #*slide_grp*.mpg are symlinks to the original images we have kept intact mixgroup=( "$WORK_DIR"/${TSET_NUM}-slide_grp-*.mpg ) for g in ${!mixgroup[@]}; do @@ -4551,7 +4988,6 @@ fi # All files must be images for slide mix. # if all are images, then we are doing a slideshow. -echo if $SINGLE_SLIDESHOW; then # if -static was not passed we have already set DO_CAROUSEL to : # So here we set STATIC to : as ani slideshow has its own code @@ -4577,7 +5013,7 @@ if [[ ${file_is_image[i]} = "yes" ]]; then SHORTFILE=: else - FRAME_CK=$(vid_length "${IN_FILES[i]}" 90) + FRAME_CK=$(stream_length "${IN_FILES[i]}" video 90) [[ $(bc -l <<< "$FRAME_CK < 2") -eq 1 ]] && SHORTFILE=: fi if $SHORTFILE; then @@ -4636,7 +5072,9 @@ # Some user feedback if ! $SINGLE_SLIDESHOW; then - yecho + #yecho "" + yecho "" + printgreen "-------------" if $VMGM_ONLY; then yecho "Disc title: \"$MENU_TITLE\"" else @@ -4658,10 +5096,16 @@ else # echo titles "as is" echo " \"${TITLES[i]}\" (${IN_FILES[i]})" fi + # FIXME move this before the aspect ratio check for IN_FILES if possible if [[ $(echo -e "${TITLES[i]}" |wc -l) -gt 1 ]]; then # if there is a multiline title we need to align to right of thumbs - SC_TITLE_ALIGN=east + $SHOWCASE && ! [[ $SC_TITLE_ALIGN = "east" ]] && \ + align_warning="\"${TITLE[i]}\" is more than one line: \ + - setting '-showcase-titles-align east'" ALIGN_OVERRIDE=: + if [[ ! $SC_TITLE_ALIGN = east ]]; then + WARN_RE_ALIGN_EAST=1 + fi fi done yecho "Current font settings: " @@ -4695,29 +5139,38 @@ if [ ! $STATIC ]; then yecho " -menu-audio-fade $FADE second(s)" fi - yecho + #yecho "" + printgreen "-------------" + yecho "" fi fi + if ((WARN_RE_ALIGN_EAST)); then + #info_message "Multiline titles must be aligned east. \ + #Setting \"-align east\" for you" + info_message "$align_warning" + SC_TITLE_ALIGN=east + $WARN && continue_in 3 + fi fi # TODO: Merge these globals with the ones up top # only the 1st 6 are mergable - keeping them here for debugging this beast :) # 9 /row -NTSC_1333_DVD=(420x280 300x200 192x128 192x128 186x124 186x124 132x88 132x88 \ +NTSC_1333_DVD=(420x280 288x192 192x128 192x128 186x124 186x124 132x88 132x88 \ 132x88 120x80 120x80 120x80 96x64 96x64 96x64 96x64 96x64 96x64 \ 96x64 96x64 84x56 84x56 84x56 84x56 84x56 84x56 84x56 \ 84x56 84x56 84x56 60x40 60x40 60x40 60x40 60x40 60x40 \ 60x40 60x40 60x40 60x40 60x40 60x40 60x40 60x40 60x40 60x40 60x40 60x40 60x40) # *_1777_DVD is for 16:9 videos displayed in proper res on a 4:3 menu -NTSC_1777_DVD=(420x210 300x150 240x120 240x120 186x98 186x98 180x90 180x90 \ +NTSC_1777_DVD=(420x210 288x144 240x120 240x120 186x98 186x98 180x90 180x90 \ 180x90 132x66 132x66 132x66 132x66 132x66 132x66 132x66 100x50 100x50 \ 100x50 100x50 100x50 100x50 100x50 100x50 100x50 88x44 88x44 \ 88x44 88x44 88x44 80x40 80x40 80x40 80x40 80x40 80x40) -PAL_1333_DVD=(420x336 300x240 190x152 190x152 190x152 190x152 130x104 130x104 \ +PAL_1333_DVD=(420x336 280x224 190x152 190x152 190x152 190x152 130x104 130x104 \ 130x104 130x104 130x104 130x104 100x80 100x80 100x80 100x80 100x80 100x80 \ 100x80 100x80 90x72 90x72 90x72 90x72 90x72 90x72 90x72 \ 90x72 90x72 90x72 60x48 60x48 60x48 60x48 60x48 60x48) -PAL_1777_DVD=(420x252 300x180 240x144 240x144 190x114 190x114 190x114 190x114 \ +PAL_1777_DVD=(420x252 280x168 240x144 240x144 190x114 190x114 190x114 190x114 \ 190x114 130x78 130x78 130x78 130x78 130x78 130x78 130x78 100x60 100x60 100x60 100x60 100x60 100x60 100x60 100x60 100x60 90x54 90x54 90x54 90x54 90x54 80x48 80x48 80x48 80x48 80x48 80x48) @@ -4744,35 +5197,72 @@ SC_THUMB_X_ARRAY=( ${SC_THUMB_X_ARRAY[NUM_FILES]} ) SC_THUMB_Y_ARRAY=( ${SC_THUMB_Y_ARRAY[NUM_FILES]} ) SC_TITLES_X_ARRAY=( ${SC_THUMB_X_ARRAY[@]} ) -SC_TITLES_Y_ARRAY=( ${SC_TITLES_Y_ARRAY[NUM_FILES]} ) +SC_TITLES_Y_ARRAY=( ${SC_TITLES_Y_ARRAY[NUM_FILES]} ) # not used by textmenu if $TEXTMENU ; then + # next line useless as it will always be overwritten for large # of titles ! $USER_SPLIT && SPLIT=13 # max text only titles in one column (-textmenu) if [[ $NUM_FILES -gt 12 ]] && ! $USER_SPLIT; then SPLIT=$((V_TOTAL / 2)) - [[ $(( SPLIT * 2)) -ne $V_TOTAL ]] && let SPLIT=SPLIT+1 + (( (SPLIT * 2) != V_TOTAL)) && ((SPLIT++)) fi -#for ((b=0; b<=NUM_FILES; b++)); do -#((b < SPLIT)) && SC_TITLES_X_ARRAY[b]=86||SC_TITLES_X_ARRAY[b]=360 -#done fi -# needed to centre showcase img: col 1 will always be larger value than col 2 + if $SHOWCASE && ! $TEXTMENU; then - ((NUM_FILES < 5)) && SPLIT=$((NUM_FILES+1)) + # TODO? allow user to specify the SPLIT? + ((NUM_FILES < 5)) && SPLIT=$((NUM_FILES+1)) # col 1 always >= col 2 ((NUM_FILES == 5)) && SPLIT=3 ((NUM_FILES >= 6)) && SPLIT=4 ((NUM_FILES >= 8)) && SPLIT=5 + # -align *east or *west disallowed for 2 column showcase thumbs + if ((NUM_FILES >= SPLIT)); then + case $BUTTON_GRAVITY in + *east|*west) + butgrav=$BUTTON_GRAVITY + # northeast or northwest + if [[ $BUTTON_GRAVITY = north* ]]; then + BUTTON_GRAVITY=north && USER_GRAVITY=false + # southeast or southwest + elif [[ $BUTTON_GRAVITY = south* ]]; then + BUTTON_GRAVITY=south && USER_GRAVITY=false + else # east or west + BUTTON_GRAVITY=north + fi + info_message "You can not use \"-align $butgrav\" with 2 \ + column -showcase, only \"north\", \"south\", \"center\". \ + Changing to \"-align ${BUTTON_GRAVITY}\", please check preview." + $WARN && continue_in 10 + ;; + esac + # central alignment disallowed for 1 column showcase + else + if [[ $SHOWCASE_FILE ]]; then + case $BUTTON_GRAVITY in + center|north|south) + [[ $BUTTON_GRAVITY = center ]] && but_grav="" || \ + but_grav=$BUTTON_GRAVITY + info_message "You can not use a central -align option as in \ + 'north', 'center', or 'south' when using a showcase image and \ + a single column of titles. + Setting '-align ${but_grav}west' for you, please check it with the preview." + BUTTON_GRAVITY=${but_grav}west && USER_GRAVITY=false + $WARN && continue_in 5 + ;; + *east) + #BUTTON_GRAVITY="northwest" + bgrav=$BUTTON_GRAVITY + BUTTON_GRAVITY=${BUTTON_GRAVITY/east/west} # could be west/nw/sw + info_message "You can not use -align $bgrav when using a showcase image. \ + Setting -align $BUTTON_GRAVITY" + $WARN && continue_in 3 + esac + fi + fi fi -AUDIO_EXT="ac3" -SAMPLERATE="48000" -MPLEX_FORMAT="8" -FFMPEG_OPTS="-b 7000k -maxrate 8000k -bufsize 224KiB $ASPECT" -SS_FFMOPTS="-b 8000k -maxrate 9000k -bufsize 224KiB $SS_ASPECT" +FFMPEG_OPTS="-b 7000k -maxrate 8000k -bufsize 224KiB" +SS_FFMOPTS="-b 8000k -maxrate 9000k -bufsize 224KiB" SHOWCASE_SIZE=384x256 -BURN_TGT="$OUT_DIR" -BURN_TGT_STR="DVD directory" -BURN_PROG="makedvd" if [ $TV_STANDARD = "ntsc" ]; then if [[ $ASPECT_RATIO = "4:3" ]]; then GEO_ARRAY=("${NTSC_1333_DVD[@]}") @@ -4783,6 +5273,7 @@ fi VIDSIZE="720x480" FRAME_RATE=29.970 + ff_frame_rate="30000/1001" if [[ $SC_AR = 133 ]]; then SHOWCASE_SIZE=384x256 SM_SHOWCASE_SIZE=288x192 @@ -4794,6 +5285,7 @@ VIDSIZE="720x576" TILE_ARRAY=("${TILE_1333[@]}") FRAME_RATE=25 + ff_frame_rate="25/1" if [[ $SC_AR = 133 ]]; then SHOWCASE_SIZE=380x304 SM_SHOWCASE_SIZE=290x232 @@ -4807,6 +5299,8 @@ GEO_ARRAY=("${PAL_1777_DVD[@]}") fi fi +# set a variable for vfilter scaling based on above sizes VFSCALE +VF_SCALE=${VIDSIZE%x*}:${VIDSIZE#*x} if [[ $TV_STANDARD = "ntsc" ]]; then YUV_FR=30000:1001 else @@ -4823,7 +5317,7 @@ yecho yecho "Reducing thumb blur to 2.0 because you are using -showcase" yecho - $WARN && sleep 3 + $WARN && continue_in 3 fi fi if [ $V_TOTAL -lt 3 ]; then @@ -4849,23 +5343,33 @@ SEEK_FRAMES[i]=$(bc_math "${SEEK_VAL[i]} * $FRAME_RATE" int) done -# some choices needed for different title alignments +# some choices needed for different -align -showcase-titles and alignments if $SHOWCASE && ! $TEXTMENU; then - if [ $V_TOTAL -le 5 ]; then - if [[ $SC_TITLE_ALIGN = "east" ]]; then - SHOWCASE_SIZE=$SM_SHOWCASE_SIZE # smaller to allow for titles - fi + JUSTIFY="west" + + if ((V_TOTAL <= 5)); then + # FIXME move this before the aspect ratio check for IN_FILES if possible + # smaller to allow for titles AUTOORDER="rows" # spumux var + [[ $SC_TITLE_ALIGN = "east" ]] && SHOWCASE_SIZE=$SM_SHOWCASE_SIZE + case $BUTTON_GRAVITY in + south|north|center) + SC_TITLE_ALIGN="center" # moves titles to left a bit for room + SHOWCASE_SIZE=$SM_SHOWCASE_SIZE + ;; + esac else SHOWCASE_SIZE=$SM_SHOWCASE_SIZE # smaller showcase thumb because we have 2 rows AUTOORDER="columns" - if $SC_THUMB && \ - [[ "$SC_TITLE_ALIGN" = "east" ]] && [[ -n $SHOWCASE_FILE ]]; then - usage_error "Sorry, there is no room for the showcase thumb " \ - "if you use more than 5 videos with -showcase-titles-align " \ - "east|west (also multiline titles). Either change the problem " \ - "option, remove the showcase image/video, or use -textmenu. Or " \ - "consider using -bgimage or -bgvideo instead of a showcase thumb." + if [[ $SHOWCASE_FILE ]] && \ + [[ "$SC_TITLE_ALIGN" = "east" ]]; then + info_message "Sorry, no room for showcase thumb with 2 columns and \ + \"-showcase-titles-align east\" (or multiline titles). Change the \ + option, remove the showcase image/video, or use -textmenu. Or \ + use -bgimage or -bgvideo instead of a thumb. Changed for you to: \ + \"-showcase-titles-align center\". Continuing on to the preview ..." + SC_TITLE_ALIGN=center + $WARN && continue_in 15 fi fi elif ! $SHOWCASE && ! $TEXTMENU; then @@ -4884,94 +5388,21 @@ fi $SINGLE_SLIDESHOW && ! $MK_CAROUSEL_MODE && CAROUSEL_SIZE=$VIDSIZE -$TEXTMENU && LEFT_MAX=$SPLIT || LEFT_MAX=5 -if [ "$SC_TITLE_ALIGN" = "west" ] || $TEXTMENU; then #FIXME - THUMB_TITLE_ALIGN="west" # for non TEXTMENU menu - for ((i=0; i<=NUM_FILES; i++)); do - if [ $i -lt $LEFT_MAX ]; then - SC_THUMB_X_ARRAY[i]=$(( ${SC_THUMB_X_ARRAY[i]} - \ - SAFE_OFFSET )) - SC_TITLES_X_ARRAY[i]=$(( ${SC_TITLES_X_ARRAY[i]} - \ - SAFE_OFFSET )) - fi - if ! $TEXTMENU && ! [[ $SHOWCASE_FILE ]]; then - if (( ${SC_THUMB_X_ARRAY[i]} > ( ${VIDSIZE/x*} / 2 ) )); then - SC_THUMB_X_ARRAY[i]=$(( ${VIDSIZE/x*} / 2 )) - SC_TITLES_X_ARRAY[i]=$(( ${VIDSIZE/x*} / 2 )) - fi - fi - done -fi -# centre aligned titles are not for textmenu style -if $TEXTMENU && [[ $SC_TITLE_ALIGN = "center" ]]; then - yecho - yecho "Sorry, you can not use center align for textmenu titles" - yecho "Using title alignment of 'west': please check the preview" - yecho - SC_TITLE_ALIGN="west" - $WARN && sleep 10 -fi +# textmenu does not use -showcase-titles-align, unset this to aid block parsing +$TEXTMENU && unset SC_TITLE_ALIGN # -align east uses text-rect if [[ $BUTTON_STYLE = "text-rect" ]] \ && ! [[ $SC_TITLE_ALIGN = "east" ]] && $SHOWCASE && ! $TEXTMENU; then - yecho "***Warning***" - yecho "text-rect buttons need to be aligned east of thumbs: by using:" - yecho " '-showcase-titles-align east'" - yecho "Setting this option for you" - yecho "Ctrl-c now to exit if you wish to reconsider" + info_message "text-rect buttons need to be aligned east of thumbs by using: + '-showcase-titles-align east'. Setting this option for you. + Ctrl-c now to exit if you wish to reconsider" SC_TITLE_ALIGN="east" - yecho - $WARN && sleep 10 -fi -if $SHOWCASE && [ "$SC_TITLE_ALIGN" = "east" ] && ! $TEXTMENU; then - THUMB_TITLE_ALIGN="west" # align titles left to allow longer titles - for ((i=0; i<=NUM_FILES; i++)); do - if [ $i -lt $LEFT_MAX ] && ! $ALIGN_OVERRIDE; then - SC_THUMB_X_ARRAY[i]=$(( ${SC_THUMB_X_ARRAY[i]} - \ - SAFE_OFFSET )) - SC_TITLES_X_ARRAY[i]=$(( ${SC_TITLES_X_ARRAY[i]} - \ - SAFE_OFFSET )) - fi - if [ ${SC_THUMB_X_ARRAY[i]} -gt 360 ]; then - SC_THUMB_X_ARRAY[i]=360 - fi - SC_TITLES_X_ARRAY[i]=$(( ${SC_THUMB_X_ARRAY[i]} + \ - ${THUMB_SIZE/x*} + 5 )) - #SC_TITLES_Y_ARRAY[i]=$(( ${SC_TITLES_Y_ARRAY[i]} + 18 )) - SC_TITLES_Y_ARRAY[i]=${SC_THUMB_Y_ARRAY[i]} # DEBUG:why not originally? - done + $WARN && continue_in 10 fi -if { $USER_GRAVITY && $SHOWCASE && ! $TEXTMENU ; } \ - && [[ $BUTTON_GRAVITY != north ]]; then - SW_CORNER=$(( ${SC_THUMB_Y_ARRAY[SPLIT-1]} + ${THUMB_SIZE/*x} )) - if [[ $BUTTON_GRAVITY = *south* ]]; then - Y_OFFSET=$(( ( ${VIDSIZE/*x} - SAFE_AREA) - SW_CORNER )) - elif [[ $BUTTON_GRAVITY = *st* ]] || [[ $BUTTON_GRAVITY = *center* ]]; then - COL1_HEIGHT=$(( SW_CORNER - ${SC_TITLES_Y_ARRAY[0]} )) - Y_OFFSET=$(( ( ${VIDSIZE/*x} / 2) - (COL1_HEIGHT / 2) )) - Y_OFFSET=$(( Y_OFFSET - ${SC_TITLES_Y_ARRAY[0]} )) - fi - for ((i=0; i<=NUM_FILES; i++)); do - SC_THUMB_Y_ARRAY[i]=$((${SC_THUMB_Y_ARRAY[i]} + Y_OFFSET )) - SC_TITLES_Y_ARRAY[i]=$((${SC_TITLES_Y_ARRAY[i]}+ Y_OFFSET)) - done -fi -# default for showcase style is left justification, for montages: center -$SHOWCASE && JUSTIFY="west" || JUSTIFY="center" -# find out the showcase thumb "-page" array for this arrangement -for ((i=0; i<=NUM_FILES; i++)); do - if $TEXTMENU; then - SCTHUMB_PAGES_ARRAY[i]=+${SC_TITLES_Y_ARRAY[i]}+${SC_TITLES_X_ARRAY[i]} - else - SCTHUMB_PAGES_ARRAY[i]=+${SC_THUMB_X_ARRAY[i]}+${SC_THUMB_Y_ARRAY[i]} - fi -done # Do everything in $WORK_DIR -echo -e "**** NOTE ****\n" -echo "Doing all work in directory $REAL_WORK_DIR" -echo "$WORK_DIR will be a symlink pointing to this directory" -echo -e "\n**************" +yecho "Changing to ${REAL_WORK_DIR} - $WORK_DIR will be the symlink." +yecho "" $WARN && sleep 1 cd "$WORK_DIR" @@ -4988,9 +5419,9 @@ # no 3d thumbs for flare shape if $THUMBS_3D || $SHOWCASE_3D && \ [[ $THUMB_SHAPE == "flare" || $SHOWCASE_SHAPE == "flare" ]]; then - warning_message "There is no 3d thumbs available for the 'flare' shape. " + info_message "There is no 3d thumbs available for the 'flare' shape. " "Disabling this option for you" - $WARN && sleep 3 + $WARN && continue_in 3 fi $FOURxONE && $SHOWCASE && FOURxONE=false && tile_warning @@ -5008,16 +5439,30 @@ THUMB_SIZE=${GEO_ARRAY[6]} fi else - warning_message "Warning: Incorrect number of videos for ${tile_arg}: + info_message "Warning: Incorrect number of videos for ${tile_arg}: this option will be ignored" - $WARN && sleep 3 + $WARN && continue_in 3 fi fi -if ( ($DO_TITLESETS || $TITLESET_MODE) && $VMGM_MENU ) || $PLAYALL; then - if [[ $BUTTON_GRAVITY = "south" ]]; then - BUTTON_GRAVITY="center" - yecho "Changing thumb alignment to 'center' \ - to make room for navigation button" +# south* aligned with nav buttons may be a problem, unless aligned southwest +if { $DO_TITLESETS || $TITLESET_MODE; } && $VMGM_MENU || $PLAYALL; then + bydir=${BUTTON_GRAVITY/south} + if [[ $BUTTON_GRAVITY = south* && $bydir != west ]]; then + if $TEXTMENU; then + # textmenu will cover the nav button if southeast aligned + # (center and southwest should be okay).Move to "east" (higher up). + if [[ $bydir = east ]]; then + BUTTON_GRAVITY=east + info_message "Changing -align option to 'east' to make room \ + for navigation button(s) like playall '>'." + $WARN && continue_in 5 + fi + else + info_message "You are using -align ${BUTTON_GRAVITY}, but need \ + room for navigation buttons like playall '>'. Please \ + check the preview and adjust your commands if necessary." + $WARN && continue_in 7 + fi fi fi @@ -5033,7 +5478,6 @@ fi # easier to have non transparent showcase use the transparent block if $SHOWCASE && ! $TRANSPARENT; then TRANSPARENT=:; fi -AUDIO_OPTS="-ab 224k -ar $SAMPLERATE -acodec $AUDIO_EXT" # spumux and dvdauthor vars TITLES_VID_TAG="<video format=\"$TV_STANDARD\"" $WIDE_SCREEN && TITLES_VID_TAG=" $TITLES_VID_TAG widescreen=\"$WIDESCREEN\"" @@ -5124,7 +5568,7 @@ # FFMPEG_OPTS="-b 7000k -maxrate 8000k -bufsize 224KiB -aspect 4:3" #MENU_N=$(bc_math "$FRAME_RATE * ${MENU_LEN[MENU_NUM-1]}" int) #ffmpeg -f image2 -loop_input -t $MENU_LEN -i "$WORK_DIR/image_stack.png" \ - #-an -r $FRAME_RATE -s $VIDSIZE -tvstd $TV_STANDARD $FFMPEG_OPTS \ + #-an -r $ff_frame_rate -s $VIDSIZE $FFMPEG_OPTS \ #-f mpeg2video -y "$WORK_DIR/intro.m2v" fi # values to use for the blur mask @@ -5158,85 +5602,89 @@ convert "$WORK_DIR/feather_orig.png" -channel RGBA \ -blur 0x60 "$WORK_DIR/feather_mask2.png" fi -if [[ -z "$TITLES_CLR" ]]; then - if $USE_FEATHER_MASK && ! $SHOWCASE && - [[ $THUMB_BG_CLR != "none" && $THUMB_SHAPE != "normal" ]] ; then - TITLES_CLR="#101010" # dark font for misted backgrounds - else - TITLES_CLR="#C6C6C6" - fi -fi +[[ -z "$TITLES_CLR" ]] && TITLES_CLR='#EAEAEA' # set submenu font colours to defaults if not passed in [[ -z $CHAPTER_STROKE ]] && CHAPTER_STROKE="$SUBMENU_STROKE" [[ -z $CHAPTER_CLR ]] && CHAPTER_CLR="$TITLES_CLR" -# Print and execute the thumb-shape mask command if $DO_MENU; then + # make thumb-shape mask - showcase mask made later after its size is set if [[ -n $THUMB_SHAPE ]]; then make_mask $THUMB_SHAPE thumb THUMB_MASK="$MASK" fi - if [[ -n $SHOWCASE_SHAPE ]]; then - MASK="$WORK_DIR/${SHOWCASE_SHAPE}_mask.png" - make_mask $SHOWCASE_SHAPE showcase - convert "$MASK" -resize ${SHOWCASE_SIZE}! "$MASK" - SHOWCASE_MASK="$MASK" - fi - yecho "Creating a menu title image" - echo - if [[ -z $TITLE_STROKE ]]; then - if [[ -z "$BG_PIC" && -z "$BG_VIDEO" ]]; then - TITLE_STROKE=none - else - TITLE_STROKE=gray - fi + + # make a menu title image + print2log "Creating a menu title image" + if $USE_M_TITLE_DECO; then + # using -title-stroke does a plain 'makemenu' style font with no shadow + # but using font outline like makemenu does + M_TITLE_CMD=(convert -size 620x100 xc:none -font "$MENU_FONT" \ + -pointsize $MENU_FONTSIZE -fill "$TITLE_CLR" -gravity center \ + "${M_TITLE_FONT_DECO[@]}" -annotate +0+0 "$MENU_TITLE") + #-stroke none -annotate +0+0 "$MENU_TITLE") + else + # with no -title-stroke passed, make a font shadow for contrast + # but no font outline (it will be a shadow on one side only + M_TITLE_STROKE=${M_TITLE_STROKE:-black} + M_TITLE_CMD=(convert -size 620x300 xc:none -gravity \ + $JUSTIFY -font "$MENU_FONT" -pointsize $MENU_FONTSIZE \ + -fill none -stroke "$M_TITLE_STROKE" -strokewidth 1 \ + -annotate +0+0 "$MENU_TITLE" \ + -fill $TITLE_CLR -stroke none \ + -annotate +1+1 "$MENU_TITLE") fi - [[ -z $TITLES_STROKE ]] && TITLES_STROKE='#010101' - - # make a title image - #! [[ -z ${STR// /} || -z $STR ]] && TRIM_CMD="-trim +repage -blur 0x0.4 " - # allow removal of contrasting 'undercolour' with 'title-stroke none' - # FIXME this is NOT IM syntax and it would be less confusing to adjust it - [[ $TITLE_STROKE = 'none' ]] && undercolour='none' || undercolour='#101010' TRIM_CMD="-trim +repage -blur 0x0.3" - TITLE_CMD=(convert -size 620x100 xc:none -font "$MENU_FONT" -pointsize \ - $MENU_FONTSIZE -fill $undercolour -stroke $undercolour -gravity center \ - -annotate +0+0 "$MENU_TITLE" -fill "$TITLE_CLR" \ - -stroke "$TITLE_STROKE" -strokewidth 1 -annotate +1+1 "$MENU_TITLE") - TITLE_CMD0=(composite -blend 0x${TITLE_OPACITY} null: - -matte) - TITLE_CMD1=(convert - $TRIM_CMD "$WORK_DIR/title_txt.png") + M_TITLE_CMD0=(composite -blend 0x${TITLE_OPACITY} null: - -matte) + M_TITLE_CMD1=(convert - $TRIM_CMD "$WORK_DIR/title_txt.png") if [[ -n $TITLE_OPACITY ]]; then - "${TITLE_CMD[@]}" miff:- | "${TITLE_CMD0[@]}" miff:- | - "${TITLE_CMD1[@]}" >> "$LOG_FILE" 2>&1 + "${M_TITLE_CMD[@]}" miff:- | "${M_TITLE_CMD0[@]}" miff:- | + "${M_TITLE_CMD1[@]}" >> "$LOG_FILE" 2>&1 else - "${TITLE_CMD[@]}" miff:- | "${TITLE_CMD1[@]}" >> "$LOG_FILE" 2>&1 + "${M_TITLE_CMD[@]}" miff:- | "${M_TITLE_CMD1[@]}" >> "$LOG_FILE" 2>&1 fi - - # make thumb titles +fi +# this is really part of same DO_MENU block above, splitting up for readability +if $DO_MENU; then + # make video titles if ! $SINGLE_SLIDESHOW; then for ((i=0; i<=NUM_FILES; i++)); do - spin "Working on video title $((i+1)) " - THUMB_TITLE_CMD=(convert -size 620x300 xc:none -gravity $JUSTIFY \ - -font "$TITLES_FONT" -pointsize $TITLES_FONTSIZE \ - -fill $CONTRAST_CLR -stroke $TITLES_STROKE \ - -annotate +0+0 "${TITLES[i]}" \ - -fill $TITLES_CLR -stroke none \ - -annotate +1+1 "${TITLES[i]}") + print2log "Working on video title $((i+1)) " + if $USE_V_TITLES_DECO; then + # use a font outline makemenu style + V_TITLES_CMD=(convert -size 620x100 xc:none \ + -font "$TITLES_FONT" -pointsize $TITLES_FONTSIZE \ + -fill "$TITLES_CLR" "${V_TITLES_FONT_DECO[@]}" \ + -gravity center -annotate +0+0 "${TITLES[i]}") + # #-stroke none -annotate +0+0 "${TITLES[i]}") + else + # default is to use a font shadow only on one side of font + V_TITLES_STROKE=${V_TITLES_STROKE:-black} + V_TITLES_CMD=(convert -size 620x300 xc:none -gravity $JUSTIFY \ + -font "$TITLES_FONT" -pointsize $TITLES_FONTSIZE \ + -fill none -stroke "$V_TITLES_STROKE" -strokewidth 1 \ + -annotate +0+0 "${TITLES[i]}" \ + -fill $TITLES_CLR -stroke none \ + -annotate +1+1 "${TITLES[i]}") + fi FADE_CMD=(composite -blend 0x${TITLES_OPACITY} null: - -matte) + # only repage and border if not 'text button' if [[ $BUTTON_STYLE = "text" ]]; then TRIM_CMD=(convert - -trim "$WORK_DIR/thumb_title${i}.png") else TRIM_CMD=(convert - -trim +repage $TEXT_BORDER \ "$WORK_DIR/thumb_title${i}.png") fi - # make thumb title, only repage and border if not 'text button' + # make thumb title if [[ -n $TITLES_OPACITY ]]; then - "${THUMB_TITLE_CMD[@]}" miff:- | "${FADE_CMD[@]}" miff:- | + "${V_TITLES_CMD[@]}" miff:- | "${FADE_CMD[@]}" miff:- | "${TRIM_CMD[@]}" else - "${THUMB_TITLE_CMD[@]}" miff:- | "${TRIM_CMD[@]}" + "${V_TITLES_CMD[@]}" miff:- | "${TRIM_CMD[@]}" fi + # save dimensions for later use + TT_DIM[i]=$(get_image_dim "$WORK_DIR/thumb_title${i}.png") # now get offset before repaging, for the spumux button crop later if [[ $BUTTON_STYLE = "text" ]]; then titles_offset[i]=$(identify -format %O \ @@ -5280,137 +5728,381 @@ at your fontsize. Use a smaller font with -titles-fontsize" fi done + yecho "" fi +fi +############################################################################### +############ set showcase/textmenu titles and thumb positions array ########### +############################################################################### - if $SHOWCASE; then - for ((i=0; i<=NUM_FILES; i++)); do - unset ts_dim j - # get widest png in each colum for use later for alignment use +# this is really part of same DO_MENU block above, splitting up for readability +if $DO_MENU && $SHOWCASE; then + # textmenu also uses this block ! + # get widest png in each colum for use later for alignment use + for ((i=0; i<=NUM_FILES; i++)); do + unset ts_dim j + if ((i < SPLIT)); then + # save widest_title x_dim as well as its array index + val=${TT_DIM[i]/x*} + [ -z "$widest_title" ] || ((val > widest_title)) \ + && widest_title=$val && widest_title_index=$i + else + val2=${TT_DIM[i]/x*} + [ -z "$widest_title2" ] || ((val2 > widest_title2)) \ + && widest_title2=$val2 && widest_title2_index=$i + fi + # get just X demension to help determine final title pos below + tt_dim=${TT_DIM[i]/x*} + done + # so we can do math on the var without error + ((widest_title2)) || widest_title2=0 + + ###################################################################### + ############### showcase with thumbs only X dimension ################ + ###################################################################### + + { $TEXTMENU && LEFT_MAX=$SPLIT ; } || LEFT_MAX=5 + # textmenu doesn't use this block at all + # TODO check_space=0 # only check if enough space once if $SHOWCASE_FILE + # some shortened var names for the math in this block + tt_w=${TT_DIM[i]} # title width + tt_w=${tt_w/x*} + t_w=${THUMB_SIZE/x*} # thumb width + safe_w=$SAFE_AREA # safe area width + vsize_w=${VIDSIZE/x*} # video size width (720) + for ((i=0; i<=NUM_FILES; i++)); do + # get array positions for thumbs and titles. The titles_xdelta is + # the amount we subtract later from the thumb position to re-define + # the arrays when the various -align options are taken into account + case $SC_TITLE_ALIGN in + west) + # only need extra room after 2nd column for long titles + ovflow=$(( widest_title2 - t_w )) if ((i < SPLIT)); then - val=${TT_DIM[i]/x*} - [ -z "$WIDEST_TITLE" ] || ((val > WIDEST_TITLE)) \ - && WIDEST_TITLE=$val - else - val2=${TT_DIM[i]/x*} - [ -z "$WIDEST_TITLE2" ] || ((val2 > WIDEST_TITLE2)) \ - && WIDEST_TITLE2=$val2 - fi - # get just X demension to help determine final title pos below - tt_dim=${TT_DIM[i]/x*} + SC_THUMB_X_ARRAY[i]=$((${SC_THUMB_X_ARRAY[i]} - SAFE_OFFSET)) + else + # ovflow=0 is the right edge of thumb, so stop there + ((ovflow < 0)) && ovflow=0 + # titles are aligned west: try to align east side close to edge + SC_THUMB_X_ARRAY[i]=$(( vsize_w - t_w - safe_w - ovflow )) + fi + SC_TITLES_X_ARRAY[i]=${SC_THUMB_X_ARRAY[i]} + titles_xdelta[i]=0 # for using later in -align options + ;; + east) + #if ((i < SPLIT)) && ! $ALIGN_OVERRIDE; then + #SC_THUMB_X_ARRAY[i]=$(( ${SC_THUMB_X_ARRAY[i]} - \ + #SAFE_OFFSET )) + #SC_TITLES_X_ARRAY[i]=$(( ${SC_TITLES_X_ARRAY[i]} - \ + #SAFE_OFFSET )) + #fi + if ((i >= SPLIT)); then + # 2 cols can't -align east/west/center so no ALIGN_OVERRIDE test + SC_THUMB_X_ARRAY[i]=$(( ( vsize_w - safe_w) - \ + $widest_title2 - t_w - 5 )) + # titlesafe warnings disabled for now + #roffset=$(( ${SC_TITLES_X_ARRAY[i]} + 5 + safe_w )) + #if (( roffset + ${TT_DIM[i]/x*} > vsize_w )); then + # titlesafe_error $(( roffset - vsize_w )) + #fi + fi + SC_TITLES_X_ARRAY[i]=$(( ${SC_THUMB_X_ARRAY[i]} + t_w + 5 )) + SC_TITLES_Y_ARRAY[i]=${SC_THUMB_Y_ARRAY[i]} + titles_xdelta[i]=$(( ${SC_THUMB_X_ARRAY[i]} - ${SC_TITLES_X_ARRAY[i]} )) + ;; + center) + # make sure the showcase file is not being covered up + ! [[ $widest_title ]] && widest_title=0 + ! [[ $widest_title2 ]] && widest_title2=0 + #if ((widest_title2)); then + # col2_thumb_x=$widest_title2 + # thumbs_space=$((${THUMB_SIZE/x*} * 2)) + #else + # col2_thumb_x=0 + # thumbs_space=${THUMB_SIZE/x*} + #fi + # need to rewrite, checking only the area on sides of the sc thumb + #if [[ $SHOWCASE_FILE ]]; then #&& ! ((checked_space)); then + # safearea=$((SAFE_AREA * 2)) + # titles_space=$((widest_title + col2_thumb_x)) + # if $(( (VS - safearea - \ + # titles_space - thumbs_space - ShowCaseSize) <= 0)); then + # : # problem: do something #FIXME run this only once + # fi + #fi + #checked_space=1 + # check if "title-safe" (not too close to screen edge or offscreen) + # for showcase with thumbs and center aligned titles only # FIXME? # thumb pos + 1/2 (X dim) of thumbsize - 1/2 (X dim) of title size - if [ "$SC_TITLE_ALIGN" = "center" ]; then - f=$(( ${THUMB_SIZE/x*} / 2 )) - j=$(( (f + ${SC_THUMB_X_ARRAY[i]}) - (tt_dim / 2) )) - k=( ${k[@]} "$j" ) - l=$((j + tt_dim)) - if [ $j -lt 48 ]; then + f=$(( ${THUMB_SIZE/x*} / 2 )) + j=$(( ( ${SC_THUMB_X_ARRAY[i]} + f ) - (${TT_DIM[i]/x*} / 2) )) + if ((widest_title > ${TT_DIM[i]/x*})); then + offset1=$(( (widest_title - ${TT_DIM[i]/x*}) / 2 )) + offset2=$((widest_title2 - ${TT_DIM[i]/x*} / 2 )) + else + offset1=${TT_DIM[i]/x*} + fi + offset_from_safe_edge1=$offset # unused + tt_x=( ${tt_x[@]} "$j" ) + l=$((j + tt_dim)) + # FIXME this test gives wrong result and is unused right now ! + if ((i < SPLIT)); then + if (( j < SAFE_AREA + SAFE_OFFSET )); then off_left=$j - titlesafe_error $off_left - elif [ $l -gt 672 ]; then - off_right=$((720 - l)) - titlesafe_error $off_right + # titlesafe warnings disabled for now + #titlesafe_error $off_left + fi + else + if (( l > vsize_w - SAFE_AREA - SAFE_OFFSET)); then + off_right=$(($vsize_w - l)) + #titlesafe_error $off_right fi fi - done + titles_xdelta[i]=$(( ${SC_THUMB_X_ARRAY[i]} - ${tt_x[i]} )) + ;; + esac + # now that we have the title delta, factor in -align option (E/W/Centre) + td=${titles_xdelta[i]} + case $BUTTON_GRAVITY in + *east) # single column showcase with thumbs only + # if title is wider than thumb + #if ((tt_w > t_w)); then + # SC_TITLES_X_ARRAY[i]=$(( vsize_w - safe_w - tt_w )) + # thumb wider, or they are the same + #else + # SC_TITLES_X_ARRAY[i]=$(( vsize_w - safe_w - t_w )) + #fi + # titles also aligned east of thumb need to Add the (neg) xdelta + #if [[ $SC_TITLE_ALIGN = east ]]; then + # SC_THUMB_X_ARRAY[i]=$(( vsize_w - safe_w - t_w - (widest_title / 2) + td )) + #else + # SC_THUMB_X_ARRAY[i]=$(( vsize_w - safe_w - t_w - (widest_title / 2) )) + #fi + #SC_TITLES_X_ARRAY[i]=$(( ${SC_THUMB_X_ARRAY[i]} - td )) + if [[ $SC_TITLE_ALIGN = east ]]; then + SC_TITLES_X_ARRAY[i]=$(( vsize_w - safe_w - widest_title )) + SC_THUMB_X_ARRAY[i]=$(( ${SC_TITLES_X_ARRAY[i]} - 5 - t_w )) + else + SC_THUMB_X_ARRAY[i]=$(( vsize_w - safe_w - t_w - (widest_title / 2) )) + SC_TITLES_X_ARRAY[i]=$(( ${SC_THUMB_X_ARRAY[i]} - td )) + fi + ;; + *west) # single column showcase with thumbs only + # they are the same, as the west sides are flush (titles_xdelta=0) + SC_THUMB_X_ARRAY[i]=$((SAFE_AREA + SAFE_OFFSET)) + SC_TITLES_X_ARRAY[i]=$((${SC_THUMB_X_ARRAY[i]} - td)) + ;; + north|south|center) # either single or 2 column showcase with thumbs + if ((NUM_FILES >= SPLIT)); then # 2 column showcase (N/S/C only) + #if ((widest_title2 > t_w)); then + # SC_THUMB_X_ARRAY[i]=$((vsize_w - safe_w - t_w + td)) + #fi + SC_TITLES_X_ARRAY[i]=$((${SC_THUMB_X_ARRAY[i]} - td)) + else # single column showcase (all -align opt should work) + SC_THUMB_X_ARRAY[i]=$(( (vsize_w / 2) - (t_w / 2) )) + SC_TITLES_X_ARRAY[i]=$(( ${SC_THUMB_X_ARRAY[i]} - td )) + fi + #if ((tt_w > t_w)); then + # SC_THUMB_X_ARRAY[i]=$(( (vsize_w / 2) - (t_w / 2) )) + # SC_TITLES_X_ARRAY[i]=$(( ${SC_THUMB_X_ARRAY[i]} - td )) + #else + # SC_THUMB_X_ARRAY[i]=$(( (vsize_w / 2) - (t_w / 2) )) + # SC_TITLES_X_ARRAY[i]=$(( ${SC_THUMB_X_ARRAY[i]} - td )) + #fi + #echo thumb: ${SC_THUMB_X_ARRAY[i]} title: ${SC_TITLES_X_ARRAY[i]} + ;; + *) + # default is to use original arrays. Subtract titles_xdelta + SC_TITLES_X_ARRAY[i]=$(( ${SC_THUMB_X_ARRAY[i]} - td )) + ;; + esac + done + ###################################################################### + ############### showcase with thumbs only Y dimension ################ + ###################################################################### + + # bottom edge of last thumb vertically + SW_CORNER=$(( ${SC_THUMB_Y_ARRAY[SPLIT-1]} + ${THUMB_SIZE/*x} )) + # TODO add north) so user can align flush with top safearea edge + # as the default is not 'exactly' north in these terms, but a compromise + # center aligned titles only can use *west -align options + case $BUTTON_GRAVITY in + northwest) + : # no offset + ;; + south*) + Y_OFFSET=$(( ( ${VIDSIZE/*x} - SAFE_AREA) - SW_CORNER )) + ;; + *east|*west|center) + COL1_HEIGHT=$(( SW_CORNER - ${SC_TITLES_Y_ARRAY[0]} )) + Y_OFFSET=$(( ( ${VIDSIZE/*x} / 2) - (COL1_HEIGHT / 2) )) + Y_OFFSET=$(( Y_OFFSET - ${SC_TITLES_Y_ARRAY[0]} )) + ;; + esac + #if [[ $BUTTON_GRAVITY = south* ]]; then + # Y_OFFSET=$(( ( ${VIDSIZE/*x} - SAFE_AREA) - SW_CORNER )) + #elif [[ $BUTTON_GRAVITY = *st* ]] || [[ $BUTTON_GRAVITY = *center* ]]; then + # COL1_HEIGHT=$(( SW_CORNER - ${SC_TITLES_Y_ARRAY[0]} )) + # Y_OFFSET=$(( ( ${VIDSIZE/*x} / 2) - (COL1_HEIGHT / 2) )) + # Y_OFFSET=$(( Y_OFFSET - ${SC_TITLES_Y_ARRAY[0]} )) + #fi + for ((i=0; i<=NUM_FILES; i++)); do + SC_THUMB_Y_ARRAY[i]=$((${SC_THUMB_Y_ARRAY[i]} + Y_OFFSET )) + SC_TITLES_Y_ARRAY[i]=$((${SC_TITLES_Y_ARRAY[i]} + Y_OFFSET)) + done + #fi + # showcase style default: left justification. montages default: center. + # find out the showcase thumb "-page" array for this arrangement + for ((i=0; i<=NUM_FILES; i++)); do if $TEXTMENU; then - # text-rect is OK with a small space between titles for spumux - [[ $BUTTON_STYLE = "text-rect" ]] && \ - SPACER=${SPACER:-"10"} || SPACER=${SPACER:-"15"} - # get an array of title Y positions - offsets1=$(for ((c=0; c<NUM_FILES; c++)); do - ((c < (LEFT_MAX-1))) && echo $((${TT_DIM[c]#*x} + SPACER)); done) - if [[ $NUM_FILES -ge $SPLIT ]]; then - offsets2=$(for ((d=0; d<=NUM_FILES; d++)); do - ((d >= LEFT_MAX)) && echo $((${TT_DIM[d]#*x} + SPACER)); done) - [[ $offsets2 ]] && offsets2="$TEXT_YSTART $offsets2" - tt_ygeos_col2=$(running_total <<< $offsets2) - fi - offsets1="$TEXT_YSTART $offsets1" - tt_ygeos_col1=$(running_total <<< $offsets1) - tt_ygeos="$tt_ygeos_col1 $tt_ygeos_col2" - unset SC_TITLES_Y_ARRAY - SC_TITLES_Y_ARRAY=( $tt_ygeos_col1 $tt_ygeos_col2 ) - # get y position of the last title in 1st column (tt_ygeos_col1) - endtitle_col1=$(wc -w <<< "$tt_ygeos_col1") - endtitle_col1_ygeo=${SC_TITLES_Y_ARRAY[endtitle_col1-1]/*x} - # add y dimension of the last title size to the above y position - SW_YCORNER=$((${TT_DIM[endtitle_col1-1]/*x} + $endtitle_col1_ygeo)) - avail_space1=$(( ( ${VIDSIZE/*x} - SAFE_AREA ) - $SW_YCORNER )) - # if there are 2 columns, get same data for column 2 - if [[ -n $tt_ygeos_col2 ]]; then - endtitle_col2=$NUM_FILES - endtitle_col2_ygeo=${SC_TITLES_Y_ARRAY[endtitle_col2]/*x} - endtitle_col2_xgeo=${SC_TITLES_Y_ARRAY[endtitle_col2]/x*} - SE_YCORNER=$((${TT_DIM[endtitle_col2]/*x}+$endtitle_col2_ygeo)) - avail_space2=$(( ( ${VIDSIZE/*x} - SAFE_AREA ) - $SE_YCORNER )) - fi - # available space is lowest value of 2 *space* vars ( if 2 columns) - if [[ -n $tt_ygeos_col2 ]] && ((SE_YCORNER > SW_YCORNER)); then - avail_space=$avail_space2 - else - avail_space=$avail_space1 - fi - # get the height of each column for -align centre - if [[ $BUTTON_GRAVITY = "center" \ - || $BUTTON_GRAVITY = "east" || $BUTTON_GRAVITY = "west" ]]; then - WEST_YSPACE=$(( SW_YCORNER - TEXT_YSTART)) - EAST_YSPACE=$((SE_YCORNER - TEXT_YSTART)) - ((WEST_YSPACE > EAST_YSPACE)) && YSPACE=$WEST_YSPACE \ - || YSPACE=$EAST_YSPACE - CANVAS=$(( ${VIDSIZE/*x} - (SAFE_AREA * 2) )) - NEW_TEXT_YSTART=$(( ((CANVAS - YSPACE) / 2) + SAFE_AREA )) - TEXT_YSTART_OFFSET=$((NEW_TEXT_YSTART - TEXT_YSTART)) - fi - # add available space to each title position for south alignment - if [[ $BUTTON_GRAVITY = *south* ]] && ((avail_space > 0)); then - for ((d=0; d<=NUM_FILES; d++)); do - SC_TITLES_Y_ARRAY[d]=$(( $avail_space + \ - ${SC_TITLES_Y_ARRAY[d]} )) - done - elif [[ $BUTTON_GRAVITY = "center" \ - || $BUTTON_GRAVITY = "east" || $BUTTON_GRAVITY = "west" ]]; then - for ((d=0; d<=NUM_FILES; d++)); do - SC_TITLES_Y_ARRAY[d]=$(($TEXT_YSTART_OFFSET + \ - ${SC_TITLES_Y_ARRAY[d]} )) - done - fi - # justify titles to the right on the east side of the menu - ((NUM_FILES >= SPLIT-1)) && WIDE_TITLE=$WIDEST_TITLE2 \ - || WIDE_TITLE=$WIDEST_TITLE - for ((d=0; d<=NUM_FILES; d++)); do - ([[ "$BUTTON_GRAVITY" = *east* ]] \ - || [[ -n $tt_ygeos_col2 ]]) && \ - east_offset=$(( ( ${VIDSIZE/x*} - SAFE_AREA ) - \ - ${TT_DIM[d]/x*} )) - if (($NUM_FILES < SPLIT)); then - SC_TITLES_X_ARRAY[d]=$SAFE_AREA - [[ "$BUTTON_GRAVITY" = *east* ]] && \ - SC_TITLES_X_ARRAY[d]=$east_offset - else - if ((d >= LEFT_MAX)); then - SC_TITLES_X_ARRAY[d]=$east_offset - else - SC_TITLES_X_ARRAY[d]=$SAFE_AREA - fi - fi - done - unset MAX_VAL val max_key + SCTHUMB_PAGES_ARRAY[i]=+${SC_TITLES_Y_ARRAY[i]}+${SC_TITLES_X_ARRAY[i]} + else + SCTHUMB_PAGES_ARRAY[i]=+${SC_THUMB_X_ARRAY[i]}+${SC_THUMB_Y_ARRAY[i]} fi - # make SHOWCASE_PAGE arrayS for thumbs and THUMBTITLES_ARRAY for titles - # use preset values unless doing centre align for titles - for ((i=0; i<=NUM_FILES; i++)); do - if [ "$SC_TITLE_ALIGN" != "center" ]; then - SC_TITLES_ARR[i]=+${SC_TITLES_X_ARRAY[i]}+${SC_TITLES_Y_ARRAY[i]} + done +fi + +############################################################################## +################# textmenu only ################# +############################################################################## + +if $DO_MENU && $TEXTMENU; then + ############# textmenu Y dimension ############# + # text-rect is OK with a small space between titles for spumux + [[ $BUTTON_STYLE = "text-rect" ]] && \ + SPACER=${SPACER:-"10"} || SPACER=${SPACER:-"15"} + + # get array of titles Y positions for textmenu + offsets1=$(for ((c=0; c<NUM_FILES; c++)); do + ((c < (LEFT_MAX-1))) && echo $((${TT_DIM[c]#*x} + SPACER)); done) + if ((NUM_FILES >= SPLIT)); then + # to line up rows across, use taller of 2 images for space calc. + if (( ${TT_DIM[c-SPLIT]#*x} > ${TT_DIM[c]#*x} )); then + tt_yspace=${TT_DIM[c-SPLIT]#*x} + else + tt_yspace=${TT_DIM[c]#*x} + fi + offsets1=$(for ((c=0; c<NUM_FILES; c++)); do + ((c < (LEFT_MAX-1))) && echo $((tt_yspace + SPACER)); done) + offsets2=$(for ((d=0; d<=NUM_FILES; d++)); do + ((d >= LEFT_MAX)) && echo $((tt_yspace + SPACER)); done) + [[ $offsets2 ]] && offsets2="$TEXT_YSTART $offsets2" + tt_ygeos_col2=$(running_total <<< $offsets2) + fi + offsets1="$TEXT_YSTART $offsets1" + tt_ygeos_col1=$(running_total <<< $offsets1) + tt_ygeos="$tt_ygeos_col1 $tt_ygeos_col2" + unset SC_TITLES_Y_ARRAY + SC_TITLES_Y_ARRAY=( $tt_ygeos_col1 $tt_ygeos_col2 ) + # get y position of the last title in 1st column (tt_ygeos_col1) + endtitle_col1=$(wc -w <<< "$tt_ygeos_col1") + endtitle_col1_ygeo=${SC_TITLES_Y_ARRAY[endtitle_col1-1]/*x} + # add y dimension of the last title size to the above y position + SW_YCORNER=$((${TT_DIM[endtitle_col1-1]/*x} + $endtitle_col1_ygeo)) + avail_space1=$(( ( ${VIDSIZE/*x} - SAFE_AREA ) - $SW_YCORNER )) + # if there are 2 columns, get same data for column 2 + if [[ -n $tt_ygeos_col2 ]]; then + endtitle_col2=$NUM_FILES + endtitle_col2_ygeo=${SC_TITLES_Y_ARRAY[endtitle_col2]/*x} + endtitle_col2_xgeo=${SC_TITLES_Y_ARRAY[endtitle_col2]/x*} + SE_YCORNER=$((${TT_DIM[endtitle_col2]/*x}+$endtitle_col2_ygeo)) + avail_space2=$(( ( ${VIDSIZE/*x} - SAFE_AREA ) - SE_YCORNER )) + fi + # available space is lowest value of 2 *space* vars ( if 2 columns) + if [[ -n $tt_ygeos_col2 ]] && ((SE_YCORNER > SW_YCORNER)); then + avail_space=$avail_space2 + end_title_pos=$SE_YCORNER + else + avail_space=$avail_space1 + end_title_pos=$SW_YCORNER + fi + # get the height of each column for -align centre + if [[ $BUTTON_GRAVITY = "center" \ + || $BUTTON_GRAVITY = "east" || $BUTTON_GRAVITY = "west" ]]; then + WEST_YSPACE=$(( SW_YCORNER - TEXT_YSTART)) + EAST_YSPACE=$((SE_YCORNER - TEXT_YSTART)) + ((WEST_YSPACE > EAST_YSPACE)) && YSPACE=$WEST_YSPACE \ + || YSPACE=$EAST_YSPACE + CANVAS_Y=$(( ${VIDSIZE/*x} - (SAFE_AREA * 2) )) + NEW_TEXT_YSTART=$(( ( (CANVAS_Y - YSPACE) / 2) + SAFE_AREA )) + TEXT_YSTART_OFFSET=$((NEW_TEXT_YSTART - TEXT_YSTART)) + fi + # add available space to each title position for south alignment + if [[ $BUTTON_GRAVITY = *south* ]] && ((avail_space > 0)); then + for ((d=0; d<=NUM_FILES; d++)); do + SC_TITLES_Y_ARRAY[d]=$(( $avail_space + \ + ${SC_TITLES_Y_ARRAY[d]} )) + done + elif [[ $BUTTON_GRAVITY = "center" \ + || $BUTTON_GRAVITY = "east" || $BUTTON_GRAVITY = "west" ]]; then + for ((d=0; d<=NUM_FILES; d++)); do + SC_TITLES_Y_ARRAY[d]=$(($TEXT_YSTART_OFFSET + \ + ${SC_TITLES_Y_ARRAY[d]} )) + done + fi +fi + ######################## textmenu X dimension ########################## +# this is really part of block above, split up for readability +if $DO_MENU && $TEXTMENU; then + XSPACE=$(( ${VIDSIZE/x*} - SAFE_AREA )) + # title Xdim location for ONE column on right side (left justified) + ljustify_eoffset=$((XSPACE-widest_title)) + # same as above, but for 2nd column when using TWO title columns + ljustify_eoffset2=$((XSPACE-widest_title2)) + for ((d=0; d<=NUM_FILES; d++)); do + ([[ "$BUTTON_GRAVITY" = *east* ]] \ + || [[ -n $tt_ygeos_col2 ]]) && \ + rjustify_eoffset=$(( XSPACE - ${TT_DIM[d]/x*} )) + if ((d < SPLIT)); then + # default is northwest alignment + SC_TITLES_X_ARRAY[d]=$SAFE_AREA + # for centred align add safe area from both sides + case "$BUTTON_GRAVITY" in + "center" | "north" | "south") + SC_TITLES_X_ARRAY[d]=$((( (XSPACE + SAFE_AREA) / 2) - \ + (${TT_DIM[d]/x*} / 2) )) + ;; + "northeast"|"southeast"|"east") + # allow justifying east column to right instead of left + if $EDGE_JUSTIFY; then + SC_TITLES_X_ARRAY[d]=$rjustify_eoffset + else + SC_TITLES_X_ARRAY[d]=$ljustify_eoffset + fi + ;; + esac + else # could be single column or a 2nd column, aligned east + if ((d >= LEFT_MAX)); then # therefore this is an east column + # allow justifying east column to right instead of left + if $EDGE_JUSTIFY; then + SC_TITLES_X_ARRAY[d]=$rjustify_eoffset + else + SC_TITLES_X_ARRAY[d]=$ljustify_eoffset2 + fi else - SC_TITLES_ARR[i]=+${k[i]}+${SC_TITLES_Y_ARRAY[i]} + SC_TITLES_X_ARRAY[d]=$SAFE_AREA fi - - SHOWCASE_THUMB_PAGES[i]="-page ${SCTHUMB_PAGES_ARRAY[i]}" - THUMBTITLES_ARRAY[i]="-page ${SC_TITLES_ARR[i]}" - done - fi + fi + done + unset MAX_VAL val max_key + # END textmenu block fi +if $SHOWCASE; then + # make -page arrays for thumbs, and for titles + # use values set in the above block for textmenu + # and for showcase with thumbs unless doing centre align for titles + for ((i=0; i<=NUM_FILES; i++)); do + #if [ "$SC_TITLE_ALIGN" != "center" ]; then + SC_TITLES_ARR[i]=+${SC_TITLES_X_ARRAY[i]}+${SC_TITLES_Y_ARRAY[i]} + #else + # SC_TITLES_ARR[i]=+${tt_x[i]}+${SC_TITLES_Y_ARRAY[i]} + #fi + SHOWCASE_THUMB_PAGES[i]="-page ${SCTHUMB_PAGES_ARRAY[i]}" + THUMBTITLES_ARRAY[i]="-page ${SC_TITLES_ARR[i]}" + done + echo +fi # make a button for playall and one for jumping to the vmgm menu, if called for # or make a 'play' button if doing a montage slideshow menu pa_ind=$((NUM_FILES+1)) @@ -5550,17 +6242,23 @@ if $MIST; then mist_dim=$(get_image_dim "$WORK_DIR/white.png" ) mist_xdim=${mist_dim/x*} - mist_xdim_offset=$(( (mist_xdim - TITLE_TEXT_XDIM) / 2 )) - if [[ $TITLE_GRAVITY = *st* ]]; then + mist_xoffset=$(( (mist_xdim - TITLE_TEXT_XDIM) / 2 )) + case $TITLE_GRAVITY in + northeast|southeast|east) title_xoffset=${title_xoffset:-"+50"} - mist_xoffset="$(bc_math "${title_xoffset#*[-+]} \ - - $mist_xdim_offset" int)" + mist_xoffset="$(bc_math "${title_xoffset#*[-+]} - $mist_xoffset" int)" [[ ${mist_xoffset:0:1} != [+-] ]] && mist_xoffset=+${mist_xoffset} - else + ;; + *) title_xoffset=${title_xoffset:-"+0"} mist_xoffset=$title_xoffset - fi + ;; + esac else + # make sure the offset supplied is >= safe_area + if [[ $TITLE_GRAVITY = east || $TITLE_GRAVITY = west ]]; then + ((${title_xoffset#*[-+]} < SAFE_AREA)) && title_xoffset=+${SAFE_AREA} + fi title_xoffset=${title_xoffset:-"+0"} fi ############################################################################### @@ -5575,27 +6273,36 @@ else bg_post_seek="-ss $BG_SEEK" && unset bg_pre_seek fi - FFMPEG_CMD=(ffmpeg $bg_pre_seek -i "$BG_VIDEO" -s $VIDSIZE -vframes 1 \ - -an $bg_post_seek -f image2 -y "$WORK_DIR/pics/template.$IMG_FMT") - echo -e "\nRunning: "${FFMPEG_CMD[@]}"\n" | fold -bs >> "$LOG_FILE" + FFMPEG_CMD=($FFmpeg $bg_pre_seek -i "$BG_VIDEO" $VF scale=$VF_SCALE \ + -an $bg_post_seek -f image2 -vframes 1 -y "$WORK_DIR/pics/template.$IMG_FMT") + #echo -e "\nRunning: "${FFMPEG_CMD[@]}"\n" | fold -bs >> "$LOG_FILE" + print2log "Running ${FFMPEG_CMD[@]}" SED_VAR="frame=" - if ! "${FFMPEG_CMD[@]}" 2>&1 |strings >> "$LOG_FILE";then + "${FFMPEG_CMD[@]}" 2>&1 | pipe2log ${FFmpeg##*/} + if ((${PIPESTATUS[0]} != 0)); then runtime_error "Problem creating images from the video." fi + echo | tee -a "$LOG_FILE" fi -if $SHOWCASE && ($SC_THUMB || $QUICK_MENU); then - if [[ $SC_TITLE_ALIGN = "east" ]] && ! $TEXTMENU; then - TS="+ ${THUMB_SIZE/x*}" - else - TS=0 - fi - if (( (WIDEST_TITLE + SAFE_AREA + TS + \ - ${SHOWCASE_SIZE/x*}) > ( ${VIDSIZE/x*} - SAFE_AREA) )); then +if $SHOWCASE && { $SC_THUMB || $QUICK_MENU ; }; then + #if [[ $SC_TITLE_ALIGN = "east" ]] && ! $TEXTMENU; then + # TS=${THUMB_SIZE/x*} + #else + # TS=0 + #fi + if ((V_TOTAL > SPLIT)); then SHOWCASE_SIZE=$SM_SHOWCASE_SIZE fi if $TEXTMENU && [[ -n $tt_ygeos_col2 ]]; then SHOWCASE_SIZE=$SM_SHOWCASE_SIZE fi + # make mask for showcase shape, now that the showcase size is set + if [[ -n $SHOWCASE_SHAPE ]]; then + MASK="$WORK_DIR/${SHOWCASE_SHAPE}_mask.png" + make_mask $SHOWCASE_SHAPE showcase + convert "$MASK" -resize ${SHOWCASE_SIZE}! "$MASK" + SHOWCASE_MASK="$MASK" + fi if $SHOWCASE_3D && [[ -n $SHOWCASE_SHAPE ]]; then CURVE_VARS="5 3 5 1 1" @@ -5615,7 +6322,8 @@ if $SWITCHED && $USER_THUMBS; then echo "Using supplied image for showcased thumb" else - echo "Getting video images from $SHOWCASE_VIDEO" + ! $QUICK_MENU && \ + yecho "Getting showcase video images from $SHOWCASE_VIDEO" fi if [[ "$SC_FRAMESTYLE" = "glass" ]]; then # some vars for get_framed_pics function @@ -5626,10 +6334,10 @@ FRAME_SIZE=$SHOWCASE_SIZE MPLAYER_SEEK_VAL=$SHOWCASE_SEEK_VAL $SWITCHED && MPLAYER_SEEK_VAL=${SEEK_VAL[MENU_NUM-1]} - echo "Using mplayer to get framed images from the showcase video" + yecho "Using mplayer to get framed images from the showcase video" get_framed_pics "$SHOWCASE_VIDEO" >> "$LOG_FILE" 2>&1 largest_img=$(get_largest 8 30 ) - mv -v "$largest_img" "$OUT" + mv "$largest_img" "$OUT" rm -f "$WORK_DIR"/00000*.png convert "$WORK_DIR/showcase_img.png" \ -background none $ROTATE $WAVE miff:-| @@ -5650,13 +6358,13 @@ convert ${USER_PICS[MENU_NUM-1]} -resize $SHOWCASE_SIZE \ "$WORK_DIR/showcase_img.png" else - FFMPEG_CMD=(ffmpeg $ffm_pre_seek -i "$SHOWCASE_VIDEO" \ - -s $SHOWCASE_SIZE -an $ffm_post_seek -vframes 1 -f image2 -y \ - "$WORK_DIR/showcase_img.png") - echo -e "\nRunning: "${FFMPEG_CMD[@]}"\n" | fold -bs \ - |tee -a "$LOG_FILE" + FFMPEG_CMD=($FFmpeg $ffm_pre_seek -i "$SHOWCASE_VIDEO" \ + $VF scale=${SHOWCASE_SIZE%x*}:${SHOWCASE_SIZE#*x} -an \ + $ffm_post_seek -f image2 -y -vframes 1 "$WORK_DIR/showcase_img.png") + print2log "Running: ${FFMPEG_CMD[@]}" SED_VAR="frame=" - if ! "${FFMPEG_CMD[@]}" 2>&1 | strings >> "$LOG_FILE";then + "${FFMPEG_CMD[@]}" 2>&1 | pipe2log ${FFmpeg##*/} + if ((${PIPESTATUS[0]} != 0)); then runtime_error "Problem creating images from the video." fi fi @@ -5682,6 +6390,7 @@ else SHAPE_CMD=(convert -size $SHOWCASE_SIZE "$SHOWCASE_IMG" \ -resize $SHOWCASE_SIZE! $SHOWCASE_FRAME $SC_RAISE) + print2log "Running ${SHAPE_CMD[@]}" fi "${SHAPE_CMD[@]}" miff:- | "${sc_3d_cmd[@]}" miff:- | @@ -5698,6 +6407,7 @@ # create the preview images if ! $TEXTMENU && ! $SINGLE_SLIDESHOW && $DO_MENU && ! $USER_THUMBS; then + print2log "Getting images from your video(s) for the preview" for ((i=0; i<=NUM_FILES; i++)) ; do # fast seek disabled by default if $FAST_SEEK; then @@ -5711,13 +6421,13 @@ SV=${SEEK_VAL[i]}; CURFILE="${IN_FILES[i]##*/}" spin "[$((i + 1)) of ${#FILES[@]}] Seeking to $SV seconds in $CURFILE" - FFMPEG_CMD=(ffmpeg $fmt $ffm_pre_seek -i "${IN_FILES[i]}" -an \ + FFMPEG_CMD=($FFmpeg $fmt $ffm_pre_seek -i "${IN_FILES[i]}" -an \ $ffm_postseek -f image2 -vframes $V_FRAMES \ - -s $THUMB_SIZE -y $WORK_DIR/pics/$i/%06d.$IMG_FMT) + $VF scale=${THUMB_SIZE%x*}:${THUMB_SIZE#*x} -y $WORK_DIR/pics/$i/%06d.$IMG_FMT) CMD=( "${FFMPEG_CMD[@]}" ) SED_VAR="frame=" ! [[ "$SC_FRAMESTYLE" = "glass" ]] \ - && echo -e "\nRunning: "${CMD[@]}"\n" | fold -bs >> "$LOG_FILE" + && print2log "Running: ${CMD[@]}" # some vars for get_framed_pics function VOUT="png:z=7"; FRAMES=30 FRAME_SIZE=$THUMB_SIZE @@ -5730,14 +6440,14 @@ mv -f $largest_img "$WORK_DIR/pics/$i/$(printf "%06d%s" 0 .$IMG_FMT)" rm -f "$WORK_DIR"/000*[0-9].png elif [ "$SC_FRAMESTYLE" = "none" ]; then - if ! "${FFMPEG_CMD[@]}" 2>&1 |strings >> "$LOG_FILE";then + "${FFMPEG_CMD[@]}" 2>&1 | pipe2log ${FFmpeg##*/} 2>&1 + if ((${PIPESTATUS[0]} != 0)); then runtime_error "Problem creating images from the video." fi # get largest image of 9 if static menu and -frame-safe - if $FRAME_SAFE; then #FIXME $STATIC not necessary, this is a preview! + if $FRAME_SAFE; then largest_img=$(get_largest 6 $V_FRAMES "$WORK_DIR/pics/$i") - echo Using $largest_img for menu >2& mv -f "$largest_img" "$WORK_DIR/pics/largest.$IMG_FMT" rm -f "$WORK_DIR"/pics/$i/*.$IMG_FMT mv "$WORK_DIR/pics/largest.$IMG_FMT" \ @@ -5746,21 +6456,21 @@ fi wait - unset NAVSEEK_CMD rectangle run_transcode FFMPEG_CMD TRANSCODE_CMD + unset NAVSEEK_CMD rectangle FFMPEG_CMD TRANSCODE_CMD done echo fi # for user supplied thumbs, resize and copy to appropriate directories -if ! $SWITCHED; then +if ! $SWITCHED && $USER_THUMBS; then for i in ${!USER_PICS[@]}; do convert "${USER_PICS[i]}" -resize $THUMB_SIZE \ "$WORK_DIR/pics/$i/000001.$IMG_FMT" done fi -# overlay menu title and thumb titles on template +# overlay menu title and video titles on template if $MIST; then # overlay white.png onto background - echo "Overlaying the text mist on the background" + print2log "Overlaying the text mist on the background" composite -dissolve $MIST_OPACITY -gravity $TITLE_GRAVITY \ -geometry ${mist_xoffset}${mist_yoffset} \ "$WORK_DIR/white.png" "$WORK_DIR/pics/template.png" \ @@ -5771,10 +6481,10 @@ sc_thumb_title_cmd=( "${sc_thumb_title_cmd[@]}" \ "${THUMBTITLES_ARRAY[i]}" "$WORK_DIR/thumb_title${i}.png") done - echo "Running: - convert -size $VIDSIZE -background none "$WORK_DIR/pics/template.png" - ${sc_thumb_title_cmd[@]} -page +210+400 "$WORK_DIR/title_txt.png" \ - -mosaic "$WORK_DIR/pics/template.png" "| format_output >> "$LOG_FILE" + print2log "Running \ + convert -size $VIDSIZE -background none $WORK_DIR/pics/template.png \ + ${sc_thumb_title_cmd[@]} -page +210+400 $WORK_DIR/title_txt.png \ + -mosaic $WORK_DIR/pics/template.png" convert -size $VIDSIZE -background none "$WORK_DIR/pics/template.png" \ ${sc_thumb_title_cmd[@]} -mosaic "$WORK_DIR/pics/template.png" convert "$WORK_DIR/pics/template.png" "$WORK_DIR/title_txt.png" \ @@ -5790,7 +6500,7 @@ # copy the preview for -quick-menu if $QUICK_MENU && [[ -s "$WORK_DIR/showcase_img.png" ]]; then - cp -v "$WORK_DIR/pics/template.png" "$WORK_DIR/quick_menu_bg.png" + cp "$WORK_DIR/pics/template.png" "$WORK_DIR/quick_menu_bg.png" fi # lets be sure of order by using a loop @@ -5887,8 +6597,7 @@ ############################################################################## if $DO_BUTTONS; then - echo - echo "Creating the highlight and selection PNGs for the main menu" + print2log "Creating the highlight and selection PNGs for the main menu" if [ "$BUTTON_STYLE" = "rect" ]; then MENU_BUTTON_SIZE=$THUMB_SIZE get_button_geo @@ -6152,7 +6861,7 @@ # make sure coordinates are even ((X0%2 && X0--)); ((Y0%2 && Y0--)) ((X1%2 && X1++)); ((Y1%2 && Y1++)) - button_geos=(x0=\"$X0\" y0=\"$Y0\" x1=\"$X1\" y1=\"$Y1\") #FIXME + button_geos=(x0=\"$X0\" y0=\"$Y0\" x1=\"$X1\" y1=\"$Y1\") btn_geos[i]=${button_geos[@]} unset button_geos echo \ @@ -6277,7 +6986,6 @@ echo text ${i},20 \'$i\' done >> "$WORK_DIR/grid2.mvg" fi - if $SHOWCASE && $DO_MENU; then if $SC_THUMB; then # find out where to put the showcase image/video in the X axis @@ -6287,40 +6995,65 @@ fi $QUICK_MENU && \ sc_width=${SHOWCASE_SIZE/x*} && sc_height=${SHOWCASE_SIZE/*x} - if $SC_THUMB || $QUICK_MENU; then #&& ! $TEXTMENU; then + if $SC_THUMB || $QUICK_MENU; then if [[ "$SC_TITLE_ALIGN" = "center" ]]; then - if [[ $WIDEST_TITLE -ge ${THUMB_SIZE/x*} ]]; then - BUTTON_COLUMN1=$(((${THUMB_SIZE/x*} / 2) + (WIDEST_TITLE / 2))) + if [[ $widest_title -ge ${THUMB_SIZE/x*} ]]; then + BUTTON_COLUMN1=$(((${THUMB_SIZE/x*} / 2) + (widest_title / 2))) else BUTTON_COLUMN1=${THUMB_SIZE/x*} fi elif [[ "$SC_TITLE_ALIGN" = "west" ]]; then - if [[ $WIDEST_TITLE -ge ${THUMB_SIZE/x*} ]]; then - BUTTON_COLUMN1=$((WIDEST_TITLE + 5)) + if [[ $widest_title -ge ${THUMB_SIZE/x*} ]]; then + BUTTON_COLUMN1=$((widest_title + 5)) else BUTTON_COLUMN1=${THUMB_SIZE/x*} fi elif [[ "$SC_TITLE_ALIGN" = "east" ]]; then - BUTTON_COLUMN1=$(( ${THUMB_SIZE/x*} + WIDEST_TITLE )) + BUTTON_COLUMN1=$(( ${THUMB_SIZE/x*} + widest_title )) fi - if ! $TEXTMENU; then - sc_space=$((${VIDSIZE%x*} - \ - ${SC_THUMB_X_ARRAY[0]} - BUTTON_COLUMN1 - SAFE_AREA)) - SC_X=$(( ${SC_THUMB_X_ARRAY[0]} + BUTTON_COLUMN1 \ - + (sc_space / 2) - (sc_width / 2) )) - else - BUTTON_COLUMN1=$((WIDEST_TITLE + 5)) + # work out the general position of the showcase image + # these will be modified later according to -align options + # TODO it's already consolidated, now split in 1 vs 2 column if/else + if $TEXTMENU; then + # this is the default, *west aligned, for one column textmenu + BUTTON_COLUMN1=$((widest_title + 5)) sc_space=$((${VIDSIZE%x*} - \ ${SC_TITLES_X_ARRAY[0]} - BUTTON_COLUMN1 - SAFE_AREA)) SC_X=$(( ${SC_TITLES_X_ARRAY[0]} + BUTTON_COLUMN1 \ + (sc_space / 2) - (sc_width / 2) )) if [[ $BUTTON_GRAVITY = *east* ]]; then - BUTTON_COLUMN1=$WIDEST_TITLE + BUTTON_COLUMN1=$widest_title sc_space=$((${VIDSIZE%x*} - (SAFE_AREA * 2) - BUTTON_COLUMN1)) SC_X=$((SAFE_AREA + (sc_space / 2) - (sc_width / 2) )) fi + center_showcase_pos=$(( (${VIDSIZE/x*} / 2) - (sc_width / 2) )) + # this next block is *east or *west for 2 columns, and N|S|Center + case $BUTTON_GRAVITY in + *east|*west) + # for 2 columns the showcase thumb will always be centered + [[ -n $tt_ygeos_col2 ]] && SC_X=$center_showcase_pos + ;; + north|south|center) + # for centered 1 column the showcase has no room, so center it + # these -align args have no effect on 2 column titles position + SC_X=$center_showcase_pos + ;; + esac + else + sc_space=$((${VIDSIZE%x*} - \ + ${SC_THUMB_X_ARRAY[0]} - BUTTON_COLUMN1 - SAFE_AREA)) + SC_X=$(( ${SC_THUMB_X_ARRAY[0]} + BUTTON_COLUMN1 \ + + (sc_space / 2) - (sc_width / 2) )) + if ((V_TOTAL > 5)); then + # for 2 columns just center the thumb between edges of columns + inner_edge_col1=$(( ${SC_THUMB_X_ARRAY[0]} + ${THUMB_SIZE/x*} )) + inner_edge_col2=${SC_THUMB_X_ARRAY[SPLIT]} + canvas=$(( (inner_edge_col2 - inner_edge_col1) / 2 )) + canvas=$(( inner_edge_col1 + canvas )) + SC_X=$(( canvas - (sc_width / 2) )) + fi fi - # find out where to put the showcase image in the Y axis + # work out the position of the showcase image in the Y axis if ! $TEXTMENU; then Y1=${SC_THUMB_Y_ARRAY[0]} Y2=${SC_THUMB_Y_ARRAY[NUM_FILES]} @@ -6343,18 +7076,16 @@ fi - ! $TEXTMENU && [[ $V_TOTAL -gt 5 ]] && \ - SC_X=$(( ( ${VIDSIZE/x*} / 2 ) - (sc_width / 2) )) - $TEXTMENU && [[ -n $tt_ygeos_col2 ]] \ - && SC_X=$(( ( ${VIDSIZE/x*} / 2 ) - (sc_width / 2) )) - $USER_SC_GEO && SC_X=${SHOWCASE_GEO/x*} - $USER_SC_GEO && SC_Y=${SHOWCASE_GEO/*x} - # make sure its divisible by 2 for ffmpeg's padding with -quick-menu if $QUICK_MENU; then SC_Y=$(( (SC_Y /2) * 2 )) SC_X=$(( (SC_X / 2) * 2 )) fi + # finally if user passes in a prefered location for showcase, use it + $USER_SC_GEO && SC_X=$(awk -F+ '{print $2}' <<< $SHOWCASE_GEO) + $USER_SC_GEO && SC_Y=$(awk -F+ '{print $3}' <<< $SHOWCASE_GEO) + + # make the -page part of the IM command for the showcase image SC_IMG_PAGE="-page +$SC_X+$SC_Y" SC_IMG_CMD="$SC_IMG_PAGE "$WORK_DIR/showcase_img.png"" fi @@ -6376,15 +7107,15 @@ IM_CMD3=(convert - -background none $WORK_DIR/title_txt.png \ -gravity $TITLE_GRAVITY -geometry \ ${title_xoffset}${title_yoffset} -composite "$PREVIEW_IMG" ) - echo "Running ${IM_CMD0[@]} miff:- | ${IM_CMD1[@]} miff:- | - ${IM_CMD2[@]} miff:- | ${IM_CMD3[@]}" |format_output >> "$LOG_FILE" + print2log "Running ${IM_CMD0[@]} miff:- | ${IM_CMD1[@]} miff:- | \ + ${IM_CMD2[@]} miff:- | ${IM_CMD3[@]}" "${IM_CMD0[@]}" miff:- | "${IM_CMD1[@]}" miff:- | "${IM_CMD2[@]}" miff:- | "${IM_CMD3[@]}" else IM_CMD=(convert -size $VIDSIZE "$WORK_DIR/pics/template.png" \ -background none ${sc_cmd[@]} $SC_IMG_CMD \ -mosaic "$PREVIEW_IMG") - echo "Running ${IM_CMD[@]}" |format_output >> "$LOG_FILE" + print2log "Running ${IM_CMD[@]}" "${IM_CMD[@]}" fi unset sc_cmd IM_CMD05 IM_CMD04 IM_CMD03 IM_CMD4 @@ -6400,8 +7131,7 @@ IM_CMD3=(convert - -background none "$WORK_DIR/title_txt.png" \ -gravity $TITLE_GRAVITY -geometry ${title_xoffset}${title_yoffset} \ -composite "$PREVIEW_IMG") - echo "Running ${IM_CMD1[@]} | ${IM_CMD2[@]} | ${IM_CMD3[@]}" | - format_output >> "$LOG_FILE" + print2log "Running ${IM_CMD1[@]} | ${IM_CMD2[@]} | ${IM_CMD3[@]}" "${IM_CMD1[@]}" | "${IM_CMD2[@]}" | "${IM_CMD3[@]}" else # Not transparent IM_CMD1=(montage ${PICS[@]} $MTG_FRM -tile ${TILE_ARRAY[NUM_FILES]} \ @@ -6411,8 +7141,7 @@ "$WORK_DIR/title_txt.png" -gravity $TITLE_GRAVITY \ -geometry ${title_xoffset}${title_yoffset} -composite - -gravity \ $BUTTON_GRAVITY -geometry +${XGEO}+${YGEO} -composite "$PREVIEW_IMG") - echo "Running ${IM_CMD1[@]} | ${IM_CMD1[@]}" | - format_output >> "$LOG_FILE" + print2log "Running ${IM_CMD1[@]} | ${IM_CMD2[@]}" "${IM_CMD1[@]}" | "${IM_CMD2[@]}" fi fi @@ -6424,7 +7153,7 @@ IM_CMD2=(convert - -background none "$WORK_DIR/title_txt.png" \ -gravity $TITLE_GRAVITY -geometry ${title_xoffset}${title_yoffset} \ -composite "${add_playbtn[@]}" "$PREVIEW_IMG" ) - echo "Running ${IM_CMD1[@]} | ${IM_CMD1[@]}" | format_output >> "$LOG_FILE" + print2log "Running ${IM_CMD1[@]} | ${IM_CMD2[@]}" "${IM_CMD1[@]}" | "${IM_CMD2[@]}" fi # if there is quickmenu bg, cut out transparent hole for showcase image/video @@ -6436,8 +7165,8 @@ # make a similar framed blank to composite onto the background frame_cmd=(convert -size $SHOWCASE_SIZE xc:black \ $SHOWCASE_FRAME "$WORK_DIR/showcase_frame.png") - yecho "Running ${frame_cmd[@]}" | format_output >> "$LOG_FILE" - "${frame_cmd[@]}" >> "$LOG_FILE" + print2log "Running ${frame_cmd[@]}" + "${frame_cmd[@]}" | pipe2log convert # composite the framed blank onto background subtracting the width \ # of the frame (border) when calculating XxY geometry convert "$WORK_DIR/pics/template.png" \ @@ -6471,7 +7200,7 @@ echo "(Press 'q' or ESC in the preview window to close it.)" fi # make the fake montage with highlighted 1st button and display it -if $DO_MENU && ! $SINGLE_SLIDESHOW; then #FIXME ? +if $DO_MENU && ! $SINGLE_SLIDESHOW; then composite -compose Over "$WORK_DIR/fake_montage.png" \ "$PREVIEW_IMG" "$PREVIEW_IMG" fi @@ -6526,7 +7255,7 @@ if [[ -n "$BG_AUDIO" ]]; then yecho "Getting length of bg audio" $SINGLE_SLIDESHOW && end_pos="" || end_pos=${MENU_LEN[MENU_NUM-1]} - BG_AUDIOLENGTH=$(audio_length "$BG_AUDIO") + BG_AUDIOLENGTH=$(stream_length "$BG_AUDIO" audio) # make sure user isn't trying to get a longer menu than the audio allows if [[ $(bc <<< "${MENU_LEN[MENU_NUM-1]} \ @@ -6571,7 +7300,6 @@ # to make sure files get symlinked properly (Hack) if [[ $MENU_NUM = [1-2] || -n ${file_is_image[@]} ]]; then if ! $MK_CAROUSEL_MODE; then - echo check_compliance $GROUPING && check_compliance group fi @@ -6598,7 +7326,6 @@ done fi fi -echo # animated slideshows join the slides and can add audio (-bgaudio) if $DO_CAROUSEL && ! $USE_DVD_SLIDESHOW; then @@ -6611,9 +7338,8 @@ fi done done - IMGENC_CMD=(ffmpeg -f yuv4mpegpipe -r $FRAME_RATE -i - -s $VIDSIZE \ - $SS_FFMOPTS -r $FRAME_RATE -bf 2 -y "$WORK_DIR/slideshow.m2v") - echo + IMGENC_CMD=($FFmpeg -f yuv4mpegpipe -i - $VF scale=${VF_SCALE},${ASPECT} \ + $SS_FFMOPTS -r $ff_frame_rate -bf 2 -y "$WORK_DIR/slideshow.m2v") for p in ${!MIX_IN[@]}; do if [[ "${F2BIN[p]}" = "yes" ]]; then BINNING_CMD=(convert "${MIX_IN[p]}" -depth 8 \ @@ -6650,11 +7376,14 @@ MIX_IN[p]="$WORK_DIR/${p}.ppm" fi done - echo + printf "\n\n" | tee -a "$LOG_FILE" sstime1=$(date +%s) # make a fifo to send raw yuv to, to be encoded by ffmpeg mkfifo "$WORK_DIR/ppm.fifo" - "${IMGENC_CMD[@]}" 2>/dev/null < "$WORK_DIR/ppm.fifo" & + print2log "Running ${IMGENC_CMD[@]}" + "${IMGENC_CMD[@]}" < "$WORK_DIR/ppm.fifo" 2>&1 | \ + pipe2log ${FFmpeg##*/} & + #"${IMGENC_CMD[@]}" 2>/dev/null < "$WORK_DIR/ppm.fifo" & encpids="$encpids $!" #exec 3> "$WORK_DIR/ppm.fifo" @@ -6697,20 +7426,20 @@ fi # encode still frames # need yuvcorrect if for fade style (remove headers) - [[ $EFFECT = "fade" ]] && YUVCORRECT="yuvcorrect -T NO_HEADER" + [[ $EFFECT = "fade" ]] && YUVCORRECT="$yuv_correct" if [[ $EFFECT = "crossfade" ]]; then # encoding 1st slide if ((f==0)); then YUVCORRECT="cat" else # subsequent slides and fades need header removed - YUVCORRECT="yuvcorrect -T NO_HEADER" + YUVCORRECT="$yuv_correct" fi fi spin "Doing stills for slide $((f+1))" >&2 "${TOYUV_STILLS_CMD[@]}" "${MIX_IN[f]}" 2>/dev/null | $YUVCORRECT 2> /dev/null # now we need yuvcorrect for everything - YUVCORRECT="yuvcorrect -T NO_HEADER" + YUVCORRECT="$yuv_correct" # do a transition to the next slide [[ $EFFECT = "fade" ]] && fadetype=fadeout || fadetype="crossfade" spin "Doing $fadetype for slide $((f+1))" >&2 @@ -6753,28 +7482,28 @@ if $MK_CAROUSEL_MODE; then # move the m2v to BASEDIR (basedir of -carousel_menu_mode) echo - mv -v "$WORK_DIR/slideshow.m2v" "$BASEDIR/carousel-${CAROUSEL_NUM}.m2v" + mv "$WORK_DIR/slideshow.m2v" "$BASEDIR/carousel-${CAROUSEL_NUM}.m2v" cleanup exit 0 fi # get length - bgaudio_time=$(vid_length "$WORK_DIR/slideshow.m2v") + bgaudio_time=$(stream_length "$WORK_DIR/slideshow.m2v" m2v) if [[ -n $BG_AUDIO ]]; then # convert background audio to wav - BGAUDIO_CMD=(ffmpeg -i "$BG_AUDIO" -t $bgaudio_time -ar 48000 \ + BGAUDIO_CMD=($FFmpeg -i "$BG_AUDIO" -t $bgaudio_time -ar 48000 \ -acodec pcm_s16le -y $WORK_DIR/slideshow.wav) else # generate silence - BGAUDIO_CMD=(ffmpeg -f s16le -ar 48000 -t $bgaudio_time -i /dev/zero - -ar 48000 -ac 2 -acodec pcm_s16le -y $WORK_DIR/slideshow.wav) + BGAUDIO_CMD=($FFmpeg -f s16le -ar 48000 -i /dev/zero -ar 48000 \ + -ac 2 -t $bgaudio_time -acodec pcm_s16le -y $WORK_DIR/slideshow.wav) fi echo - echo "Encoding audio to wav with: ${BGAUDIO_CMD[@]}" | format_output | - tee -a "$LOG_FILE" + echo "Encoding audio to wav with: ${BGAUDIO_CMD[@]}" | format_output | \ + pipe2log echo - "${BGAUDIO_CMD[@]}" >> "$LOG_FILE" 2>&1 + "${BGAUDIO_CMD[@]}" 2>&1 | pipe2log ${FFmpeg##*/} # fade wav if background audio used and user did not disable fading if [[ -n $BG_AUDIO ]] && $AUDIO_FADE; then sox "$WORK_DIR/slideshow.wav" "$WORK_DIR/slideshow-faded.wav" \ @@ -6784,20 +7513,17 @@ fi # convert the wav to target format - echo echo "Converting wav to $TARGET format" - BGAUDIO_CMD=(ffmpeg -i "$WORK_DIR/slideshow.wav" \ - $AUDIO_OPTS -y "$WORK_DIR/slideshow.ac3") - echo "Runnning ${BGAUDIO_CMD[@]}" | tee -a "$LOG_FILE" - "${BGAUDIO_CMD[@]}" | format_output >> "$LOG_FILE" 2>&1 echo + BGAUDIO_CMD=($FFmpeg -i "$WORK_DIR/slideshow.wav" \ + $AUDIO_OPTS -y "$WORK_DIR/slideshow.ac3") + print2log "Runnning ${BGAUDIO_CMD[@]}" + "${BGAUDIO_CMD[@]}" 2>&1 | pipe2log ${FFmpeg##*/} # multiplex to mpeg-2 ( svcd or dvd ) MPLEX_CMD=(mplex -V -f $MPLEX_FORMAT -o "$WORK_DIR/slideshow.mpg" \ "$WORK_DIR/slideshow.$AUDIO_EXT" "$WORK_DIR/slideshow.m2v") - yecho - echo "Running ${MPLEX_CMD[@]}" |format_output |tee -a "$LOG_FILE" - "${MPLEX_CMD[@]}" |format_output >> "$LOG_FILE" 2>&1 - yecho + print2log "Running ${MPLEX_CMD[@]}" + "${MPLEX_CMD[@]}" 2>&1 | pipe2log mplex if [[ -s "$WORK_DIR/slideshow.mpg" ]]; then mv "$WORK_DIR/slideshow.mpg" "$WORK_DIR/intro.mpg" else @@ -6817,7 +7543,7 @@ "${SS_AUDIO[@]}" -f "$WORK_DIR/dvd-slideshow.conf" mv "$WORK_DIR/slideshow.vob" "$WORK_DIR/intro.mpg" fi -# check bgvideo and showcase VIDEO for compliance ( if present ) #FIXME +# check bgvideo and showcase VIDEO for compliance ( if present ) if [[ -n $BG_VIDEO && $BG_VIDEO = $BG_AUDIO ]]; then # do not reencode animated slideshow made in MK_CAROUSEL_MODE if ! [[ $BG_VIDEO = $WORK_DIR/carousel-00.m2v ]]; then @@ -6840,7 +7566,7 @@ # symlink IN_FILES in $WORK_DIR to solve some quoting issues for dvdauthor if [[ $MENU_NUM -eq 1 ]]; then - yecho "Symlinking files to $WORK_DIR" + print2log "Symlinking files to $WORK_DIR" for i in ${!IN_FILES[@]}; do if ! [[ -e $BASEDIR/${TSET_NUM}-$((i+1)).mpg ]]; then (cd "$REAL_WORK_DIR" && ln -sf "${IN_FILES[i]}" \ @@ -6851,8 +7577,9 @@ $SINGLE_SLIDESHOW && echo "Getting stats on the slides now" for ((i=0; i<${#IN_FILES[@]}; i++)); do if [[ $MENU_NUM -eq 1 ]]; then - ! $SINGLE_SLIDESHOW && spin "Getting stats on ${IN_FILES[i]}" - idvid_stats[i]=$(idvid -terse -accurate "${IN_FILES[i]}" 2>/dev/null) + ! $SINGLE_SLIDESHOW && \ + spin "getting stats for the log" $SPINNER #on ${IN_FILES[i]##*/}" + idvid_stats[i]=$(idvid -terse -accurate "${IN_FILES[i]}" 2> /dev/null) fi if [ -s "${IN_FILES[i]}.nav_log" ]; then length[i]=$(awk 'END{print NR}' "${IN_FILES[i]}.nav_log") @@ -6860,19 +7587,18 @@ done if $GROUPING && [[ $MENU_NUM -eq 1 ]]; then - echo - echo ". . . Getting stats on grouped files now . . ." - echo + print2log ". . . Getting stats on grouped files now . . ." for u in ${!grouping[@]}; do CUR_VID=$(readlink -f "${grouping[u]}") - spin "Getting stats on "${CUR_VID##*/}"" - group_idvid_stats[u]=$(idvid -terse -accurate "$CUR_VID" 2>/dev/null) + spin "Getting grouped video stats for the log on "${CUR_VID##*/}"" + group_idvid_stats[u]=$(idvid -terse -accurate "$CUR_VID" 2> /dev/null) if [ -s "$CUR_VID.nav_log" ]; then group_length[u]=$(awk 'END{print NR}' "$CUR_VID.nav_log") fi done echo fi +#echo -e "\nCheck the stats in todisc.log if you wish" # get length of videos in a separate loop from other stats # if we are doing SVCD there will be no nav_seek file @@ -6880,8 +7606,8 @@ # if we have a non empty nav_log get the length from that if [ -s "${IN_FILES[i]}".nav_log ]; then VID_LEN[i]=$(bc_math "${length[i]} / $FRAME_RATE") - else # otherwise, we run mencoder to get the length - VID_LEN[i]=$(vid_length "${IN_FILES[i]}" ) + else # otherwise, we run ffmpeg to get the length + VID_LEN[i]=$(stream_length "${IN_FILES[i]}" ) fi if [[ ${VID_LEN[i]%.*} -lt ${SEEK_VAL[i]%.*} ]]; then usage_error "A seek of ${SEEK_VAL[i]} seconds is too large for @@ -6907,14 +7633,14 @@ # if we have a value for ${group_length[g]} get the length from that if [[ -n "${group_length[g]}" ]]; then GROUP_VID_LEN[g]=$(bc_math "${group_length[g]} / $FRAME_RATE") - else # otherwise, we run mencoder to get the length - GROUP_VID_LEN[g]=$(vid_length "${grouping[g]}") + else # otherwise, we run stream_length to get the length + GROUP_VID_LEN[g]=$(stream_length "${grouping[g]}") fi done if $GROUPING; then index=0 for i in "${!IN_FILES[@]}"; do - if [[ ${GROUP[i]} ]]; then + if [[ ${GROUP_ARR[i]} ]]; then iter=( $BASEDIR/${TSET_NUM}-group-$((i+1))-*.mpg ) for ((t=index; t<index+${#iter[@]}; t++)); do # get lengths of group videos also in a seperate loop @@ -6941,20 +7667,19 @@ # put in the log file in case anyone is interested if ! $VMGM_ONLY && [[ $MENU_NUM -eq 1 ]] && $DO_STATS; then get_stats files - echo + print2log "" fi if ! $VMGM_ONLY && [[ $MENU_NUM -eq 1 ]] && $GROUPING && $DO_STATS; then get_stats group - echo; echo $SEPARATOR + print2log "" fi -echo # run quick_menu to create an almost finished menu file ( intro.m2v ) $QUICK_MENU && quick_menu # if doing switched menus, use the bgaudio from each video # unless "none" is passed for -bgaudio if $SWITCHED; then - yecho + yecho "" let vid=MENU_NUM-1 SHOWCASE_SEEK_VAL=${SEEK_VAL[vid]} # use silence if a short file ( probably a slide ) and no background audio @@ -6993,10 +7718,9 @@ # the menu audio will be the same length as the switched video fi yecho "Using audio from "${FILES[vid]}" for the audio background," - ! $STATIC && yecho \ - "using the same seek value for the audio as the video" - yecho "If you wish to use silence for the switched menu," - yecho "use '-bgaudio none'" + ! $STATIC && info_message "using the same seek value for the audio \ + as the video. If you wish to use silence for the switched menu, + use '-bgaudio none'" else if [[ $BG_AUDIO = "none" ]]; then # no audio if -bgaudio none BG_AUDIO="" @@ -7010,7 +7734,7 @@ fi fi fi - yecho + yecho "" fi for ((i=0; i<${#VID_LEN[@]}; i++)); do NEW_LENGTH=( ${NEW_LENGTH[@]} ${VID_LEN[i]%.*} ) @@ -7104,7 +7828,7 @@ $WORK_DIR/pics/$i/$(printf "%06d%s" $p .png) 2>/dev/null done elif [[ ${file_is_image[i]} = "yes" ]]; then - spin "Convert ${FILES[i]} to proper size/format" + spin "Convert ${FILES[i]##*/} to proper size/format" convert "${FILES[i]}" -depth 8 \ -resize ${THUMB_SIZE}! \ "$WORK_DIR/pics/$i/$(printf "%06d%s" 0 .${IMG_FMT})" @@ -7120,30 +7844,46 @@ thumb_frames=$THUMB_FRAMES fi # warning to ignore transcode error messages - print_tcode_info + $use_transcode && print_tcode_info if [ -s "${IN_FILES[i]}.nav_log" ]; then NAV_SEEK[i]="--nav_seek" NAVSEEK[i]=${IN_FILES[i]}.nav_log fi - yuv_fifo="$WORK_DIR/pics/$i/out.yuv" - log_tmp="$WORK_DIR/pics/$i/log.tmp" - [[ ! -p "$yuv_fifo" ]] && mkfifo "$yuv_fifo" + ff_log_tmp="$WORK_DIR/pics/$i/ff_log.tmp" + tc_log_tmp="$WORK_DIR/pics/$i/tc_log.tmp" + if $use_transcode; then + vid_stream="$WORK_DIR/pics/$i/out.yuv" + [[ ! -p "$vid_stream" ]] && mkfifo "$vid_stream" + ff_seek="" + ff_frames="" + else + # using ffmpeg directly on file, PIPE_FORMAT not needed + vid_stream="${IN_FILES[i]}" + unset PIPE_FORMAT + ff_seek="-ss ${SEEK_VAL[i]}" + ff_frames="-vframes $thumb_frames" + fi + # resize using ffmpeg instead of transcode - FFMPEG_CMD2=(ffmpeg $PIPE_FORMAT -i "$yuv_fifo" -f image2 -s $THUMB_SIZE -y \ - "$WORK_DIR/pics/$i/%06d.$IMG_FMT") + FFMPEG_CMD2=($FFmpeg $PIPE_FORMAT -i "$vid_stream" $ff_seek \ + $ff_frames -f image2 $VF scale=${THUMB_SIZE%x*}:${THUMB_SIZE#*x} \ + -y "$WORK_DIR/pics/$i/%06d.$IMG_FMT") TRANSCODE_CMD2=(transcode --progress_rate 10 \ --write_pid $WORK_DIR/tcode$i.pid -q 1 -i "${IN_FILES[i]}" \ -c ${SEEK_FRAMES[i]}-$((${SEEK_FRAMES[i]} + $thumb_frames)) \ - ${NAV_SEEK[i]} "${NAVSEEK[i]}" -o "$yuv_fifo" \ + ${NAV_SEEK[i]} "${NAVSEEK[i]}" -o "$vid_stream" \ -f $FRAME_RATE $EXPORT) - yecho "Running ${TRANSCODE_CMD2[@]}" | fold -bs - yecho "Running ${FFMPEG_CMD2[@]}" | fold -bs - "${TRANSCODE_CMD2[@]}" 2>&1 | strings >> "$LOG_FILE" & - "${FFMPEG_CMD2[@]}" > "$log_tmp" 2>&1 & + if $use_transcode; then + print2log "Running ${TRANSCODE_CMD2[@]}" + "${TRANSCODE_CMD2[@]}" 2>&1 | pipe2log transcode & + fi + print2log "Running ${FFMPEG_CMD2[@]}" + "${FFMPEG_CMD2[@]}" > "$ff_log_tmp" 2>&1 & ffm_pid=$! - wait_for "$WORK_DIR/tcode$i.pid" - TRANSCODE_PID=$(<$WORK_DIR/tcode$i.pid) - tcode_pids="$tcode_pids $TRANSCODE_PID" + if $use_transcode; then + wait_for "$WORK_DIR/tcode$i.pid" + tcode_pids="$tcode_pids $(<$WORK_DIR/tcode$i.pid)" + fi if [[ -n "$ffm_pid" ]]; then wait_for "$WORK_DIR/pics/$i/000001.$IMG_FMT" while ps -p $ffm_pid >/dev/null; do @@ -7153,12 +7893,27 @@ awk -F / '{ field = $NF }; END{ print field }') spin "Seeking in video and creating images: $last_image" done - wait # wait for ffmpeg and transcode to finish + # wait for ffmpeg and transcode to finish + wait $ffm_pid # get exit code of ffmpeg + if (($? != 0)); then + cat "$ff_log_tmp" | sed '/time=10000000000.00/d' | pipe2log ${FFmpeg##*/} + rm -f "$ff_log_tmp" + runtime_error \ + "Problem with ${FFmpeg##*/} while creating images from video" + fi + if $use_transcode; then + wait $(<$WORK_DIR/tcode$i.pid) + # get exit code of transcode + if (($? != 0)); then + runtime_error \ + "Problem with transcode while creating images from video" + fi + fi # get the largest image if static menu(we made 9) # get largest image of 9 if static menu and not -frame-safe if $STATIC && $FRAME_SAFE; then largest=$(get_largest 6 $V_FRAMES "$WORK_DIR/pics/$i/") - # remove the unused images after saving the largest as 1st + # remove unused images after saving the largest as 1st mv "$largest" "$WORK_DIR/pics/$i/000001.$IMG_FMT" 2>/dev/null rm -f "$WORK_DIR"/pics/$i/00000{2..9}.png fi @@ -7167,12 +7922,13 @@ ((numpics > ani_pics)) && ani_pics=$numpics # append ffmpeg output to the log echo -e \ - "\n$ME Log from ffmpeg (processing transcode stream)\n" \ + "\n$ME Log from ${FFmpeg##*/} (processing video stream)\n" \ >> "$LOG_FILE" - strings "$log_tmp" | sed '/time=10000000000.00/d' >> "$LOG_FILE" - rm -f "$log_tmp" + cat "$ff_log_tmp" | sed '/time=10000000000.00/d' | pipe2log ${FFmpeg##*/} + rm -f "$ff_log_tmp" echo - echo "Created $numpics images of $THUMB_FRAMES" + echo -n "Created $numpics images of $THUMB_FRAMES" + echo -ne "\r$(printf %60s)" # print spaces to overwrite previous line else runtime_error "Problem creating images from the video." fi @@ -7180,10 +7936,14 @@ fi # copy 000001 image to 000000 as we use 0 based counting (transcode) # TODO transition to using "1" based' images as we use ffmpeg now - cp "$WORK_DIR/pics/$i/000001.$IMG_FMT" "$WORK_DIR/pics/$i/000000.$IMG_FMT" - last=$(find $WORK_DIR/pics/$i -maxdepth 1 -name \*.$IMG_FMT | \ - sort | awk 'END{print}') - rm -f "$last" + [[ -s "$WORK_DIR/pics/$i/000001.$IMG_FMT" ]] && cp \ + "$WORK_DIR/pics/$i/000001.$IMG_FMT" "$WORK_DIR/pics/$i/000000.$IMG_FMT" + dir_cnt=$(find "$WORK_DIR/pics/$i" -maxdepth 1 -name "*.$IMG_FMT" |wc -l) + if ((dir_cnt > 1)); then + last=$(find $WORK_DIR/pics/$i -maxdepth 1 -name \*.$IMG_FMT | \ + sort | awk 'END{print}') + rm -f "$last" + fi done fi # create the pics for background image @@ -7266,8 +8026,7 @@ if $SUB_MENU; then for ((s=0; s<=NUM_FILES; s++)); do if ! ${SLIDESHOW[s]}; then - echo - echo "Creating highlight and select PNGs for submenu $((s + 1))" + print2log "Creating highlight and select PNGs for submenu $((s + 1))" C=$((${CHAPTERS[s]} - 1)) MENU_BUTTON_SIZE=${GEO_ARRAY[C]} get_button_geo @@ -7367,7 +8126,8 @@ echo for ((i=0; i<=NUM_FILES; i++)); do ! ${SLIDESHOW[i]} && \ - echo -e "Chapters for "${IN_FILES[i]}" are: \n"${CHAPT_ARRAY[i]}"\n" + echo -e "Chapters for "${IN_FILES[i]}" are: \n"${CHAPT_ARRAY[i]}"\n" | \ + pipe2log done fi # get button coordinates if text-rect buttons (showcase menu only) @@ -7474,7 +8234,7 @@ fi if ((i==NUM_FILES+2)); then # quick-nav assumes titlesets # VMGM_MENU means NOT -no-vmgm - if $VMGM_MENU && $PLAYALL && ! $VMGM_ONLY; then #DEBUG + if $VMGM_MENU && $PLAYALL && ! $VMGM_ONLY; then echo -n " <button name=\"$i\" ${btn_geos[i-1]} " echo -e "up=\"$((i-1))\" down=\"$((i+1))\"/>" echo -e " <button name=\"$((i+1))\" ${btn_geos[i]} $down/>" @@ -7522,7 +8282,7 @@ fi else for ((i=1; i<=NUM_BUTTONS; i++)); do - if $SHOWCASE && [[ $NUM_FILES -ge $SPLIT ]]; then + if $SHOWCASE && ((NUM_FILES >= SPLIT)); then if ((i>SPLIT)) && ((i<NUM_BUTTONS)); then left="left=\"$((i-SPLIT))\""; right="" elif (( i<=SPLIT)) && (( (i+SPLIT) <= (NUM_FILES+1) )); then @@ -7760,12 +8520,12 @@ if [[ -n $AUDIO_CHANNEL ]]; then echo "${VOB_PRE[i]}" fi - if [[ -n ${GROUP[i]} ]]; then + if [[ -n ${GROUP_ARR[i]} ]]; then ((MENU_NUM == 1 && ${CHAPTERS[i]} != 0)) && get_group_chapters $i format if ((${nochapt[i]})); then ! ${SLIDESHOW[i]} && echo -e \ " <vob file=\"$BASEDIR/${TSET_NUM}-$((i+1)).mpg\" $vid_pause/>" - for ((m=1; m<=$((${GROUP[i]})); m++)); do + for ((m=1; m<=$((${GROUP_ARR[i]})); m++)); do mpg="$BASEDIR/${TSET_NUM}-group-$((i+1))-${m}.mpg" [[ -e $mpg ]] && \ echo -e " <vob file=\"$mpg\" $grp_vid_pause/>" @@ -7773,7 +8533,7 @@ else ! ${SLIDESHOW[i]} && echo -e \ " <vob file=\"$BASEDIR/${TSET_NUM}-$((i+1)).mpg\" $chpts0 $vid_pause/>" - for ((m=1; m<=$((${GROUP[i]})); m++)); do + for ((m=1; m<=$((${GROUP_ARR[i]})); m++)); do mpg="$BASEDIR/${TSET_NUM}-group-$((i+1))-${m}.mpg" [[ -e $mpg ]] && echo -e \ " <vob file=\"$mpg\" ${chpts[++j]} $grp_vid_pause/>" @@ -7884,6 +8644,7 @@ # make dummy VMGM mpeg if ! $TITLESET_MODE && ! $DO_TITLESETS; then + yecho "Creating a blank mpeg for the vmgm menu" make_dummy fi # do submenu 1st for debug purposes @@ -7892,7 +8653,7 @@ yecho yecho "Building submenus" yecho - yecho "Creating images for each chapter" + print2log "Creating images for each chapter" if [ -z "$SM_TITLES" ]; then if $MULTILINE_TITLE; then for i in ${!TITLES[@]}; do @@ -7909,7 +8670,7 @@ # Audio and no -submenu-length given: full length of the audio file if $SUBMENU_AUDIO; then if [[ -n $SM_AUDIO_FILE ]]; then - SM_AUDIOLEN=$(audio_length "$SM_AUDIO_FILE") + SM_AUDIOLEN=$(stream_length "$SM_AUDIO_FILE" audio) fi for ((i=0; i<=NUM_FILES; i++)); do [[ -n $SM_AUDIO_FILE ]] && SUBMENU_AUDIOLEN[i]=$SM_AUDIOLEN @@ -7919,7 +8680,7 @@ if ${SLIDESHOW[i]}; then yecho spin "getting length of ${SM_AUDIO[i]} " - SUBMENU_AUDIOLEN[i]=$(audio_length "${SM_AUDIO[i]}") + SUBMENU_AUDIOLEN[i]=$(stream_length "${SM_AUDIO[i]}" audio) SUBMENU_LEN[i]=${SUBMENU_AUDIOLEN[i]} else SUBMENU_AUDIOLEN[i]=$( unformat_time ${SUBMENU_LEN[i]} ) @@ -7954,9 +8715,10 @@ smframes=${SUBMENU_FRAMES[i]} if ! ${SLIDESHOW[i]}; then C=$((${CHAPTERS[i]} - 1)) + VSIZE=${GEO_ARRAY[C]} SN_BTN_XY=${GEO_ARRAY[C]} # button dimensions NUM_CHAPTERS=${CHAPTERS[i]} - yecho "Creating a transparent title PNG" + print2log "Creating a transparent title PNG" SMTITLE_CMD=(convert -size 620x300 xc:none -font "$SM_TITLE_FONT" \ -pointsize $SUBMENU_FONTSIZE -fill "$SM_TITLE_CLR" \ -draw "gravity center text 2,2 \"${SM_TITLES[i]}\"" \ @@ -8001,7 +8763,7 @@ TOTAL_IMGS=${CHAPTERS[i]} PREFIX=${i}- fi - if [[ -n ${GROUP[i]} ]]; then + if [[ -n ${GROUP_ARR[i]} ]]; then unset x CUT c FILE_IN # this will also take care of grouped USER_CHAPTERS BASE=$WORK_DIR/${TSET_NUM}-group @@ -8054,19 +8816,20 @@ if $USER_CHAPTERS; then # 1 second seek for 1st chapt (00:00:00), to avoid black frames cmd[0]=30-$(bc_math "30 + $CUT_TIME" int) - elif [[ -z ${GROUP[i]} ]]; then + elif [[ -z ${GROUP_ARR[i]} ]]; then # auto chapters needs the last seek removed key=$((${#cmd[@]} - 1)) unset cmd[key] fi - yecho - yecho "Creating $TOTAL_IMGS chapter images for ${IN_FILES[i]}" - yecho - unset cf frm - for t in "${cmd[@]}"; do + print2log "" + print2log "Creating $TOTAL_IMGS chapter images for ${IN_FILES[i]}" + print2log "" + unset cf f + for t in "${!cmd[@]}"; do + ! $use_transcode && break # don't run block if just using ffmpeg # warning to ignore transcode error messages print_tcode_info - if [[ -n ${GROUP[i]} ]]; then + if [[ -n ${GROUP_ARR[i]} ]]; then CUR_FILE="${FILE_IN[cf++]}" else CUR_FILE="${IN_FILES[i]}" @@ -8077,53 +8840,51 @@ else unset NAVSEEK NAVLOG fi - log_tmp="$PICS_OUT/log.tmp" + ff_log_tmp="$PICS_OUT/ff_log.tmp" + tc_log_tmp="$PICS_OUT/tc_log.tmp" yuv_fifo="$PICS_OUT/out.yuv" [[ ! -p "$yuv_fifo" ]] && mkfifo "$yuv_fifo" # resize using ffmpeg instead of transcode - FFMPEG_CMD=(ffmpeg $PIPE_FORMAT -i "$yuv_fifo" \ - -f image2 -s ${GEO_ARRAY[C]} -y "$PICS_OUT/%06d.$SM_IMG_FMT") + FFMPEG_CMD=($FFmpeg $PIPE_FORMAT -i "$yuv_fifo" \ + -f image2 $VF scale=${VSIZE%x*}:${VSIZE#*x} -y "$PICS_OUT/%06d.$SM_IMG_FMT") TCODE_CMD=(nice transcode --progress_rate 10 \ --write_pid $WORK_DIR/tcode$i.pid -q 1 -i "$CUR_FILE" \ $NAVSEEK "$NAVLOG" -o "$yuv_fifo" -f \ - $FRAME_RATE -c $t $EXPORT) - yecho "Running ${TCODE_CMD[@]}" | fold -bs - yecho "Running ${FFMPEG_CMD[@]}" | fold -bs - "${TCODE_CMD[@]}" 2>&1 | strings >> "$LOG_FILE" & - "${FFMPEG_CMD[@]}" > "$log_tmp" 2>&1 & + $FRAME_RATE -c ${cmd[t]} $EXPORT) + print2log "Running ${TCODE_CMD[@]}" + print2log "Running ${FFMPEG_CMD[@]}" + "${TCODE_CMD[@]}" 2>&1 | pipe2log transcode & + "${FFMPEG_CMD[@]}" > "$ff_log_tmp" 2>&1 & ffm_pid=$! wait_for "$WORK_DIR/tcode$i.pid" TCODE_PID=$(<$WORK_DIR/tcode$i.pid) tcode_pids="$tcode_pids $TCODE_PID" - if [[ -n "$TCODE_PID" ]]; then + if [[ -n $TCODE_PID ]]; then while ps -p $ffm_pid >/dev/null; do wait_for "$IMG_DIR/000001.$SM_IMG_FMT" sleep 1 # spinner interval end=$(find "$IMG_DIR" -maxdepth 1 -name \*.$SM_IMG_FMT | sort | awk -F / '{ field = $NF }; END{ print field }') - spin "Seeking in video and creating images: $end" + e=${end##*/}; e=${e%%.*}; e=${e##*0} # strip to digit + spin \ + "Seeking and making $e images for chapter $((t+1)): $end" done - echo total_imgs=$(find "$IMG_DIR" -name "*.$SM_IMG_FMT" | wc -l) wait - echo "Created $total_imgs $sm_img_fmt of $TOTAL_IMGS" + #yecho "" + print2log "Created $total_imgs $sm_img_fmt of $TOTAL_IMGS" else runtime_error "Problem creating images from the video." fi - echo -e \ - "\n$ME Log from ffmpeg (processing transcode stream)\n" \ - >> "$LOG_FILE" - strings "$log_tmp" >> "$LOG_FILE" - rm -f "$log_tmp" - unset TCODE_CMD cmd run_transcode + cat "$ff_log_tmp" | pipe2log ${FFmpeg##*/} + rm -f "$ff_log_tmp" + unset TCODE_CMD + # transcode loops so each loop uses %06d, then moved to %08d if ! $ANI_SUB_MENU ; then - echo mv $WORK_DIR/submenu/000001.$SM_IMG_FMT \ - $WORK_DIR/submenu/$(printf "%08d%s\n" $((frm++)) .$SM_IMG_FMT) - let frm+=1 + $WORK_DIR/submenu/$(printf "%08d%s\n" $((f++)) .$SM_IMG_FMT) + let f+=1 elif $ANI_SUB_MENU; then - echo "renaming images by frame number" - echo u=${t/*-}; v=${t/-*} # names now start with 000001. Rename starting at 000000. for ((n=1; n<smframes+1; n++)); do @@ -8133,17 +8894,69 @@ lastimage=$WORK_DIR/animenu/$(printf \ "%06d%s\n" $((n-1)) .$SM_IMG_FMT) nextimage=$WORK_DIR/animenu/$(printf \ - "%08d%s\n" $((frm++ )) .$SM_IMG_FMT) + "%08d%s\n" $((f++ )) .$SM_IMG_FMT) if [[ ! -e $curimage ]]; then cp "$lastimage" "$nextimage" else mv "$curimage" "$nextimage" fi - let frm+=1 + let f+=1 done fi done - # make the chapter titles if called for. Shadow is hardcoded at #101010 + if ! $use_transcode; then # don't run block if using transcode + if [[ -n ${GROUP_ARR[i]} ]]; then + CUR_FILE="${FILE_IN[cf++]}" + else + CUR_FILE="${IN_FILES[i]}" + fi + ff_log_tmp="$PICS_OUT/ff_log.tmp" + frames=$CUT_TIME + + # avconv has no 'between' expr but keep commented code below + #frames=$((CUT_TIME - 1)) + #[[ ${FFmpeg##*/} =~ avconv ]] && frames=$CUT_TIME + # between filter is "inclusive" so between(300, 300) is 300 + #cur_frame=${cf%-*} + #if [[ ${FFmpeg##*/} =~ avconv ]]; then + #else # ffmpeg + # "select using "between" expr + # for fr in ${cmd[@]}; do + # cur_frame=${fr%-*} + # select1+="between(n,${cur_frame},$(( cur_frame + frames)))+" + # done + #fi + + for fr in ${cmd[@]}; do + cur_frame=${fr%-*} + select1+="(gt(n,${cur_frame}))*lte(n,$(( cur_frame + frames)))+" + done + + # remove last '+' sign + select1=${select1%+} + select1="'${select1}'",setpts="'N/($ff_frame_rate*TB)'" + scale1=scale=${VSIZE%x*}:${VSIZE#*x} + ffm_cmd=($FFmpeg -i "$CUR_FILE" -vf select="${select1}",${scale1} \ + -y "$IMG_DIR/%08d.$SM_IMG_FMT") + print2log "Running ${ffm_cmd[@]}" + "${ffm_cmd[@]}" > "$ff_log_tmp" 2>&1 & + ffm_pid=$! + while ps -p $ffm_pid >/dev/null; do + wait_for "$IMG_DIR/00000001.$SM_IMG_FMT" + sleep 1 # spinner interval + end=$(find "$IMG_DIR" -maxdepth 1 -name \*.$SM_IMG_FMT | + sort | awk -F / '{ field = $NF }; END{ print field }') + e=${end##*/}; e=${e%%.*}; e=${e##*0} # strip to digit + spin \ + "Seeking and making $TOTAL_IMGS images for chapters: $end" + done + total_imgs=$(find "$IMG_DIR" -name "*.$SM_IMG_FMT" | wc -l) + print2log "Created $total_imgs $sm_img_fmt of $TOTAL_IMGS" + wait + cat "$ff_log_tmp" | pipe2log ${FFmpeg##*/} + unset select1 ffm_cmd + fi + # make the chapter titles if needed. Shadow is hardcoded at #101010 if [[ -n ${CHAPTER_TITLES[@]} ]]; then echo "Making Chapter titles for Video $((i+1))" for ((a=0; a<${CHAPTERS[i]}; a++)); do @@ -8172,7 +8985,7 @@ done fi if $ANI_SUB_MENU ; then - # move submenu images to each subdir: $WORK_DIR/animenu/{0,1,2,etc} + # move submenu images to subdirs: $WORK_DIR/animenu/{0,1,2,etc} # or if making chapter titles, output to subdirs; rm original for ((a=0; a<${CHAPTERS[i]}; a++)); do unset num_procs smpids curimgs @@ -8213,14 +9026,14 @@ if $ANI_SUB_MENU; then $DEBUG && stime=$(date +%s) - TOYUV_CMD=(ppmtoy4m -v 0 -n $smframes -A $PIXEL_AR -F $YUV_FR -I p \ - -S 420mpeg2 -r) - IMGENC_CMD=(ffmpeg -f yuv4mpegpipe -r $FRAME_RATE -i - -an \ - -r $FRAME_RATE -s $VIDSIZE -tvstd $TV_STANDARD $FFMPEG_OPTS \ + TOYUV_CMD=(ppmtoy4m -v 0 -n $smframes -A $PIXEL_AR -F $YUV_FR \ + -I p -S 420mpeg2 -r) + IMGENC_CMD=($FFmpeg -f yuv4mpegpipe -i - -an $FFMPEG_OPTS \ + -r $ff_frame_rate $VF scale=${VF_SCALE},${ASPECT} \ -y "$WORK_DIR/menu$i.m2v") - echo - yecho "Running ${TOYUV_CMD[@]} < $WORK_DIR/ppm.fifo | - ${IMGENC_CMD[@]}" | fold -bs + yecho "" + print2log "Running ${TOYUV_CMD[@]} < $WORK_DIR/ppm.fifo | + ${IMGENC_CMD[@]}" mkfifo "$WORK_DIR/ppm.fifo" 2>/dev/null mkfifo "$WORK_DIR/enc.fifo" 2>/dev/null "${TOYUV_CMD[@]}" < "$WORK_DIR/ppm.fifo" > \ @@ -8229,7 +9042,8 @@ "${IMGENC_CMD[@]}" < "$WORK_DIR/enc.fifo" 2>/dev/null & encpids="$encpids $!" echo - echo "Encoding $smframes frames for "${IN_FILES[i]}"" >&2 + v=${IN_FILES[i]} + #echo "Encoding $smframes frames for "${IN_FILES[i]}"" >&2 # make fifos for intermediary piping for ((f=1; f<=max_procs; f++)); do [[ ! -p "$WORK_DIR/temp-${f}.ppm" ]] && \ @@ -8259,7 +9073,7 @@ smpids="$smpids $!" ppm_fifos+=("$out_ppm") # all frames waiting to be processed if ((num_procs==max_procs || a == smframes-1 )); then - spin "\rProcessing frame $((a+1)) of $smframes " >&2 + spin "\r${v##*/}: Processing frame $((a+1)) of $smframes " >&2 cat "${ppm_fifos[@]}" wait $smpids 2>/dev/null unset smpids num_procs ppm_fifos @@ -8271,12 +9085,13 @@ # wait for ppmtoy4m and ffmpeg to finish wait + echo >&2 - unset IM_CMD IM_CMD2 d f P + unset IM_CMD IM_CMD2 d f P v else # not $ANI_SUB_MENU - yecho + yecho "" yecho "Making montage images for "${IN_FILES[i]}"" # just use $CHAPTERS number of images imgs=( $(find $WORK_DIR/submenu -name \*.$SM_IMG_FMT | @@ -8305,26 +9120,23 @@ fi if ! $ANI_SUB_MENU; then - yecho + yecho "" yecho "Converting chapter montage of ${IN_FILES[i]} to m2v video format" IMG_STREAM_CMD1=(convert "$PICS_IN" ppm:-) IMG_STREAM_CMD2=(ppmtoy4m -v 0 -n ${SM_LOOPS[i]} -A $PIXEL_AR -F $YUV_FR -I p \ -S 420mpeg2 -r) - ENC_CMD1=(ffmpeg -f yuv4mpegpipe -r $FRAME_RATE -i - \ - -r $FRAME_RATE -s $VIDSIZE -tvstd $TV_STANDARD $FFMPEG_OPTS \ + ENC_CMD1=($FFmpeg -f yuv4mpegpipe -i - \ + -r $ff_frame_rate $VF scale=${VF_SCALE},${ASPECT} $FFMPEG_OPTS \ -y "$WORK_DIR/menu$i.m2v") - echo "Running ${IMG_STREAM_CMD1[@]} | ${IMG_STREAM_CMD2[@]} | \ + print2log "Running ${IMG_STREAM_CMD1[@]} | ${IMG_STREAM_CMD2[@]} | \ ${ENC_CMD1[@]}"| format_output | tee -a "$LOG_FILE" 2>&1 - if ! "${IMG_STREAM_CMD1[@]}" | "${IMG_STREAM_CMD2[@]}" | - "${ENC_CMD1[@]}" 2>&1|strings >> "$LOG_FILE"; then - runtime_error - fi + "${IMG_STREAM_CMD1[@]}" | "${IMG_STREAM_CMD2[@]}" | + "${ENC_CMD1[@]}" 2>&1|strings >> "$LOG_FILE" fi # check if m2v was created ok before proceeding - if mencoder -quiet -oac pcm -ovc copy -frames 0 \ - "$WORK_DIR/menu$i.m2v" -o /dev/null &>/dev/null; then + if is_video "$WORK_DIR/menu$i.m2v"; then : else echo @@ -8333,7 +9145,7 @@ fi # clean out submenu dirs of images echo - echo "Cleaning up leftover pics in $REAL_WORK_DIR/animenu" + print2log "Cleaning up leftover pics in $REAL_WORK_DIR/animenu" rm -f $WORK_DIR/submenu/* find $WORK_DIR/animenu/ -maxdepth 1 -type f -exec rm -f {} \; if $ANI_SUB_MENU; then @@ -8366,11 +9178,11 @@ # encode to m2v yecho "Encoding to compliant m2v video format" - PPM_CMD=(ppmtoy4m -v 0 -n ${SM_LOOPS[i]} -A $PIXEL_AR -I p -F $YUV_FR \ - -S 420mpeg2 -r) - FFM_CMD=(ffmpeg $INSIZE -r $FRAME_RATE -pix_fmt yuv420p \ - -f yuv4mpegpipe -i - -an -r $FRAME_RATE -s $VIDSIZE \ - -tvstd $TV_STANDARD $FFMPEG_OPTS -y "$WORK_DIR/menu${i}.m2v") + PPM_CMD=(ppmtoy4m -v 0 -n ${SM_LOOPS[i]} -A $PIXEL_AR -I p \ + -F $YUV_FR -S 420mpeg2 -r) + FFM_CMD=($FFmpeg $PIPE_FORMAT -i - \ + -an -r $ff_frame_rate $VF scale=${VF_SCALE},${ASPECT} \ + $FFMPEG_OPTS -y "$WORK_DIR/menu${i}.m2v") yecho "Running ${PPM_CMD[@]} | ${FFM_CMD[@]}" | format_output cat "$WORK_DIR/polaroid_stack${i}.ppm" | "${PPM_CMD[@]}" | "${FFM_CMD[@]}" 2>&1 | strings >> "$LOG_FILE" @@ -8378,41 +9190,42 @@ fi done unset IMG_STREAM_CMD1 ENC_CMD1 JPEG2YUV_OPTS + yecho "Working on submenu audio" for ((s=0; s<=NUM_FILES; s++)); do # create audio background for either animated or plain submenus - yecho - yecho "Creating an audio background" - yecho "Working on submenu audio for "${IN_FILES[s]}"" + #yecho "Creating an audio background" + #yecho "Working on submenu audio for "${IN_FILES[s]}"" if $SUBMENU_AUDIO; then # user supplied audio file for ths video if [[ -n "$SM_AUDIO_FILE" ]]; then # user supplied "1" audio file COPY_AC3=(cp -v $WORK_DIR/submenu.$AUDIO_EXT \ $WORK_DIR/menu$s.$AUDIO_EXT) - BGAUDIO_CMD=(ffmpeg -i "$SM_AUDIO_FILE" \ + BGAUDIO_CMD=($FFmpeg -i "$SM_AUDIO_FILE" \ -t ${SUBMENU_AUDIOLEN[s]} -ar 48000 -acodec pcm_s16le \ -y $WORK_DIR/submenu.wav) elif [[ "${SM_AUDIO[s]}" = "none" ]]; then # user asked for silence - SUBMENU_AUDIOLEN[s]=$(vid_length "$WORK_DIR/menu$s.m2v") - BGAUDIO_CMD=(ffmpeg -f s16le -ar 48000 -i /dev/zero $AUDIO_OPTS \ + SUBMENU_AUDIOLEN[s]=$(stream_length "$WORK_DIR/menu$s.m2v" m2v) + BGAUDIO_CMD=($FFmpeg -f s16le -ar 48000 -i /dev/zero $AUDIO_OPTS \ -t ${SUBMENU_AUDIOLEN[s]} -y $WORK_DIR/menu$s.$AUDIO_EXT) else # SM_AUDIO[s] is an audio file we will process it # do separate wavs for each supplied audio bg for each submenu - BGAUDIO_CMD=(ffmpeg -i "${SM_AUDIO[s]}" \ + # again using default or given submenu length + BGAUDIO_CMD=($FFmpeg -i "${SM_AUDIO[s]}" \ -t ${SUBMENU_AUDIOLEN[s]} -ar 48000 -acodec pcm_s16le \ -y $WORK_DIR/menu$s.wav) - BGAUDIO_CMD2=(ffmpeg -i $WORK_DIR/menu$s.wav \ + BGAUDIO_CMD2=($FFmpeg -i $WORK_DIR/menu$s.wav \ $AUDIO_OPTS -y $WORK_DIR/menu$s.$AUDIO_EXT) fi else # no supplied audio for submenu so create silence - SUBMENU_AUDIOLEN[s]=$(vid_length "$WORK_DIR/menu$s.m2v") - BGAUDIO_CMD=(ffmpeg -f s16le -ar 48000 -i /dev/zero $AUDIO_OPTS \ + SUBMENU_AUDIOLEN[s]=$(stream_length "$WORK_DIR/menu$s.m2v" m2v) + BGAUDIO_CMD=($FFmpeg -f s16le -ar 48000 -i /dev/zero $AUDIO_OPTS \ -t ${SUBMENU_AUDIOLEN[s]} -y $WORK_DIR/menu$s.$AUDIO_EXT) fi # run if wav doesn't exist, or its a slideshow if [[ ! -s $WORK_DIR/submenu.wav ]] || ${SLIDESHOW[s]}; then - yecho "Running ${BGAUDIO_CMD[@]}" + print2log "Running ${BGAUDIO_CMD[@]}" # run command, error out if problem - ! "${BGAUDIO_CMD[@]}" 2>&1 |strings >> "$LOG_FILE" 2>&1 \ + ! "${BGAUDIO_CMD[@]}" 2>&1 | pipe2log ${FFmpeg##*/} \ && runtime_error "Problem getting audio for the submenu" fi # convert to DVD/SVCD format as long as not "none" or single audio file @@ -8420,18 +9233,17 @@ && [[ ! "${SM_AUDIO[s]}" = "none" && -z "$SM_AUDIO_FILE" ]]; then if $SM_AUDIO_FADE; then #TIME=$(audio_length "$WORK_DIR/menu$s.wav") - echo -e "Running: + print2log "Running: sox $WORK_DIR/menu$s.wav $WORK_DIR/menu$s-processed.wav fade t - $SM_FADE ${SUBMENU_AUDIOLEN[s]} $SM_FADE" | - sed 's/ */ /g' | format_output + $SM_FADE ${SUBMENU_AUDIOLEN[s]} $SM_FADE" sox -q $WORK_DIR/menu$s.wav $WORK_DIR/menu$s-processed.wav \ fade t $SM_FADE ${SUBMENU_AUDIOLEN[s]} $SM_FADE rm $WORK_DIR/menu$s.wav mv $WORK_DIR/menu$s-processed.wav $WORK_DIR/menu$s.wav fi - echo "Running "${BGAUDIO_CMD2[@]}"" | fold -bs >> "$LOG_FILE" - ! "${BGAUDIO_CMD2[@]}" 2>&1 |strings >> "$LOG_FILE" \ - && runtime_error "Problem getting audio for the submenu" + print2log "Running ${BGAUDIO_CMD2[@]}" + "${BGAUDIO_CMD2[@]}" 2>&1 | pipe2log ${FFmpeg##*/} + ((${PIPESTATUS[0]} != 0)) && runtime_error "Problem getting audio for the submenu" unset TIME fi # if "1" audio file, then convert it if it has not been done yet @@ -8439,51 +9251,52 @@ && ! -s $WORK_DIR/submenu-processed.wav ]]; then if $SM_AUDIO_FADE; then #TIME=$(audio_length "$WORK_DIR/submenu.wav") - echo -e "Running: + print2log "Running: sox $WORK_DIR/submenu.wav $WORK_DIR/submenu-processed.wav \ - fade t $SM_FADE ${SUBMENU_AUDIOLEN[s]} $SM_FADE" | - format_output >> "$LOG_FILE" + fade t $SM_FADE ${SUBMENU_AUDIOLEN[s]} $SM_FADE" sox -q $WORK_DIR/submenu.wav $WORK_DIR/submenu-processed.wav \ fade t $SM_FADE ${SUBMENU_AUDIOLEN[s]} $SM_FADE rm -f $WORK_DIR/submenu.wav cp $WORK_DIR/submenu-processed.wav $WORK_DIR/submenu.wav fi - BGAUDIO_CMD3=(ffmpeg -i $WORK_DIR/submenu.wav \ + BGAUDIO_CMD3=($FFmpeg -i $WORK_DIR/submenu.wav \ $AUDIO_OPTS -y $WORK_DIR/submenu.$AUDIO_EXT) if [ -s $WORK_DIR/submenu.$AUDIO_EXT ]; then # if exists do nothing : else - echo "Running "${BGAUDIO_CMD3[@]}"" >> "$LOG_FILE.tmp" 2>&1 - ! "${BGAUDIO_CMD3[@]}" 2>&1 |strings >> "$LOG_FILE" \ - && runtime_error + print2log "Running ${BGAUDIO_CMD3[@]}" + "${BGAUDIO_CMD3[@]}" 2>&1 | pipe2log ${FFmpeg##*/} + ((${PIPESTATUS[0]} != 0)) && runtime_error "Problem getting audio for the submenu" fi fi # copy the final file for each submenu if only 1 supplied "${COPY_AC3[@]}" - yecho - yecho "Multiplexing video and audio together" + print2log "Multiplexing video and audio together" S=$((s + 1)) MPLEX_CMD=(mplex -V -f $MPLEX_FORMAT -o $WORK_DIR/menu$S.mpg \ $WORK_DIR/menu$s.$AUDIO_EXT $WORK_DIR/menu$s.m2v) - echo "Running: "${MPLEX_CMD[@]}"" | fold -bs >> "$LOG_FILE" - ! "${MPLEX_CMD[@]}" 2>&1 |strings >> "$LOG_FILE" && runtime_error + print2log "Running: ${MPLEX_CMD[@]}" + "${MPLEX_CMD[@]}" 2>&1 |pipe2log mplex + ((${PIPESTATUS[0]} != 0)) && runtime_error \ + "Problem muxing audio and video with mplex" # remove wav to save space - rm -fv $WORK_DIR/menu$s.wav + rm -f $WORK_DIR/menu$s.wav done - rm -fv $WORK_DIR/submenu.{wav,$AUDIO_EXT} + rm -f $WORK_DIR/submenu.{wav,$AUDIO_EXT} rm -fr $WORK_DIR/animenu/* fi ############################################################################## -# End of submenus # +# End of submenus # ############################################################################## ############################################################################## -# Work on main menu # +# Work on main menu # ############################################################################## if $DO_MENU; then yecho yecho "Building main menu" + yecho fi if [[ -n "$BG_VIDEO" ]] && ! $QUICK_MENU; then if $FAST_SEEK; then @@ -8492,11 +9305,11 @@ bg_post_seek="-ss $BG_SEEK" && unset bg_pre_seek fi yecho "Getting background video from $BG_VIDEO" - FFMPEG_CMD=(ffmpeg $bg_pre_seek -i "$BG_VIDEO" -an $bg_post_seek \ - -vframes $BG_VIDEO_FRAMES -s $VIDSIZE -f image2 \ - -y "$WORK_DIR/bg/%d.$IMG_FMT") - yecho "Extracting/resizing background images" - echo "Running: ${FFMPEG_CMD[@]}" | format_output >> "$LOG_FILE" + FFMPEG_CMD=($FFmpeg $bg_pre_seek -i "$BG_VIDEO" -an $bg_post_seek \ + $VF scale=$VF_SCALE -f image2 \ + -vframes $BG_VIDEO_FRAMES -y "$WORK_DIR/bg/%d.$IMG_FMT") + print2log "Extracting/resizing background images" + print2log "Running: ${FFMPEG_CMD[@]}" # Run command and check for failure if ! "${FFMPEG_CMD[@]}" 2>&1 |strings >> "$LOG_FILE"; then runtime_error "Problem creating images from the background video" @@ -8547,12 +9360,13 @@ #convert ${USER_PICS[MENU_NUM-1]} -resize $SHOWCASE_SIZE \ cp "$WORK_DIR/showcase_img.png" "$WORK_DIR/showcase/000001.png" else - FFMPEG_CMD=(ffmpeg $ffm_pre_seek -i "$SHOWCASE_VIDEO" -s \ - $SHOWCASE_SIZE -vframes $FRAMES -an $ffm_post_seek -f image2 \ - -y "$WORK_DIR/showcase/%06d.png") - echo -e "\nRunning: "${FFMPEG_CMD[@]}"\n" | fold -bs >> "$LOG_FILE" + FFMPEG_CMD=($FFmpeg $ffm_pre_seek -i "$SHOWCASE_VIDEO" \ + $VF scale=${SHOWCASE_SIZE%x*}:${SHOWCASE_SIZE#*x} -an -vframes \ + $FRAMES $ffm_post_seek -f image2 -y "$WORK_DIR/showcase/%06d.png") + print2log "Running: ${FFMPEG_CMD[@]}" SED_VAR="frame=" - "${FFMPEG_CMD[@]}" >> "$LOG_FILE.tmp" 2>&1 & + #"${FFMPEG_CMD[@]}" >> "$LOG_FILE.tmp" 2>&1 & + "${FFMPEG_CMD[@]}" 2>&1 | pipe2log ${FFmpeg##*/} & ffm_pid=$! while ps -p $ffm_pid >/dev/null; do sleep 1 @@ -8561,8 +9375,6 @@ wait $ffm_pid (($?)) && runtime_error "Problem creating images from the video." - strings "$LOG_FILE.tmp" >> "$LOG_FILE" - rm -f "$LOG_FILE.tmp" echo fi fi @@ -8614,7 +9426,7 @@ else { convert -size $SHOWCASE_SIZE "$pic" $SC_RAISE miff:- | convert - $SHOWCASE_FRAME -background none $ROTATE $WAVE miff:- | - convert - $QUALITY resize ${SHOWCASE_SIZE}! "$pic" ; } \ + convert - $QUALITY -resize ${SHOWCASE_SIZE}! "$pic" ; } \ 2>> "$LOG_FILE" & fi fi @@ -8644,7 +9456,7 @@ ((num_scpics > ani_pics)) && ani_pics=$num_scpics unset IMAGES last_pic next_pic FFMPEG_CMD pic -yecho +yecho "" if [[ ! "$SC_FRAMESTYLE" = "glass" && ! $TEXTMENU ]]; then if $SHOWCASE; then yecho "Processing video images" @@ -8809,14 +9621,14 @@ done fi if ! $QUICK_MENU && $DO_MENU; then - yecho - yecho "Making $FRAMES final montage frames and compositing onto \ + yecho "" + yecho "Making $FRAMES final montage frame(s) and compositing onto \ background with title" - yecho + yecho "" fi if $STATIC; then # we have a value for MENU_AUDIOLEN AND BG_AUDIO - if [[ -n "$BG_AUDIO" && "$BG_AUDIO" != "none" ]]; then + if [[ -n "$BG_AUDIO" && "$BG_AUDIO" != "none" ]] && ! $MENU_FADE; then LOOPS=$( bc <<< "$MENU_AUDIOLEN * $FRAME_RATE" 2>/dev/null) LOOPS=${LOOPS%.*} # switched menu: no bg audio or video and not menu fade @@ -8832,7 +9644,6 @@ PPM_LOOPS=$LOOPS fi if ! $QUICK_MENU && $DO_MENU; then - $STATIC && INSIZE="-s $VIDSIZE" echo echo \ "Converting images to video and encoding to $TARGET-compliant format" >&2 @@ -8846,17 +9657,21 @@ PPM_FRAMES=$((PPM_FRAMES+18)) TOYUV_CMD=(ppmtoy4m -v 2 -n $PPM_FRAMES -A $PIXEL_AR -I p -F $YUV_FR \ -S 420mpeg2 -r) - IMGENC_CMD=(ffmpeg $INSIZE -r $FRAME_RATE $PIPE_FORMAT -i - -an \ - -r $FRAME_RATE -s $VIDSIZE -tvstd $TV_STANDARD $FFMPEG_OPTS \ + IMGENC_CMD=($FFmpeg $PIPE_FORMAT -i - -an \ + -r $ff_frame_rate $VF scale=${VF_SCALE},${ASPECT} $FFMPEG_OPTS \ -y $WORK_DIR/intro.m2v) - yecho "Running ${TOYUV_CMD[@]} < $WORK_DIR/ppm.fifo | ${IMGENC_CMD[@]}" | - fold -bs + #print2log "Running ${TOYUV_CMD[@]} < $WORK_DIR/ppm.fifo | ${IMGENC_CMD[@]}" | + print2log "Running:" + echo "${TOYUV_CMD[@]} < $WORK_DIR/ppm.fifo | ${IMGENC_CMD[@]}" | \ + while read -r line; do + print2log "$line" + done mkfifo "$WORK_DIR/ppm.fifo" 2>/dev/null mkfifo "$WORK_DIR/enc.fifo" 2>/dev/null "${TOYUV_CMD[@]}" < "$WORK_DIR/ppm.fifo" > "$WORK_DIR/enc.fifo" \ - 2>> "$LOG_FILE" & #/dev/null & + 2>> "${LOG_FILE}.1-tmp" & #/dev/null & encpids="$encpids $!" - "${IMGENC_CMD[@]}" < "$WORK_DIR/enc.fifo" 2>> "$LOG_FILE" & #/dev/null & + "${IMGENC_CMD[@]}" < "$WORK_DIR/enc.fifo" 2>> "${LOG_FILE}.2-tmp" & #/dev/null & encpids="$encpids $!" fi # make intermediary fifos for images. They will get catted to ppm.fifo @@ -8986,9 +9801,11 @@ # -menu-fade working with -static $SINGLE_SLIDESHOW && \ IM_CMD1=(convert "$WORK_DIR/polaroid_stack.png" miff:- ) - - $TEXTMENU && unset MONTAGE_CMD - $TEXTMENU && MONTAGE_CMD=( "${MONTAGE_CMD03[@]}" ) + # -text-menu can have showcase image so don't unset if it is present + if $TEXTMENU && [[ -z "$SHOWCASE_IMG" ]]; then + unset MONTAGE_CMD + MONTAGE_CMD=( "${MONTAGE_CMD03[@]}" ) + fi # if doing less animated frames than the total # of frames # break from the loop and use ppmtoy4m to repeat last frame # if we are not doing a fadeout, or if doing fadeout, cat the last @@ -9059,7 +9876,7 @@ 2>> "$LOG_FILE" & else # not SHOWCASE_VIDEO (SHOWCASE_IMG) { "${MONTAGE_CMD[@]}" miff:- | "${MONTAGE_CMD02[@]}" miff:- | - "${MONTAGE_CMD2c[@]}" miff:- |"${MONTAGE_CMD5[@]}" | + "${MONTAGE_CMD2c[@]}" miff:- | "${MONTAGE_CMD5[@]}" | "${MONTAGE_CMD6[@]}" | "${MONTAGE_CMD3[@]}" miff:- | "${MONTAGE_CMD4[@]}" | "${MONTAGE_CMD7[@]}" ; } \ 2>> "$LOG_FILE" & @@ -9311,95 +10128,105 @@ fi # end making final montages # wait for ppmtoy4m and ffmpeg to finish wait +# send formated ffmpeg output to log +if [[ -e "${LOG_FILE}.1-tmp" ]]; then + cat "${LOG_FILE}.1-tmp" | pipe2log ppmtoy4m + rm -f "${LOG_FILE}.1-tmp" +fi +if [[ -e "${LOG_FILE}.2-tmp" ]]; then + cat "${LOG_FILE}.2-tmp" | pipe2log ${FFmpeg##*/} + rm -f "${LOG_FILE}.2-tmp" +fi if ! $QUICK_MENU && $DO_MENU; then echo - echo "Cleaning up montage images" + print2log "Cleaning up montage images" rm -f $WORK_DIR/animenu/*.$IMG_FMT rm -f $WORK_DIR/animenu/*.png fi # check if m2v was created ok before proceeding if $DO_MENU; then - if ! mencoder -quiet -oac pcm -ovc copy -frames 0 \ - "$WORK_DIR/intro.m2v" -o /dev/null &> /dev/null; then + if ! is_video "$WORK_DIR/intro.m2v"; then echo runtime_error "The menu video file has not been created !" fi fi if $DO_MENU; then - MENU_ATIME=$(vid_length "$WORK_DIR/intro.m2v") + MENU_ATIME=$(stream_length "$WORK_DIR/intro.m2v" m2v) $SWITCHED && MENU_ATIME=${MENU_LEN[MENU_NUM-1]} fi - # use mplayer to dump audio if mplayer used for video # but first check if audio same file as video and its not a static menu if [[ $SC_FRAMESTYLE = "glass" && $BG_AUDIO = $SHOWCASE_VIDEO ]]; then ! $STATIC && USE_MPLAYER_4AUDIO=: fi BG_AUDIO_LENGTH="-t $MENU_ATIME" -# create audio background for the main menu +# audio background for main menu # if $DO_MENU; then - sample_size=$(get_sox_arg) if [[ -z "$BG_AUDIO" || "$BG_AUDIO" = "none" ]]; then # use silence ! $SWITCHED && AUDIO_FADE=false # do not fade silence - echo "Running cat /dev/zero 2>/dev/null | nice -n 0 sox -t raw -c 2 -r 48000 \ - $sample_size -s - $WORK_DIR/intro.wav trim 0 $MENU_ATIME" |fold -bs - cat /dev/zero 2>/dev/null | nice -n 0 sox -t raw -c 2 -r 48000 \ - $sample_size -s - $WORK_DIR/intro.wav trim 0 $MENU_ATIME + BGAUDIO_CMD=($FFmpeg -f s16le -ar 48000 -i /dev/zero -ar 48000 \ + -t $MENU_ATIME -ac 2 -acodec pcm_s16le -y $WORK_DIR/intro.wav) + print2log "Running ${BGAUDIO_CMD[@]}" + "${BGAUDIO_CMD[@]}" 2>&1 | pipe2log ${FFmpeg##*/} + if [[ ! -s "$WORK_DIR/intro.wav" ]]; then + runtime_error "There was a problem creating menu background silence" + fi # Make sure file exists elif test ! -s "$BG_AUDIO"; then runtime_error "Cannot find background audio file: $BG_AUDIO" - else # audio supplied: convert to wav then later to dvd/svcd format + else # audio supplied: convert to wav then later to dvd format # TODO if ! $BG_AUDIOVIDEO_FILE; then # check if same file and if so # decode the audio and jpegs in one step above, and skip this block if $USE_MPLAYER_4AUDIO; then - BGAUDIO_CMD=(mplayer -quiet -vc null -vo null -ss \ + pipe_prog=mplayer + BGAUDIO_CMD=(mplayer -quiet -vc null -vo null -ss \ $MPLAYER_SEEK_VAL -ao pcm:waveheader:file="$WORK_DIR/intro.wav" \ -endpos $MENU_ATIME "$BG_AUDIO") else - BGAUDIO_CMD=(ffmpeg -y -async 1 -ss $BG_AUDIO_SEEK \ - $BG_AUDIO_LENGTH -i "$BG_AUDIO" -r $FRAME_RATE -ar 48000 \ + pipe_prog=${FFmpeg##*/} + BGAUDIO_CMD=($FFmpeg -y \ + -i "$BG_AUDIO" -vn -ss $BG_AUDIO_SEEK $BG_AUDIO_LENGTH -ar 48000 \ -acodec pcm_s16le $WORK_DIR/intro.wav) fi - yecho - echo "Running ${BGAUDIO_CMD[@]}" |format_output|tee -a "$LOG_FILE" 2>&1 - ! "${BGAUDIO_CMD[@]}" 2>&1 |strings >> "$LOG_FILE" && runtime_error + print2log "Running ${BGAUDIO_CMD[@]}" + "${BGAUDIO_CMD[@]}" 2>&1 |pipe2log $pipe_prog + ((${PIPESTATUS[0]} != 0)) && runtime_error \ + "Problem creating wav file during background audio processing" if $AUDIO_FADE; then # bgaudio supplied and audio fade selected - WAV_TIME=$(audio_length "$WORK_DIR/intro.wav") - echo "Running: + WAV_TIME=$(stream_length "$WORK_DIR/intro.wav" audio) + print2log "Running: sox $WORK_DIR/intro.wav $WORK_DIR/intro-processed.wav fade t - $FADE $WAV_TIME $FADE" |format_output + $FADE $WAV_TIME $FADE" sox $WORK_DIR/intro.wav \ - $WORK_DIR/intro-processed.wav fade t $FADE $WAV_TIME $FADE - rm $WORK_DIR/intro.wav + $WORK_DIR/intro-processed.wav fade t $FADE $WAV_TIME $FADE 2>&1 | pipe2log sox + $KEEP_FILES || rm $WORK_DIR/intro.wav mv $WORK_DIR/intro-processed.wav $WORK_DIR/intro.wav fi fi -fi -unset BGAUDIO_CMD TIME + unset BGAUDIO_CMD TIME + + # convert to proper audio format + BGAUDIO_CMD=($FFmpeg -i $WORK_DIR/intro.wav \ + $AUDIO_OPTS -y $WORK_DIR/intro.$AUDIO_EXT) + echo "Running "${BGAUDIO_CMD[@]}"" | pipe2log + "${BGAUDIO_CMD[@]}" 2>&1 | pipe2log ${FFmpeg##*/} -# convert to proper audio format -BGAUDIO_CMD=(ffmpeg -i $WORK_DIR/intro.wav \ -$AUDIO_OPTS -y $WORK_DIR/intro.$AUDIO_EXT) -yecho "Running "${BGAUDIO_CMD[@]}"" | fold -bs >> "$LOG_FILE" -"${BGAUDIO_CMD[@]}" 2>&1 |strings >> "$LOG_FILE" -if $DO_MENU; then ! [[ -s $WORK_DIR/intro.$AUDIO_EXT ]] && runtime_error unset BGAUDIO_CMD - rm -fv "$WORK_DIR/intro.wav" - echo - echo "Multiplexing main menu audio and video together" + $KEEP_FILES || rm -f "$WORK_DIR/intro.wav" + print2log "Multiplexing main menu audio and video together" # mplex main menu audio and video together INTRO_MPLEX_CMD="mplex -V -f $MPLEX_FORMAT -o $WORK_DIR/intro.mpg \ $WORK_DIR/intro.$AUDIO_EXT $WORK_DIR/intro.m2v" - echo -e "\nRunning: $INTRO_MPLEX_CMD\n" |fold -bs >> "$LOG_FILE" - yecho - ! ${INTRO_MPLEX_CMD[@]} 2>&1 |strings >> "$LOG_FILE" && runtime_error + print2log "Running: $INTRO_MPLEX_CMD" + ${INTRO_MPLEX_CMD[@]} 2>&1 |pipe2log mplex + ((${PIPESTATUS[0]} != 0)) && runtime_error \ + "Problem muxing the menu video and audio with mplex" - yecho if $SWITCHED_MODE || $SWITCHED_MENUS; then - yecho "Copying the menu mpeg" + echo "Copying the menu mpeg" |pipe2log if [[ $MENU_NUM -ne 1 ]]; then cp -v "$REAL_WORK_DIR/intro.mpg" \ "$BASEDIR/${TSET_NUM}-${MENU_NUM}intro.mpg" @@ -9416,31 +10243,43 @@ fi fi if $SWITCHED_MENUS; then + print2log "Running spumux to create navigation buttons." for ((i=1; i<=${#FILES[@]}; i++)); do MENU_FILE="$BASEDIR/animenu${TSET_NUM}-${i}.mpg" - yecho "Running spumux "$SPUMUX_XML" \ - < "$REAL_WORK_DIR/${TSET_NUM}-${i}intro.mpg" > "$MENU_FILE"" + print2log "Running spumux $SPUMUX_XML \ + < $REAL_WORK_DIR/${TSET_NUM}-${i}intro.mpg > $MENU_FILE" spumux "$SPUMUX_XML" < "$WORK_DIR/${TSET_NUM}-${i}intro.mpg" \ - > "$MENU_FILE" 2>> "$LOG_FILE" + > "$MENU_FILE" 2>> "${LOG_FILE}.tmp" + wait + [[ -e ${LOG_FILE}.tmp ]] && cat "${LOG_FILE}.tmp" | pipe2log spumux + rm -f ${LOG_FILE}.tmp check_menufile done fi fi if ! $SWITCHED_MENUS && ! $SWITCHED_MODE; then - yecho "Running spumux "$SPUMUX_XML" < $WORK_DIR/intro.mpg > "$MENU_FILE"" - spumux "$SPUMUX_XML" < $WORK_DIR/intro.mpg > "$MENU_FILE" 2>> "$LOG_FILE" + print2log "Running spumux $SPUMUX_XML < $WORK_DIR/intro.mpg > $MENU_FILE" + spumux "$SPUMUX_XML" < $WORK_DIR/intro.mpg > "$MENU_FILE" 2>> "${LOG_FILE}.tmp" + wait + [[ -e ${LOG_FILE}.tmp ]] && cat "${LOG_FILE}.tmp" | pipe2log spumux + rm -f ${LOG_FILE}.tmp check_menufile fi if $SUB_MENU; then - echo "Creating submenus" + echo "Creating submenus" | pipe2log + print2log "Running spumux to create navigation buttons" for ((x=1; x<=V_TOTAL; x++)); do - yecho "Running spumux "$WORK_DIR/submenu${x}_spumux.xml" < \ + print2log "Running spumux "$WORK_DIR/submenu${x}_spumux.xml" < \ $WORK_DIR/menu${x}.mpg > \ $(sed 's/\(.*\)menu/\1Menu/' <<< $WORK_DIR/menu${x}.mpg)"|fold -bs spumux "$WORK_DIR/submenu${x}_spumux.xml" < \ $WORK_DIR/menu${x}.mpg > \ $(sed 's/\(.*\)menu/\1Menu/' <<< $BASEDIR/${TSET_NUM}-menu${x}.mpg) \ - 2>> "$LOG_FILE" + 2>> "${LOG_FILE}.tmp" + wait + [[ -e ${LOG_FILE}.tmp ]] && cat "${LOG_FILE}.tmp" | pipe2log spumux + rm -f ${LOG_FILE}.tmp + done fi if $TITLESET_MODE; then @@ -9448,14 +10287,14 @@ fi if $AUTHOR && ! $VMGM_ONLY && ! $DO_TITLESETS && ! $SWITCHED_MODE; then - echo "Running dvdauthor to create the DVD filesystem" - dvdauthor -x "$DVDAUTHOR_XML" 2>&1 | tee -a "$LOG_FILE.tmp" + yecho "Running dvdauthor to create the DVD filesystem" + dvdauthor -x "$DVDAUTHOR_XML" 2>&1 | pipe2log dvdauthor if [[ ${PIPESTATUS[0]} -ne 0 ]]; then dvdauthor_error fi - strings "$LOG_FILE.tmp" >> "$LOG_FILE" && rm -f "$LOG_FILE.tmp" + #strings "$LOG_FILE.tmp" >> "$LOG_FILE" && rm -f "$LOG_FILE.tmp" fi -echo "Cleaning up unwanted files in $REAL_WORK_DIR" +print2log "Cleaning up unwanted files in $REAL_WORK_DIR" find "$WORK_DIR"/ -name '*.$IMG_FMT' ! -name preview.$IMG_FMT -exec rm -f {} \; \ > /dev/null 2>&1 rm -fr "$WORK_DIR/animenu" "$WORK_DIR/pics" "$WORK_DIR/submenu"
View file
tovid-0.34.tar.bz2/src/todisc-fade-routine -> tovid-0.35.tar.gz/src/todisc-fade-routine
Changed
@@ -7,7 +7,7 @@ # # Project homepage: http://tovid.wikia.com # -# Copyright (C) 2005-2010 +# Copyright (C) 2005-2015 # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License
View file
tovid-0.34.tar.bz2/src/todiscgui -> tovid-0.35.tar.gz/src/todiscgui
Changed
@@ -4,6 +4,20 @@ import sys from libtovid.guis import todisc +command = [] +position = '' +project = '' if __name__ == '__main__': - todisc.run(sys.argv[1:]) + args = sys.argv[1:] + while args: + arg = args.pop(0) + # if passing --position pop next arg as well + if arg in ['--position', '-position']: + position = args.pop(0) + elif arg in ['--project', '-project']: + project = args.pop(0) + else: + # if --position or --project not passed, all args append to command + command.append(arg) + todisc.run(command, position=position, project=project)
View file
tovid-0.34.tar.bz2/src/tovid -> tovid-0.35.tar.gz/src/tovid
Changed
@@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/python # tovid.py """Frontend to the tovid suite. @@ -10,19 +10,24 @@ Where 'command' is one of the following: - Command Description Formerly - ----------------------------------------------------------------- - id Identify one or more video files idvid - dvd Author and/or burn a DVD makedvd - menu Create an MPEG menu makemenu - vcd Author and/or burn a VCD makevcd - xml Create (S)VCD or DVD .xml file makexml - postproc Post-process an MPEG video file postproc - disc Create a DVD with menus todisc - gui Start the tovid GUI todiscgui - mpg Encode videos to MPEG format tovid - titlesets Start the titleset wizard (new) - chapters Set video chapter points with mplayer (new) + Main commands (one step DVD creation) + + Command Description Formerly + ----------------------------------------------------------------------- + disc Options to encode, make menus, author and burn todisc + gui Start the tovid GUI todiscgui + titlesets Start the titleset wizard GUI (new) + + + Helper commands (used by 'Main commands' or run standalone) + + Command Description Formerly + ----------------------------------------------------------------------- + mpg Encode videos to MPEG format tovid + id Identify one or more video files idvid + dvd Author and/or burn a DVD makedvd + chapters A GUI to set chapter points with mplayer (new) + The following general options are also available: --prefix | -prefix Return the tovid install prefix @@ -41,16 +46,16 @@ import time import shlex import shutil -from ConfigParser import ConfigParser +# python 3 compatibility +try: + from ConfigParser import ConfigParser +except ImportError: + from configparser import ConfigParser # Command names to script mappings _scripts = { 'id': 'idvid', 'dvd': 'makedvd', - 'menu': 'makemenu', - 'vcd': 'makevcd', - 'xml': 'makexml', - 'postproc': 'postproc', 'disc': 'todisc', 'gui': 'todiscgui', 'mpg': 'makempg', @@ -86,8 +91,11 @@ """Return the tovid version string. """ tovid_init = self.script_dir + '/tovid-init' - cmd = shlex.split("bash -c '. %s && printf $TOVID_VERSION'" % tovid_init) - return subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0] + # can't just source tovid-init to get TOVID_VERSION - sourcing may fail + cmd = shlex.split("awk -F= '/^TOVID_VERSION/ {print $2}' %s" % tovid_init) + result = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0] + # Python 3 needs decode("utf-8") as it returns a byte string not str + return result.decode("utf-8").replace('"', '').strip() def parse_options(self, args): @@ -98,11 +106,11 @@ arg = args.pop(0) if arg in ['-prefix', '--prefix']: - print self.prefix + print(self.prefix) sys.exit(0) elif arg in ['-version', '--version']: - print self.version + print(self.version) sys.exit(0) elif arg in ['-info', '--info']: @@ -166,23 +174,30 @@ return # Create ~/.tovid if it doesn't exist already - user_tovid_dir = os.path.expanduser('~/.tovid') - if not os.path.exists(user_tovid_dir): - print("Creating '%s'" % user_tovid_dir) - os.mkdir(user_tovid_dir) - + # honour TOVID_HOME environment variable + self.user_tovid_dir = os.getenv('TOVID_HOME') or os.path.expanduser('~/.tovid') + #user_tovid_dir = os.path.expanduser('~/.tovid') + + if not os.path.exists(self.user_tovid_dir): + try: + os.mkdir(self.user_tovid_dir) + print("Creating '%s'" % self.user_tovid_dir) + except OSError: + print("Cannot create %s, exiting ..." %self.user_tovid_dir) + sys.exit(1) # Copy default tovid.ini to ~/.tovid if it doesn't exist already - user_tovid_ini = os.path.join(user_tovid_dir, 'tovid.ini') - if not os.path.exists(user_tovid_ini): - print("Creating '%s'" % user_tovid_ini) - shutil.copy(default_tovid_ini, user_tovid_ini) + self.user_tovid_ini = os.path.join(self.user_tovid_dir, 'tovid.ini') + if not os.path.exists(self.user_tovid_ini): + print("Creating '%s'" % self.user_tovid_ini) + shutil.copy(default_tovid_ini, self.user_tovid_ini) def get_config_options(self, command): """Return any options found in ~/.tovid/tovid.ini for the given command. """ # Parse the user's tovid.ini file - filename = os.path.expanduser('~/.tovid/tovid.ini') + #filename = os.path.expanduser('~/.tovid/tovid.ini') + filename = self.user_tovid_ini config = ConfigParser() config.read(filename) # If no [command] section exists, or if there's no 'options' setting,
View file
tovid-0.34.tar.bz2/src/tovid-init -> tovid-0.35.tar.gz/src/tovid-init
Changed
@@ -8,7 +8,7 @@ # # Project homepage: http://tovid.wikia.com # -# Copyright (C) 2005-2010 +# Copyright (C) 2005-2014 # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -45,7 +45,7 @@ #set -u # Suite version -TOVID_VERSION="0.34" +TOVID_VERSION="0.35" # String used to separate blocks of output SEPARATOR="=========================================================" @@ -53,7 +53,7 @@ TOVID_HOME="$HOME/.tovid" TOVID_HOME_PAGE="http://tovid.wikia.com" TOVID_FORUMS="http://groups.google.com/group/tovid-users" - +TOVID_ISSUES="http://code.google.com/p/tovid/issues/list" # ****************************************************************************** # ****************************************************************************** @@ -180,9 +180,8 @@ # ****************************************************************************** # Take a string containing a time (like "02:15:25.3") and # format it as an integer number of seconds. Fractional seconds -# are truncated. Result is echoed to stdout, so to use the output -# as a "return value", call the function like this: -# RETURN_VALUE=$(unformat_time $TIME_STRING) +# are truncated. Result is echoed to stdout, so to use the output you can +# call the function like this: var=$(unformat_time $TIME_STRING) # ****************************************************************************** function unformat_time() { @@ -195,7 +194,11 @@ else TOT_SECONDS=$1 fi - echo $TOT_SECONDS + if [[ -n $2 && $2 = "int" ]]; then + echo ${TOT_SECONDS%%.*} + else + echo $TOT_SECONDS + fi } # ***************************************************************************** @@ -278,15 +281,17 @@ # Wait for input file to appear # After a 30-second timeout, exit gracefully CUR_TIME=30 - while test $CUR_TIME -gt 0; do + while test $CUR_TIME -gt 0; do + sleep 3 # If file exists, wait a few more seconds, then break out if test -e "$FOP_OUTFILE"; then - printf "Processing started. Please wait... " - sleep 3s + $QUIET || printf "Processing started. Please wait... " + sleep 1 + CUR_TIME=1 break fi printf "Waiting $CUR_TIME seconds for output file \"$FOP_BASENAME_NAME\" to appear...\r" - sleep 1s + sleep 1 CUR_TIME=$(expr $CUR_TIME - 1) done @@ -319,12 +324,12 @@ # Doze a bit to let the file size increase # (SLEEP_TIME defaults to 1s if unset) - sleep ${SLEEP_TIME-"1s"} + sleep ${SLEEP_TIME-"1"} FOP_LAST_SIZE=$FOP_CUR_SIZE FOP_CUR_SIZE=$(du -b "$FOP_OUTFILE" | awk '{print $1}') done - printf "\n\n" + $QUIET && printf "\n" || printf "\n\n" } # ****************************************************************************** @@ -412,8 +417,8 @@ count=$(seq 1 $LAST) for _CNTR in $(sort -nr <<< "$count") do - echo -n -e " in $_CNTR seconds...\r"; - sleep 1s; + echo -n -e " in $_CNTR seconds...or press <ENTER>\r"; + read -t 1 && break; done } @@ -437,7 +442,18 @@ done return 0 } - +# ***************************************************************************** +# takes 1 arg: [name to prefix each line of output] +# uses stdbuf (coreutils) if present so stdin is line buffered +send_to_log() +{ + [[ $1 ]] && prog_name="[$1]: " || prog_name="[${0##*/}]: " + $std_buf tr "\015" "\n" < /dev/stdin | \ + while read line; do + printf "%s %s\n" "$prog_name" "$line" + done + printf "\n" +} # ****************************************************************************** # @@ -456,7 +472,8 @@ KERNEL=$(uname) if test "$KERNEL" = "Linux"; then # Linux should have /proc/cpuinfo - CPU_MODEL=$(awk -F ":" '/model name/ {print $2}' /proc/cpuinfo | head -n 1) + CPU_MODEL=$(awk -F ":" '/model name/ {print $2}' \ + /proc/cpuinfo | head -n 1 | sed 's/^ *//g') CPU_SPEED=$(awk 'BEGIN { IGNORECASE = 1 } /MHz/ { print $4 }' /proc/cpuinfo | head -n 1) # Test for multiple CPUs. If they are available, try to use them. if test $(grep "^processor" /proc/cpuinfo | wc -l) -ge "2"; then @@ -529,14 +546,29 @@ # tovid preferences # Configures working directory for all scripts and # output directory for the makempg script +# also used for setting ffmpeg/avconv program #WORKING_DIR=/tmp #OUTPUT_DIR=/video/outfiles +#TOVID_FFMPEG=ffmpeg EOF` printf "$PREFS_CONTENTS\n" > "$USER_PREFS" fi # if preferences vars are set in the environment, use those (takes precedence). [[ $TOVID_WORKING_DIR ]] && WORKING_DIR="$TOVID_WORKING_DIR" [[ $TOVID_OUTPUT_DIR ]] && OUTPUT_DIR="$TOVID_WORKING_DIR" +[[ $TOVID_FFMPEG_CMD ]] && TOVID_FFMPEG="$TOVID_FFMPEG_CMD" +# FFmpeg and FFprobe are vars used for ffmpeg by scripts needing ffmpeg/avconv +# if avconv is installed, use that unless env var set +hash avconv 2>/dev/null && TOVID_FFMPEG=${TOVID_FFMPEG:-avconv} +hash avprobe 2>/dev/null && TOVID_FFPROBE=${TOVID_FFPROBE:=avprobe} +# finally, default to ffmpeg if non of the above override it +FFmpeg=${TOVID_FFMPEG:=ffmpeg} +[[ $FFmpeg =~ ffmpeg ]] && TOVID_FFPROBE=ffprobe +[[ $FFmpeg =~ avconv ]] && TOVID_FFPROBE=avprobe +FFprobe=${TOVID_FFPROBE:=ffprobe} + +# stdbuf (coreutils>=7.5) is useful to todisc and makempg, use it if present +hash stdbuf 2>/dev/null && std_buf="stdbuf -oL" || std_buf="" # ****************************************************************************** # Check for run-time dependencies @@ -561,7 +593,7 @@ # ************************************************************************* # Required Dependencies # ************************************************************************* - core="grep sed md5sum mplayer mencoder mplex mpeg2enc yuvfps yuvdenoise ppmtoy4m mp2enc jpeg2yuv ffmpeg" + core="grep sed md5sum mplayer mplex mpeg2enc yuvfps yuvdenoise ppmtoy4m mp2enc jpeg2yuv" # ************************************************************************* # Optional Dependencies @@ -596,9 +628,13 @@ # ------------------------------------------------------------------------- # todisc dependencies - todisc_deps="$magick mogrify spumux dvdauthor transcode sox" + todisc_deps="$magick mogrify spumux dvdauthor sox" # Quit and complain if ANY core dependency is missing. assert_dep "$core" "You are missing CORE tovid dependencies!" + # ffmpeg is also a part of core deps, but is taken care of here + ffmpeg_alts="Use either ffmpeg (ffmpeg.org) or avconv (libav.org)." + ffmpeg_pref="Set choice in ${USER_PREFS}. As in: TOVID_FFMPEG=ffmpeg" + assert_dep $FFmpeg "You are missing $FFmpeg ! $ffmpeg_alts ${ffmpeg_pref}." # End tovid-init
View file
tovid-0.34.tar.bz2/src/tovid-init.in -> tovid-0.35.tar.gz/src/tovid-init.in
Changed
@@ -8,7 +8,7 @@ # # Project homepage: http://tovid.wikia.com # -# Copyright (C) 2005-2010 +# Copyright (C) 2005-2014 # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -53,7 +53,7 @@ TOVID_HOME="$HOME/.tovid" TOVID_HOME_PAGE="http://tovid.wikia.com" TOVID_FORUMS="http://groups.google.com/group/tovid-users" - +TOVID_ISSUES="http://code.google.com/p/tovid/issues/list" # ****************************************************************************** # ****************************************************************************** @@ -180,9 +180,8 @@ # ****************************************************************************** # Take a string containing a time (like "02:15:25.3") and # format it as an integer number of seconds. Fractional seconds -# are truncated. Result is echoed to stdout, so to use the output -# as a "return value", call the function like this: -# RETURN_VALUE=$(unformat_time $TIME_STRING) +# are truncated. Result is echoed to stdout, so to use the output you can +# call the function like this: var=$(unformat_time $TIME_STRING) # ****************************************************************************** function unformat_time() { @@ -195,7 +194,11 @@ else TOT_SECONDS=$1 fi - echo $TOT_SECONDS + if [[ -n $2 && $2 = "int" ]]; then + echo ${TOT_SECONDS%%.*} + else + echo $TOT_SECONDS + fi } # ***************************************************************************** @@ -278,15 +281,17 @@ # Wait for input file to appear # After a 30-second timeout, exit gracefully CUR_TIME=30 - while test $CUR_TIME -gt 0; do + while test $CUR_TIME -gt 0; do + sleep 3 # If file exists, wait a few more seconds, then break out if test -e "$FOP_OUTFILE"; then - printf "Processing started. Please wait... " - sleep 3s + $QUIET || printf "Processing started. Please wait... " + sleep 1 + CUR_TIME=1 break fi printf "Waiting $CUR_TIME seconds for output file \"$FOP_BASENAME_NAME\" to appear...\r" - sleep 1s + sleep 1 CUR_TIME=$(expr $CUR_TIME - 1) done @@ -319,12 +324,12 @@ # Doze a bit to let the file size increase # (SLEEP_TIME defaults to 1s if unset) - sleep ${SLEEP_TIME-"1s"} + sleep ${SLEEP_TIME-"1"} FOP_LAST_SIZE=$FOP_CUR_SIZE FOP_CUR_SIZE=$(du -b "$FOP_OUTFILE" | awk '{print $1}') done - printf "\n\n" + $QUIET && printf "\n" || printf "\n\n" } # ****************************************************************************** @@ -412,8 +417,8 @@ count=$(seq 1 $LAST) for _CNTR in $(sort -nr <<< "$count") do - echo -n -e " in $_CNTR seconds...\r"; - sleep 1s; + echo -n -e " in $_CNTR seconds...or press <ENTER>\r"; + read -t 1 && break; done } @@ -437,7 +442,18 @@ done return 0 } - +# ***************************************************************************** +# takes 1 arg: [name to prefix each line of output] +# uses stdbuf (coreutils) if present so stdin is line buffered +send_to_log() +{ + [[ $1 ]] && prog_name="[$1]: " || prog_name="[${0##*/}]: " + $std_buf tr "\015" "\n" < /dev/stdin | \ + while read line; do + printf "%s %s\n" "$prog_name" "$line" + done + printf "\n" +} # ****************************************************************************** # @@ -456,7 +472,8 @@ KERNEL=$(uname) if test "$KERNEL" = "Linux"; then # Linux should have /proc/cpuinfo - CPU_MODEL=$(awk -F ":" '/model name/ {print $2}' /proc/cpuinfo | head -n 1) + CPU_MODEL=$(awk -F ":" '/model name/ {print $2}' \ + /proc/cpuinfo | head -n 1 | sed 's/^ *//g') CPU_SPEED=$(awk 'BEGIN { IGNORECASE = 1 } /MHz/ { print $4 }' /proc/cpuinfo | head -n 1) # Test for multiple CPUs. If they are available, try to use them. if test $(grep "^processor" /proc/cpuinfo | wc -l) -ge "2"; then @@ -529,14 +546,29 @@ # tovid preferences # Configures working directory for all scripts and # output directory for the makempg script +# also used for setting ffmpeg/avconv program #WORKING_DIR=/tmp #OUTPUT_DIR=/video/outfiles +#TOVID_FFMPEG=ffmpeg EOF` printf "$PREFS_CONTENTS\n" > "$USER_PREFS" fi # if preferences vars are set in the environment, use those (takes precedence). [[ $TOVID_WORKING_DIR ]] && WORKING_DIR="$TOVID_WORKING_DIR" [[ $TOVID_OUTPUT_DIR ]] && OUTPUT_DIR="$TOVID_WORKING_DIR" +[[ $TOVID_FFMPEG_CMD ]] && TOVID_FFMPEG="$TOVID_FFMPEG_CMD" +# FFmpeg and FFprobe are vars used for ffmpeg by scripts needing ffmpeg/avconv +# if avconv is installed, use that unless env var set +hash avconv 2>/dev/null && TOVID_FFMPEG=${TOVID_FFMPEG:-avconv} +hash avprobe 2>/dev/null && TOVID_FFPROBE=${TOVID_FFPROBE:=avprobe} +# finally, default to ffmpeg if non of the above override it +FFmpeg=${TOVID_FFMPEG:=ffmpeg} +[[ $FFmpeg =~ ffmpeg ]] && TOVID_FFPROBE=ffprobe +[[ $FFmpeg =~ avconv ]] && TOVID_FFPROBE=avprobe +FFprobe=${TOVID_FFPROBE:=ffprobe} + +# stdbuf (coreutils>=7.5) is useful to todisc and makempg, use it if present +hash stdbuf 2>/dev/null && std_buf="stdbuf -oL" || std_buf="" # ****************************************************************************** # Check for run-time dependencies @@ -561,7 +593,7 @@ # ************************************************************************* # Required Dependencies # ************************************************************************* - core="grep sed md5sum mplayer mencoder mplex mpeg2enc yuvfps yuvdenoise ppmtoy4m mp2enc jpeg2yuv ffmpeg" + core="grep sed md5sum mplayer mplex mpeg2enc yuvfps yuvdenoise ppmtoy4m mp2enc jpeg2yuv" # ************************************************************************* # Optional Dependencies @@ -596,9 +628,13 @@ # ------------------------------------------------------------------------- # todisc dependencies - todisc_deps="$magick mogrify spumux dvdauthor transcode sox" + todisc_deps="$magick mogrify spumux dvdauthor sox" # Quit and complain if ANY core dependency is missing. assert_dep "$core" "You are missing CORE tovid dependencies!" + # ffmpeg is also a part of core deps, but is taken care of here + ffmpeg_alts="Use either ffmpeg (ffmpeg.org) or avconv (libav.org)." + ffmpeg_pref="Set choice in ${USER_PREFS}. As in: TOVID_FFMPEG=ffmpeg" + assert_dep $FFmpeg "You are missing $FFmpeg ! $ffmpeg_alts ${ffmpeg_pref}." # End tovid-init
View file
tovid-0.34.tar.bz2/src/tovid.ini -> tovid-0.35.tar.gz/src/tovid.ini
Changed
@@ -17,6 +17,10 @@ ; command, you can specify one or more "default" options that will always be ; passed to the 'tovid' script when used with that command. ; +; Note that in the [gui] section you should use only boolean options as others +; may have trouble loading, particularly options that 'optionally' take args or +; optionally take one or many args +; ; You can include all your desired default options on a single line, like this: ; ; [mpg] @@ -69,30 +73,6 @@ ; -device /dev/hdb ; -speed 8 -[menu] -options = -; -dvd -; -align center -; -textcolor #FF0000 -; -overwrite - -[vcd] -options = -; -device /dev/hdb -; -speed 24 -; -quiet - -[xml] -options = -; -overwrite -; -quiet -; -nochapters - -[postproc] -options = -; -parallel -; -normalize - [disc] options = ; -thumb-shape plectrum @@ -112,5 +92,9 @@ [gui] options = - +; -no-ask +; -no-warn +; -no-confirm-backup +; -ffmpeg +; -static
View file
tovid-0.34.tar.bz2/tovidgui.desktop -> tovid-0.35.tar.gz/tovidgui.desktop
Changed
@@ -4,10 +4,10 @@ Exec=tovid gui Icon=tovid Terminal=false -GenericName=DVD creation with menus -GenericName[en_US]=DVD creation with menus -Comment=Author videos to DVD with menus -Comment[en_US]=Author videos to DVD with menus +GenericName=DVD creation with optional menus +GenericName[en_US]=DVD creation with optional menus +Comment=Author videos to DVD with optional menus +Comment[en_US]=Author videos to DVD with optional menus Categories=AudioVideo;Video; StartupNotify=true X-KDE-SubstituteUID=false
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.