Initial commit
authorHarishankar <hari@harishankar.(none)>
Thu, 26 Feb 2009 16:59:04 +0000 (22:29 +0530)
committerHarishankar <hari@harishankar.(none)>
Thu, 26 Feb 2009 16:59:04 +0000 (22:29 +0530)
25 files changed:
MANIFEST [new file with mode: 0644]
audiocodecdialogs.py [new file with mode: 0644]
audiocodecdialogs.pyc [new file with mode: 0644]
biamove.py [new file with mode: 0755]
dist/BiaMovE-0.1.tar.gz [new file with mode: 0644]
dist/BiaMovE-0.1.win32.exe [new file with mode: 0644]
dist/BiaMovE-0.1.win32.exe.zip [new file with mode: 0644]
dist/BiaMovE-0.2.tar.gz [new file with mode: 0644]
dist/BiaMovE-0.2.win32.exe [new file with mode: 0644]
doc/biamove-doc.docbook [new file with mode: 0644]
doc/biamove-doc.html [new file with mode: 0644]
doc/biamove-doc.pdf [new file with mode: 0644]
mainwindow.py [new file with mode: 0644]
mainwindow.pyc [new file with mode: 0644]
miscdialogs.py [new file with mode: 0644]
miscdialogs.pyc [new file with mode: 0644]
sample.avi [new file with mode: 0644]
screens/biamove-main.jpg [new file with mode: 0644]
setup.py [new file with mode: 0644]
videocodecdialogs.py [new file with mode: 0644]
videocodecdialogs.pyc [new file with mode: 0644]
videofilterdialogs.py [new file with mode: 0644]
videofilterdialogs.pyc [new file with mode: 0644]
videomuxerdialogs.py [new file with mode: 0644]
videomuxerdialogs.pyc [new file with mode: 0644]

diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..00ec0c4
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,8 @@
+audiocodecdialogs.py
+biamove.py
+mainwindow.py
+miscdialogs.py
+setup.py
+videocodecdialogs.py
+videofilterdialogs.py
+videomuxerdialogs.py
diff --git a/audiocodecdialogs.py b/audiocodecdialogs.py
new file mode 100644 (file)
index 0000000..3533cd5
--- /dev/null
@@ -0,0 +1,169 @@
+# audio codec dialogs for the BiaMovE application
+
+import Tkinter
+import tkFileDialog
+import tkSimpleDialog
+import tkMessageBox
+
+class FAACDialog (tkSimpleDialog.Dialog):
+       """ FAAC audio codec options dialog"""
+       
+       def apply (self):
+               self.result = "-faacopts "
+               if self.bitrateorqualityflag.get() == "bitrateflag":
+                       self.result += "br=" + self.bitrate.get()
+               else:
+                       self.result += "quality=" + self.quality.get()
+               self.result += ":object=" + self.objecttype.get().split()[0] + ":mpeg=" + self.mpegversion.get()
+               
+       def body (self, master):
+               Tkinter.Label (master, text="FAAC audio encoding options (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=2)
+               
+               self.bitrateorqualityflag = Tkinter.StringVar ()
+               self.bitrateorqualityflag.set ("bitrateflag")
+               
+               Tkinter.Radiobutton (master, variable=self.bitrateorqualityflag, text="Use bitrate", value="bitrateflag").grid (column=0, row=1)
+               Tkinter.Radiobutton (master, variable=self.bitrateorqualityflag, text="Use quality", value="qualityflag").grid (column=1, row=1)
+               
+               Tkinter.Label (master, text="Bitrate").grid (column=0, row=2)
+               
+               self.bitrate = Tkinter.StringVar ()
+               self.bitrate.set (64)
+               Tkinter.Spinbox (master, textvariable=self.bitrate, from_=0, to=1024).grid (column=1, row=2)
+               
+               Tkinter.Label (master, text="Quality (1 to 1000)").grid (column=0, row=3)
+               
+               self.quality = Tkinter.StringVar ()
+               self.quality.set (500)
+               Tkinter.Spinbox (master, textvariable=self.quality, from_=1, to=1000).grid (column=1, row=3)
+               
+               Tkinter.Label (master, text="Object type complexity").grid (column=0, row=4)
+               
+               self.objecttype = Tkinter.StringVar ()
+               self.objecttype.set ("1   MAIN (default)")
+               Tkinter.OptionMenu (master, self.objecttype, "1   MAIN (default)", "2   LOW", "3   SSR", "4   LTP (extremely slow)").grid (column=1, row=4)
+               
+               Tkinter.Label (master, text="MPEG version").grid (column=0, row=5)
+               
+               self.mpegversion = Tkinter.StringVar ()
+               self.mpegversion.set ("4")
+               Tkinter.OptionMenu (master, self.mpegversion, "2", "4").grid (column=1, row=5)
+
+class TwolameDialog (tkSimpleDialog.Dialog):
+       """ Twolame audio codec options dialog"""
+       
+       def apply (self):
+               self.result = "-twolameopts "
+               self.result += "br=" + self.bitrate.get()
+               if self.variability.get() != "0":
+                       self.result += ":vbr=" + self.variability.get() + ":maxvbr=" + self.maxbitrate.get()
+               self.result += ":mode=" + self.mode.get()
+       
+       def body(self, master):
+               Tkinter.Label (master, text="Twolame audio encoding options (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=2)
+               Tkinter.Label (master, text="Bitrate variability range (-50 to 50, 0 for CBR)").grid (column=0, row=1)
+               
+               self.variability = Tkinter.StringVar ()
+               self.variability.set (0)
+               Tkinter.Spinbox (master, textvariable = self.variability, from_=-50, to=50).grid (column=1, row=1)
+               
+               Tkinter.Label (master, text="Bitrate (min rate for VBR) (32 to 384)").grid (column=0, row=2)
+               
+               self.bitrate = Tkinter.StringVar ()
+               self.bitrate.set (128)
+               Tkinter.Spinbox (master, textvariable = self.bitrate, from_=32, to=384).grid (column=1, row=2)
+               
+               Tkinter.Label (master, text="Max bitrate (VBR only) (32 to 384)").grid (column=0, row=3)
+               
+               self.maxbitrate = Tkinter.StringVar ()
+               self.maxbitrate.set (192)
+               Tkinter.Spinbox (master, textvariable = self.maxbitrate, from_=32, to=384).grid (column=1, row=3)
+               
+               Tkinter.Label (master, text="Mode").grid (column=0, row=4)
+               
+               self.mode = Tkinter.StringVar ()
+               self.mode.set ("stereo")
+               Tkinter.OptionMenu (master, self.mode, "stereo", "jstereo", "mono", "dual").grid (column=1, row=4)
+
+class LAMEDialog (tkSimpleDialog.Dialog):
+       """LAME Audio codec options dialog"""
+       def apply (self):
+               self.result = "-lameopts "
+               if self.bitratemethod.get() == "vbr":
+                       self.result += "vbr=" + self.vbrmethod.get().split()[0]
+                       self.result += ":q=" + str (self.vbrquality.get())
+               else:
+                       self.result += self.bitratemethod.get() + ":br=" + str(self.bitrate.get())
+
+               self.result += ":vol=" + str(self.audiogain.get())
+               
+               if (self.audiomode.get() != "(auto)"):
+                       self.result += ":mode=" + self.audiomode.get().split()[0]
+       
+       def body (self, master):
+               Tkinter.Label (master, text="LAME audio encoding options (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=3)
+               
+               self.bitratemethod = Tkinter.StringVar ()
+               self.bitratemethod.set ("abr")
+               
+               bitratetypes = [ ("cbr", "Constant bitrate"), ("vbr", "Variable bitrate"), ("abr", "Average bitrate") ]
+               i = 0
+               for val, txt in bitratetypes:
+                       Tkinter.Radiobutton (master, variable=self.bitratemethod, text=txt, value=val).grid (column=i, row=1)
+                       i += 1
+                       
+               Tkinter.Label (master, text="Variable bitrate options", fg="darkblue").grid (column=0, row=2, columnspan=3, pady=10)
+               
+               Tkinter.Label (master, text="VBR Method").grid (column=0, row=3)
+                               
+               self.vbrmethod = Tkinter.StringVar ()
+               self.vbrmethod.set ("2   rh")
+               Tkinter.OptionMenu (master, self.vbrmethod, "0   cbr", "1   mt", "2   rh", "3   abr", "4   mtrh").grid (column=1, row=3)
+               
+               Tkinter.Label (master, text="VBR Quality (0-highest 9-lowest)").grid (column=0, row=4)
+               
+               self.vbrquality = Tkinter.StringVar ()
+               self.vbrquality.set (0)
+               Tkinter.Spinbox (master, textvariable=self.vbrquality, from_=0, to=9).grid (column=1, row=4)
+               
+               Tkinter.Label (master, text="Constant/average bitrate options", fg="darkblue").grid (column=0, row=5, columnspan=3, pady=10)
+               
+               Tkinter.Label (master, text="Bitrate (0 to 1024)").grid (column=0, row=6)
+               
+               self.bitrate = Tkinter.StringVar ()
+               self.bitrate.set (128)
+               Tkinter.Spinbox (master, textvariable=self.bitrate, from_=0, to=1024).grid (column=1, row=6)
+               
+               Tkinter.Label (master, text="General options", fg="darkblue").grid (column=0, row=7, columnspan=3, pady=10)
+               
+               Tkinter.Label (master, text="Audio input gain (0 to 10)").grid (column=0, row=8)
+               
+               self.audiogain = Tkinter.StringVar ()
+               self.audiogain. set (0)
+               Tkinter.Spinbox (master, textvariable = self.audiogain, from_=0, to=10).grid (column=1, row=8)
+               
+               Tkinter.Label (master, text="Mode").grid (column=0, row=9)
+               
+               self.audiomode = Tkinter.StringVar ()
+               self.audiomode.set ("(auto)")
+               Tkinter.OptionMenu (master, self.audiomode, "(auto)", "0   stereo", "1   joint-stereo", "2   dualchannel", "3   mono").grid (column=1, row=9)
+
+class LAVCAudioDialog (tkSimpleDialog.Dialog):
+       """LAVC Video codec options dialog"""
+       def apply (self):
+               self.result = "-lavcopts acodec=" + self.audiocodecopt.get().split ()[0] + ":abitrate=" + str (self.audiobitrate.get())
+       
+       def body (self, master):
+               Tkinter.Label (master, text="LAVC audio codec options (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=2)
+
+               Tkinter.Label (master, text="Audio codec to use").grid (column=0, row=1)
+
+               self.audiocodecopt = Tkinter.StringVar ()
+               self.audiocodecopt.set ("mp2   MPEG-1 audio layer 2 (MP2)")
+               Tkinter.OptionMenu (master, self.audiocodecopt, "ac3   Dolby Digital (AC-3)", "adpcm_ima_qt   Apple QuickTime", "adpcm_ima_wav   Microsoft/IBM WAVE", "adpcm_ima_dk3   Duck DK3", "adpcm_ima_dk4   Duck DK4", "adpcm_ima_ws   Westwood Studio", "adpcm_ima_smjpeg   SDL Motion JPEG", "adpcm_ms   Microsoft", "adpcm_4xm   4X Technologies", "adpcm_xa   Phillips Yellow Book CD-ROM eXtended Architecture", "adpcm_ea   Electronic Arts", "adpcm_ct   Creative 16->4-bit", "adpcm_swf   Adobe Shockwave Flash", "adpcm_yamaha   Yamaha", "adpcm_sbpro_4   Creative VOC SoundBlaster Pro 8->4-bit", "adpcm_sbpro_3   Creative VOC SoundBlaster Pro 8->2.6-bit", "adpcm_sbpro_2   Creative VOC SoundBlaster Pro 8->2-bit", "adpcm_thp   Nintendo GameCube FMV THP", "adpcm_adx   Sega/CRI ADX", "flac   Free Lossless Audio Codec (FLAC)", "g726   G.726 ADPCM", "libamr_nb   3GPP Adaptive Multi-Rate (AMR) narrow-band", "libamr_wb   3GPP Adaptive Multi-Rate (AMR) wide-band", "libfaac   Advanced Audio Coding (AAC) - using FAAC", "libgsm   ETSI GSM 06.10 full rate", "libgsm_ms   Microsoft GSM", "libmp3lame   MPEG-1 audio layer 3 (MP3) - using LAME", "mp2   MPEG-1 audio layer 2 (MP2)", "roq_dpcm   Id Software RoQ DPCM", "sonic   experimental FFmpeg lossy codec", "sonicls   experimental FFmpeg lossless codec", "vorbis   Vorbis", "wmav1   Windows Media Audio v1", "wmav2   Windows Media Audio v2", "pcm_s32le   signed 32-bit little-endian", "pcm_s32be   signed 32-bit big-endian", "pcm_u32le   unsigned 32-bit little-endian", "pcm_u32be   unsigned 32-bit big-endian", "pcm_s24le   signed 24-bit little-endian", "pcm_s24be   signed 24-bit big-endian", "pcm_u24le   unsigned 24-bit little-endian", "pcm_u24be   unsigned 24-bit big-endian", "pcm_s16le   signed 16-bit little-endian", "pcm_s16be   signed 16-bit big-endian", "pcm_u16le   unsigned 16-bit little-endian", "pcm_u16be   unsigned 16-bit big-endian", "pcm_s8   signed 8-bit", "pcm_u8   unsigned 8-bit", "pcm_alaw   G.711 A-LAW", "pcm_mulaw   G.711 u-LAW", "pcm_s24daud   signed 24-bit D-Cinema Audio format", "pcm_zork   Activision Zork Nemesis").grid (column=1, row=1)
+               
+               Tkinter.Label (master, text="Audio bitrate").grid (column=0, row=2)
+               
+               self.audiobitrate = Tkinter.StringVar ()
+               self.audiobitrate.set (224)
+               Tkinter.Spinbox (master, textvariable=self.audiobitrate, from_=0, to=1024).grid (column=1, row=2)
diff --git a/audiocodecdialogs.pyc b/audiocodecdialogs.pyc
new file mode 100644 (file)
index 0000000..a0b2215
Binary files /dev/null and b/audiocodecdialogs.pyc differ
diff --git a/biamove.py b/biamove.py
new file mode 100755 (executable)
index 0000000..e1ad659
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+# main application launcher for the BiaMovE application
+
+from mainwindow import *
+
+def main ():
+       root = Tkinter.Tk ()
+       root.title ("BiaMovE - Video encoder GUI")
+       wnd = MainWindow (master=root)
+       wnd.mainloop ()
+
+if __name__ == "__main__":
+       main ()
diff --git a/dist/BiaMovE-0.1.tar.gz b/dist/BiaMovE-0.1.tar.gz
new file mode 100644 (file)
index 0000000..91b86cd
Binary files /dev/null and b/dist/BiaMovE-0.1.tar.gz differ
diff --git a/dist/BiaMovE-0.1.win32.exe b/dist/BiaMovE-0.1.win32.exe
new file mode 100644 (file)
index 0000000..952d7d8
Binary files /dev/null and b/dist/BiaMovE-0.1.win32.exe differ
diff --git a/dist/BiaMovE-0.1.win32.exe.zip b/dist/BiaMovE-0.1.win32.exe.zip
new file mode 100644 (file)
index 0000000..a99b8ce
Binary files /dev/null and b/dist/BiaMovE-0.1.win32.exe.zip differ
diff --git a/dist/BiaMovE-0.2.tar.gz b/dist/BiaMovE-0.2.tar.gz
new file mode 100644 (file)
index 0000000..121b390
Binary files /dev/null and b/dist/BiaMovE-0.2.tar.gz differ
diff --git a/dist/BiaMovE-0.2.win32.exe b/dist/BiaMovE-0.2.win32.exe
new file mode 100644 (file)
index 0000000..9c573e6
Binary files /dev/null and b/dist/BiaMovE-0.2.win32.exe differ
diff --git a/doc/biamove-doc.docbook b/doc/biamove-doc.docbook
new file mode 100644 (file)
index 0000000..174f35e
--- /dev/null
@@ -0,0 +1,94 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.5//EN" 
+[<!ENTITY bia "<application>BiaMovE</application>">
+<!ENTITY author "Harishankar">
+<!ENTITY menc "<application>Mencoder</application>">
+<!ENTITY ffmpeg "<application>FFMpeg</application>">]>
+<Book>
+       <title>&bia; documentation</title>
+       <bookinfo>
+               <author>
+                       <firstname>&author;</firstname>
+                       <surname>V</surname>
+               </author>
+               <abstract>
+                       <para>A short guide to video encoding using &bia; (via &menc;)</para>
+               </abstract>
+       </bookinfo>
+       <chapter id="intro">
+               <title>Introduction</title>
+               <para>
+                       &bia; (pronounced "by-a-movie") is a graphical user interface to <ulink url="http://www.mplayerhq.hu/">&menc;</ulink>, an extremely powerful and versatile cross-platform video encoding command-line utility. The problem with &menc; is that it is very complex and non-trivial to lay users.
+               </para>
+               <para>
+                       Adding to the complexity is the existence/non-existence of video/audio codecs, proprietary technologies and technical terminology related to audio and video. I had a very difficult time poring over the &menc; documentation to find specific options so I decided that while I was learning how to use it, why not create a GUI front-end for it?
+               </para>
+               <sect1 id="why">
+                       <title>Why &menc;</title>
+                       <para>
+                               Why &menc; and why not &ffmpeg;? Well, for one, &menc; can wrap around &ffmpeg; libraries using <filename>libavcodec</filename>. Secondly I found using the &ffmpeg; command line much easier than &menc; and felt that it would be better to write a GUI around &menc; instead.
+                       </para>
+               </sect1>
+               <sect1 id="philosophy">
+                       <title>Philosophy</title>
+                       <para>
+                               When I wrote &bia; I wanted to mainly explore the codec-specific options of &menc;. I did so because video/audio codecs are extremely complex creatures. I cannot pretend that I understood everything I read in the &menc; manual pages. With &bia; I've tried to hide a little bit of the complexity, but without restricting the advanced user.
+                       </para>
+                       <para>
+                               &bia; is not a tool for the newbie though. It is just a thin (albeit useful) GUI wrapper to &menc;. It does <emphasis>not</emphasis>:
+                               <itemizedlist>
+                                       <listitem><para>Check for the sanity of your &menc; configuration, nor does it check for codec availability on your setup.</para></listitem>
+                                       <listitem><para>Does not verify the sanity of your options. It just passes on your choices to the underlying &menc; command line.</para></listitem>
+                               </itemizedlist>
+                       </para>
+                       <para>
+                               Along the way, I've been bumbling along, discovering by trial and error, by experimentation and research, the proper way to mix video and audio codecs and produce valid video streams. If you are a newbie to video encoding and want to learn more, I suggest your read the section on <link linkend="videobasics">video encoding basics</link> and also study the &menc; manual pages in depth.
+                       </para>
+               </sect1>
+       </chapter>
+       <chapter id="videobasics">
+               <title>Video encoding basics</title>
+               <para>
+                       Before you jump into video encoding, it's useful to understand a few video (and audio) related concepts. This will help you exploit the full power of &bia; and &menc;. While most of the information here is common knowledge, I've documented some of my thoughts and discoveries in an easily accessible manner. However, before you dive in, I suggest you read the <link linkend="concepts">concepts</link> section for definitions to common terms specific to digital audio/video technologies.
+               </para>
+               <para>
+                       If you are of the "just want to rip my DVDs to my iPod" type, feel free to skip this section.
+               </para>
+               <sect1 id="theproblems">
+                       <title>The problems</title>
+                       <para>
+                               For most people simply using a command-line tool like &menc; can be a daunting task. The &menc; manual page alone is scary enough, because it documents both the player <application>MPlayer</application> as well as the encoder.
+                       </para>
+                       <para>
+                               Apart from the command-line itself, video and audio codecs are complex and tricky subjects in themselves. Apart from the variety of standards and formats adopted by different organizations (for instance, <abbrev>MPEG-4</abbrev>, <abbrev>H.264</abbrev>, <acronym>DivX</acronym>, <acronym>XViD</acronym> etc.), there exists hundreds of specifications within even these formats. Worse still, many of these standards are not compatible with each other and many video players, particularly hardware players, do not recognize open standards codecs (the <trademark class="trade">Apple iPod</trademark> is a case in point).
+                       </para>
+                       <para>
+                               Complicating it is the fact that not all muxers (container formats) work with all codecs and not all video and audio codecs are compatible with each other. Again, certain codecs provide very sane default parameters while other codecs require to be told exactly how to encode the underlying data. Last, but not least, some codecs are plain buggy and broken or don't work very well with &menc;.
+                       </para>
+                       <para>
+                               &bia; cannot overcome these problems for you for the reasons already mentioned earlier. However reading these notes should help you avoid some of the pitfalls.
+                       </para>
+               </sect1>
+               <sect1 id="concepts">
+                       <title>Concepts</title>
+                       <sect2 id="bitrate">
+                               <title>Bitrate</title>
+                               <para>
+                                       Bitrate is the number of bits which encode the information per unit of time. It is usually measured in kilobits per second (kbit/s) or megabits per second (mbit/s). In practical terms, higher the bitrate, higher the quality of the information stored (whether video or audio).
+                               </para>
+                               <para>
+                                       The best bitrate depends on several factors including desired video/audio quality versus size trade-off, the resolution of the video as well as the number of frames per second.
+                               </para>
+                       </sect2>
+                       <sect2 id="framerate">
+                               <title>Framerate</title>
+                               <para>
+                                       Framerate is the number of frames per unit time. Frames may be audio or video frames. Think of a single frame as a still. Over the years, different video standards (<acronym>PAL</acronym>, <abbrev>NTSC</abbrev> etc.) have evolved and use standard framerates (24.997 fps, 25 fps, 29.997 fps, 30 fps etc.) but theoritically any video can have any framerate or even variable framerates.
+                               </para>
+                               <para>
+                                       The higher the framerate, smoother the animation. Usually 25 to 30 fps is more than enough for the human eye.
+                               </para>
+                       </sect2>
+               </sect1>
+       </chapter>
+
+</Book>
\ No newline at end of file
diff --git a/doc/biamove-doc.html b/doc/biamove-doc.html
new file mode 100644 (file)
index 0000000..fbd2a53
--- /dev/null
@@ -0,0 +1,376 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>BiaMovE documentation</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"></HEAD
+><BODY
+CLASS="BOOK"
+><DIV
+CLASS="BOOK"
+><A
+NAME="AEN1"
+></A
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="AEN1"
+><SPAN
+CLASS="APPLICATION"
+>BiaMovE</SPAN
+> documentation</A
+></H1
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN5"
+></A
+>Harishankar V</H3
+><DIV
+><DIV
+CLASS="ABSTRACT"
+><P
+></P
+><A
+NAME="AEN8"
+></A
+><P
+>A short guide to video encoding using <SPAN
+CLASS="APPLICATION"
+>BiaMovE</SPAN
+> (via <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+>)</P
+><P
+></P
+></DIV
+></DIV
+><HR></DIV
+><DIV
+CLASS="TOC"
+><DL
+><DT
+><B
+>Table of Contents</B
+></DT
+><DT
+>1. <A
+HREF="#INTRO"
+>Introduction</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#WHY"
+>Why <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+></A
+></DT
+><DT
+><A
+HREF="#PHILOSOPHY"
+>Philosophy</A
+></DT
+></DL
+></DD
+><DT
+>2. <A
+HREF="#VIDEOBASICS"
+>Video encoding basics</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#THEPROBLEMS"
+>The problems</A
+></DT
+><DT
+><A
+HREF="#CONCEPTS"
+>Concepts</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#BITRATE"
+>Bitrate</A
+></DT
+><DT
+><A
+HREF="#FRAMERATE"
+>Framerate</A
+></DT
+></DL
+></DD
+></DL
+></DD
+></DL
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="INTRO"
+></A
+>Chapter 1. Introduction</H1
+><P
+>                      <SPAN
+CLASS="APPLICATION"
+>BiaMovE</SPAN
+> (pronounced "by-a-movie") is a graphical user interface to <A
+HREF="http://www.mplayerhq.hu/"
+TARGET="_top"
+><SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+></A
+>, an extremely powerful and versatile cross-platform video encoding command-line utility. The problem with <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> is that it is very complex and non-trivial to lay users.
+               </P
+><P
+>                      Adding to the complexity is the existence/non-existence of video/audio codecs, proprietary technologies and technical terminology related to audio and video. I had a very difficult time poring over the <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> documentation to find specific options so I decided that while I was learning how to use it, why not create a GUI front-end for it?
+               </P
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="WHY"
+>Why <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+></A
+></H2
+><P
+>                              Why <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> and why not <SPAN
+CLASS="APPLICATION"
+>FFMpeg</SPAN
+>? Well, for one, <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> can wrap around <SPAN
+CLASS="APPLICATION"
+>FFMpeg</SPAN
+> libraries using <TT
+CLASS="FILENAME"
+>libavcodec</TT
+>. Secondly I found using the <SPAN
+CLASS="APPLICATION"
+>FFMpeg</SPAN
+> command line much easier than <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> and felt that it would be better to write a GUI around <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> instead.
+                       </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="PHILOSOPHY"
+>Philosophy</A
+></H2
+><P
+>                              When I wrote <SPAN
+CLASS="APPLICATION"
+>BiaMovE</SPAN
+> I wanted to mainly explore the codec-specific options of <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+>. I did so because video/audio codecs are extremely complex creatures. I cannot pretend that I understood everything I read in the <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> manual pages. With <SPAN
+CLASS="APPLICATION"
+>BiaMovE</SPAN
+> I've tried to hide a little bit of the complexity, but without restricting the advanced user.
+                       </P
+><P
+>                              <SPAN
+CLASS="APPLICATION"
+>BiaMovE</SPAN
+> is not a tool for the newbie though. It is just a thin (albeit useful) GUI wrapper to <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+>. It does <SPAN
+CLASS="emphasis"
+><I
+CLASS="EMPHASIS"
+>not</I
+></SPAN
+>:
+                               <P
+></P
+><UL
+><LI
+><P
+>Check for the sanity of your <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> configuration, nor does it check for codec availability on your setup.</P
+></LI
+><LI
+><P
+>Does not verify the sanity of your options. It just passes on your choices to the underlying <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> command line.</P
+></LI
+></UL
+>
+                       </P
+><P
+>                              Along the way, I've been bumbling along, discovering by trial and error, by experimentation and research, the proper way to mix video and audio codecs and produce valid video streams. If you are a newbie to video encoding and want to learn more, I suggest your read the section on <A
+HREF="#VIDEOBASICS"
+>video encoding basics</A
+> and also study the <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> manual pages in depth.
+                       </P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="VIDEOBASICS"
+></A
+>Chapter 2. Video encoding basics</H1
+><P
+>                      Before you jump into video encoding, it's useful to understand a few video (and audio) related concepts. This will help you exploit the full power of <SPAN
+CLASS="APPLICATION"
+>BiaMovE</SPAN
+> and <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+>. While most of the information here is common knowledge, I've documented some of my thoughts and discoveries in an easily accessible manner. However, before you dive in, I suggest you read the <A
+HREF="#CONCEPTS"
+>concepts</A
+> section for definitions to common terms specific to digital audio/video technologies.
+               </P
+><P
+>                      If you are of the "just want to rip my DVDs to my iPod" type, feel free to skip this section.
+               </P
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="THEPROBLEMS"
+>The problems</A
+></H2
+><P
+>                              For most people simply using a command-line tool like <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> can be a daunting task. The <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+> manual page alone is scary enough, because it documents both the player <SPAN
+CLASS="APPLICATION"
+>MPlayer</SPAN
+> as well as the encoder.
+                       </P
+><P
+>                              Apart from the command-line itself, video and audio codecs are complex and tricky subjects in themselves. Apart from the variety of standards and formats adopted by different organizations (for instance, <ABBR
+CLASS="ABBREV"
+>MPEG-4</ABBR
+>, <ABBR
+CLASS="ABBREV"
+>H.264</ABBR
+>, <ACRONYM
+CLASS="ACRONYM"
+>DivX</ACRONYM
+>, <ACRONYM
+CLASS="ACRONYM"
+>XViD</ACRONYM
+> etc.), there exists hundreds of specifications within even these formats. Worse still, many of these standards are not compatible with each other and many video players, particularly hardware players, do not recognize open standards codecs (the <SPAN
+CLASS="TRADEMARK"
+>Apple iPod</SPAN
+>&#8482; is a case in point).
+                       </P
+><P
+>                              Complicating it is the fact that not all muxers (container formats) work with all codecs and not all video and audio codecs are compatible with each other. Again, certain codecs provide very sane default parameters while other codecs require to be told exactly how to encode the underlying data. Last, but not least, some codecs are plain buggy and broken or don't work very well with <SPAN
+CLASS="APPLICATION"
+>Mencoder</SPAN
+>.
+                       </P
+><P
+>                              <SPAN
+CLASS="APPLICATION"
+>BiaMovE</SPAN
+> cannot overcome these problems for you for the reasons already mentioned earlier. However reading these notes should help you avoid some of the pitfalls.
+                       </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="CONCEPTS"
+>Concepts</A
+></H2
+><DIV
+CLASS="SECT2"
+><H3
+CLASS="SECT2"
+><A
+NAME="BITRATE"
+>Bitrate</A
+></H3
+><P
+>                                      Bitrate is the number of bits which encode the information per unit of time. It is usually measured in kilobits per second (kbit/s) or megabits per second (mbit/s). In practical terms, higher the bitrate, higher the quality of the information stored (whether video or audio).
+                               </P
+><P
+>                                      The best bitrate depends on several factors including desired video/audio quality versus size trade-off, the resolution of the video as well as the number of frames per second.
+                               </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="FRAMERATE"
+>Framerate</A
+></H3
+><P
+>                                      Framerate is the number of frames per unit time. Frames may be audio or video frames. Think of a single frame as a still. Over the years, different video standards (<ACRONYM
+CLASS="ACRONYM"
+>PAL</ACRONYM
+>, <ABBR
+CLASS="ABBREV"
+>NTSC</ABBR
+> etc.) have evolved and use standard framerates (24.997 fps, 25 fps, 29.997 fps, 30 fps etc.) but theoritically any video can have any framerate or even variable framerates.
+                               </P
+><P
+>                                      The higher the framerate, smoother the animation. Usually 25 to 30 fps is more than enough for the human eye.
+                               </P
+></DIV
+></DIV
+></DIV
+></DIV
+></BODY
+></HTML
+>
\ No newline at end of file
diff --git a/doc/biamove-doc.pdf b/doc/biamove-doc.pdf
new file mode 100644 (file)
index 0000000..90bb212
Binary files /dev/null and b/doc/biamove-doc.pdf differ
diff --git a/mainwindow.py b/mainwindow.py
new file mode 100644 (file)
index 0000000..f696d69
--- /dev/null
@@ -0,0 +1,327 @@
+# Main Window class for the BiaMovE application
+
+import Tkinter
+import tkFileDialog
+import tkSimpleDialog
+import tkMessageBox
+import os
+import os.path
+import subprocess
+import sys
+import ConfigParser as CP
+
+# import all the dialog classes
+from audiocodecdialogs import *
+from videofilterdialogs import *
+from videocodecdialogs import *
+from videomuxerdialogs import *
+from miscdialogs import *
+
+class MainWindow (Tkinter.Frame):
+       """The main window class of the BiaMovE application"""
+       def on_misc_options (self):
+               """ Called when the misc options button is clicked"""
+               miscdlg = MiscOptionsDialog (self)
+               if miscdlg.result != None:
+                       self.otherparameters.set (miscdlg.result)
+               
+       def on_videofilters (self):
+               """Called when the video filters button is clicked"""
+               if self.outputvideo.get().split()[0] == "copy":
+                       tkMessageBox.showinfo ("Video filters", "You cannot apply filters when the video stream is directly copied. Change the video codec.")
+               else:
+                       filtersdlg = VideoFiltersDialog (self)
+                       if filtersdlg.result != None:
+                               self.videofilters.set (filtersdlg.result)
+       
+       def build_mencoder_command (self):
+               """ To build the mencoder command """
+               
+               # mencoder command line
+               commandlist = ["mencoder",]
+               
+               # dvd options (if present)
+               for item in self.dvdopts.get().split():
+                       commandlist.append (item)
+                       
+               # output format
+               commandlist.append ("-of")
+               commandlist.append (self.outputcontainer.get().split()[0])
+               
+               for item in self.outputcontaineropts.get().split():
+                       commandlist.append (item)
+               
+               # video codec
+               commandlist.append ("-ovc")
+               commandlist.append (self.outputvideo.get().split()[0])
+               
+               for item in self.videoopts.get().split():
+                       commandlist.append (item)
+               
+               # audio codec
+               commandlist.append ("-oac")
+               commandlist.append (self.outputaudio.get().split()[0])
+               
+               for item in self.audioopts.get().split():
+                       commandlist.append (item)
+                       
+               # video filters
+               if self.videofilters.get().strip() != "":
+                       commandlist.append ("-vf")
+                       commandlist.append (self.videofilters.get().strip())
+               
+               # misc options
+               for item in self.otherparameters.get().split():
+                       commandlist.append (item)
+                       
+               # input file
+               commandlist.append (self.inputfile.get())
+               
+               # output file
+               commandlist.append ("-o")
+               commandlist.append (self.outputfile.get())
+                       
+               return commandlist
+       
+       def on_encode (self):
+               """Called when the encode button is clicked"""
+               if self.inputfile.get().strip() == "" or self.outputfile.get().strip() == "":
+                       tkMessageBox.showerror ("Cannot encode", "No input and/or output file specified")
+               else:
+                       commandlist = self.build_mencoder_command ()
+                       
+                       if tkMessageBox.askyesno ("Confirm", "Are you sure you wish to encode (in *NIX you must have TERM environment variable set)?"):
+                               if sys.platform.startswith ('win'):
+                                       po, pi = os.popen2 ("cmd /K " + subprocess.list2cmdline (commandlist))
+                               else:
+                                       if "TERM" in os.environ:
+                                               if os.environ["TERM"] == "xterm":
+                                                       term_command = os.environ["TERM"] + " -hold -e " + subprocess.list2cmdline (commandlist)
+                                               else:
+                                                       term_command = os.environ["TERM"] + " -e " + subprocess.list2cmdline(commandlist)
+                                               po, pi = os.popen2 (term_command)
+                                       else:
+                                               tkMessageBox.showerror ("Cannot encode", "The TERM environment variable is not set. Cannot find a suitable terminal.")
+                               
+       def on_save_profile (self):
+               """ Called when the save profile button is clicked"""
+               profile_name = tkSimpleDialog.askstring ("Save profile", "Give a name for this profile")
+               if profile_name != None:
+                       config = CP.SafeConfigParser ()
+                       
+                       cfgfile = os.path.join (os.path.expanduser ("~"), ".biamoverc")
+                       
+                       config.read ( cfgfile )
+                       if (config.has_section (profile_name)):
+                               if not tkMessageBox.askyesno ("Section exists", "This section exists. Do you wish to overwrite the settings?"):
+                                       return
+                       else:
+                               config.add_section (profile_name)
+       
+                       config.set (profile_name, "ContainerFormat", self.outputcontainer.get())
+                       config.set (profile_name, "VideoCodec", self.outputvideo.get())
+                       config.set (profile_name, "AudioCodec", self.outputaudio.get())
+                       config.set (profile_name, "ContainerParameters", self.outputcontaineropts.get())
+                       config.set (profile_name, "VideoParameters", self.videoopts.get())
+                       config.set (profile_name, "AudioParameters", self.audioopts.get())
+                       config.set (profile_name, "VideoFilters", self.videofilters.get())
+                       config.set (profile_name, "OtherParameters", self.otherparameters.get())
+                                               
+                       config.write (file (cfgfile, "w"))
+       
+       def on_load_profile (self):
+               """ Called when the load profile button is clicked"""
+               loaddlg = ProfileLoadDialog (self)
+               sect = loaddlg.result
+               if sect != None:
+                       config = CP.SafeConfigParser ()
+                       cfgfile = os.path.join (os.path.expanduser("~"), ".biamoverc")
+                       config.read (cfgfile)
+                       
+                       if (config.has_section (sect)):
+                               self.outputcontainer.set (config.get (sect, "ContainerFormat"))
+                               self.outputvideo.set (config.get (sect, "VideoCodec"))
+                               self.outputaudio.set (config.get (sect, "AudioCodec"))
+                               self.outputcontaineropts.set (config.get (sect, "ContainerParameters"))
+                               self.videoopts.set (config.get (sect, "VideoParameters"))
+                               self.audioopts.set (config.get (sect, "AudioParameters"))
+                               self.videofilters.set (config.get (sect, "VideoFilters"))
+                               self.otherparameters.set (config.get (sect, "OtherParameters"))
+
+       def on_container_options (self):
+               """ Called when the container options button is clicked"""
+               containerfmt = self.outputcontainer.get().split()[0]
+               if (containerfmt == "lavf"):
+                       lavfdlg = LAVFMuxerDialog (self)
+                       if lavfdlg.result != None:
+                               self.outputcontaineropts.set (lavfdlg.result)
+               elif (containerfmt == "mpeg"):
+                       mpegdlg = MPEGMuxerDialog (self)
+                       if mpegdlg.result != None:
+                               self.outputcontaineropts.set (mpegdlg.result)
+               else:
+                       tkMessageBox.showinfo ("Muxer options","No options for this muxer or options not implemented yet")
+                       self.outputcontaineropts.set ("")
+       
+       def on_codec_video (self):
+               """ Called when the video codec options button is clicked"""
+               videocodec = self.outputvideo.get().split()[0]
+               if (videocodec == "nuv"):
+                       nuvdlg = NUVDialog (self)
+                       if nuvdlg.result != None:
+                               self.videoopts.set (nuvdlg.result)
+               elif (videocodec == "lavc"):
+                       lavcdlg = LAVCVideoDialog (self)
+                       if lavcdlg.result != None:
+                               self.videoopts.set (lavcdlg.result)
+               elif (videocodec == "xvid"):
+                       xviddlg = XvidEncDialog (self)
+                       if xviddlg.result != None:
+                               self.videoopts.set (xviddlg.result)
+               elif (videocodec == "x264"):
+                       x264dlg = X264EncDialog (self)
+                       if x264dlg.result != None:
+                               self.videoopts.set (x264dlg.result)
+               else:
+                       tkMessageBox.showinfo ("Video options", "No options for this codec or options not implemented yet")
+                       self.videoopts.set ("")
+       
+       def on_codec_audio (self):
+               """ Called when the audio codec options button is clicked"""
+               
+               # if the output audio codec is lavc show the lavc codec dialog
+               audiocodec = self.outputaudio.get().split()[0]
+               if (audiocodec == "lavc"):
+                       lavcdlg = LAVCAudioDialog (self)
+                       if lavcdlg.result != None:
+                               self.audioopts.set (lavcdlg.result)
+               # if the output audio codec is lame show the lame codec dialog
+               elif (audiocodec == "mp3lame"):
+                       lamedlg = LAMEDialog (self)
+                       if lamedlg.result != None:
+                               self.audioopts.set (lamedlg.result)
+               elif (audiocodec == "twolame"):
+                       twolamedlg = TwolameDialog (self)
+                       if twolamedlg.result != None:
+                               self.audioopts.set (twolamedlg.result)
+               elif (audiocodec == "faac"):
+                       faacdlg = FAACDialog (self)
+                       if faacdlg.result != None:
+                               self.audioopts.set (faacdlg.result)
+               else:
+                       tkMessageBox.showinfo ("Audio options", "No options for this codec or options not implemented yet")
+                       self.audioopts.set ("")
+       
+       def on_input_browse (self):
+               """Called when the input browse button is clicked"""
+               infile = tkFileDialog.askopenfilename ()
+               if infile != None:
+                       self.inputfile.set (infile)
+       
+       def on_output_browse (self):
+               """ Called when the output browse button is clicked"""
+               outfile = tkFileDialog.asksaveasfilename ()
+               if outfile != None:
+                       self.outputfile.set (outfile)
+                       
+       def on_dvd_device (self):
+               """ called when the DVD options button is clicked"""
+               dvddlg = DVDDialog (self)
+               if dvddlg.result != None:
+                       self.inputfile.set (dvddlg.result)
+                       self.dvdopts.set (dvddlg.result_args)
+       
+       def create_widgets (self):
+               """ Called during __init__ """
+               Tkinter.Label (self, text="You need Mencoder installed (compiled with appropriate codecs) for this program to function properly. This program does NOT detect which codecs are available and which are not.", fg = "darkblue", wraplength=600).grid(column=0, row=0, columnspan=4)
+               
+               Tkinter.Label (self, text="Input file/source URL").grid (column=0, row=1)
+               
+               self.inputfile = Tkinter.StringVar ()
+               Tkinter.Entry (self, textvariable=self.inputfile).grid (column=1, row=1)
+               
+               Tkinter.Button (self, text="browse...", command=self.on_input_browse).grid (column=2, row=1)
+               
+               dvdframe = Tkinter.Frame (self)
+               
+               self.dvdopts = Tkinter.StringVar ()
+               
+               Tkinter.Button (dvdframe, text="DVD...", command=self.on_dvd_device).pack (side=Tkinter.LEFT)
+               Tkinter.Entry (dvdframe, textvariable=self.dvdopts).pack (side=Tkinter.RIGHT)
+               
+               dvdframe.grid (column=3, row=1, columnspan=2)
+               
+               Tkinter.Label (self, text="Output file").grid (column=0, row=2)
+               
+               self.outputfile = Tkinter.StringVar ()
+               Tkinter.Entry (self, textvariable=self.outputfile).grid (column=1, row=2)
+               
+               Tkinter.Button (self, text="browse...", command=self.on_output_browse).grid (column=2, row=2)
+               
+               Tkinter.Label (self, text="mencoder options", fg="darkblue").grid (column=0, row=3, pady=5, columnspan=4)
+               
+               Tkinter.Label (self, text="Output container format").grid (column=0, row=4)
+               
+               self.outputcontainer = Tkinter.StringVar()
+               self.outputcontainer.set ("avi   Microsoft AVI")
+               Tkinter.OptionMenu (self, self.outputcontainer, "avi   Microsoft AVI", "mpeg   MPEG 1/2 stream", "lavf   FFMPEG libavformat muxers", "rawvideo   Raw video (only) stream", "rawaudio   Raw audio (only) stream").grid (column=1, row=4)
+               
+               Tkinter.Button (self, text="Container options...", command=self.on_container_options).grid (column=2, row=4)
+               
+               self.outputcontaineropts = Tkinter.StringVar ()
+               Tkinter.Entry (self, textvariable=self.outputcontaineropts).grid (column=3, row=4)
+
+               Tkinter.Label (self, text="Output video codec").grid (column=0, row=5)
+
+               self.outputvideo = Tkinter.StringVar ()
+               self.outputvideo.set ("copy   Frames copy")
+               Tkinter.OptionMenu (self, self.outputvideo, "copy   Frames copy", "raw   Uncompressed video", "nuv   Nuppel video", "lavc   FFMPEG codecs ", "xvid   XviD encoding", "x264   H.264 encoding").grid (column=1, row=5)
+               
+               Tkinter.Button (self, text="codec options...", command=self.on_codec_video).grid (column=2, row=5)
+               
+               self.videoopts = Tkinter.StringVar ()
+               Tkinter.Entry (self, textvariable=self.videoopts).grid (column=3, row=5)
+               
+               Tkinter.Label (self, text="Output audio codec").grid (column=0, row=6)
+               
+               self.outputaudio = Tkinter.StringVar ()
+               self.outputaudio.set ("copy   Frames copy")
+               Tkinter.OptionMenu (self, self.outputaudio, "copy   Frames copy", "pcm   Uncompressed PCM", "mp3lame   MP3 using LAME", "lavc   FFMPEG codecs", "twolame   TwoLAME MP2", "faac   FAAC AAC Audio").grid (column=1, row=6)
+               
+               Tkinter.Button (self, text="codec options...", command = self.on_codec_audio).grid (column=2, row=6)
+               
+               self.audioopts = Tkinter.StringVar ()
+               Tkinter.Entry (self, textvariable = self.audioopts).grid (column=3, row=6)
+               
+               Tkinter.Label (self, text="Video filters").grid (column=0, row=7)
+               Tkinter.Button (self, text="setup filters...", command=self.on_videofilters).grid (column=1, row=7)
+               
+               self.videofilters = Tkinter.StringVar ()
+               Tkinter.Entry (self, textvariable=self.videofilters).grid (column=2, row=7)
+               
+               Tkinter.Label (self, text="Other Mencoder parameters").grid (column=0, row=8, pady=10)
+               
+               Tkinter.Button (self, text="Misc Options...", command=self.on_misc_options).grid (column=1, row=8)
+               
+               self.otherparameters = Tkinter.StringVar ()
+               Tkinter.Entry (self, textvariable=self.otherparameters).grid (column=2, row=8)
+               
+               Tkinter.Label (self, text="Save/Load Profile", fg="darkblue").grid (column=0, row=9, pady=5, columnspan=2)
+               
+               leftframe = Tkinter.Frame (self)
+               Tkinter.Button (leftframe, text="Save...", command=self.on_save_profile).pack (side=Tkinter.LEFT)
+               Tkinter.Button (leftframe, text="Load...", command=self.on_load_profile).pack (side=Tkinter.RIGHT)
+               leftframe.grid (column=0, row=10, columnspan=2)
+               
+               Tkinter.Label (self, text="Actions", fg="darkblue").grid (column=2, row=9, pady=5, columnspan=2)
+               
+               rightframe = Tkinter.Frame (self)
+               Tkinter.Button (rightframe, text="Encode", command=self.on_encode).pack (side=Tkinter.LEFT)
+               Tkinter.Button (rightframe, text="Quit", command=self.quit).pack (side=Tkinter.RIGHT)
+               rightframe.grid (column=2, row=10, columnspan=2)
+               
+       def __init__ (self, master=None):
+               Tkinter.Frame.__init__ (self, master)
+               
+               self.grid (padx=10,pady=10)
+               self.create_widgets ()
diff --git a/mainwindow.pyc b/mainwindow.pyc
new file mode 100644 (file)
index 0000000..6c7e9df
Binary files /dev/null and b/mainwindow.pyc differ
diff --git a/miscdialogs.py b/miscdialogs.py
new file mode 100644 (file)
index 0000000..6753dd3
--- /dev/null
@@ -0,0 +1,196 @@
+# Miscellaneous dialogs for the BiaMovE application
+
+import Tkinter
+import tkFileDialog
+import tkSimpleDialog
+import tkMessageBox
+import os.path
+import sys
+import ConfigParser as CP
+
+class DVDInfoDialog (tkSimpleDialog.Dialog):
+       """ Class to display the DVD information (works only on *NIX and only if the biadvdlister
+       executable program is installed """
+       def __init__ (self, master, dvddevice):
+               self.dvddevice = dvddevice
+               tkSimpleDialog.Dialog.__init__ (self, master, "DVD Information")
+       
+       def fill_info (self, master):
+               if self.dvddevice.strip() == "":
+                       self.dvddevice = "/dev/dvd"
+               
+               fi, fo, fe = os.popen3 ("biadvdlister --dvd-device " + self.dvddevice)
+               infos = fo.readlines ()
+               if infos == []:
+                       errors = fe.readlines ()
+                       i = 1
+                       for error in errors:
+                               Tkinter.Label (master, text=error.strip()).grid (column=0, row=i, columnspan=2)
+                               i += 1
+               else:
+                       r = 1
+                       c = 0
+                       for info in infos:
+                               rec = info.split ()
+                               for field in rec:
+                                       Tkinter.Label (master, text=field).grid (column=c, row=r)
+                                       c += 1
+                               r += 1
+                               c = 0
+       
+       def body (self, master):
+               Tkinter.Label (master, text="DVD information (you need the biadvdlister program installed for this feature)", fg="darkblue", wraplength=280).grid (column=0, row=0, columnspan=2)
+               
+               self.fill_info (master)
+
+class DVDDialog (tkSimpleDialog.Dialog):
+       """ Class to choose DVD device and set DVD options """
+       def apply (self):
+               self.result = "dvd://" + self.dvdtrack.get ()
+               
+               self.result_args = ""
+               if self.allchapters.get() == 0:
+                       self.result_args += " -chapter " + self.startchapter.get()
+                       if self.endchapter.get().strip () != "":
+                               self.result_args += "-" + self.endchapter.get()
+               if self.dvddevice.get().strip() != "":
+                       self.result_args += " -dvd-device " + self.dvddevice.get()
+               
+               self.result = self.result.strip ()
+               self.result_args = self.result_args.strip ()
+                       
+       def on_dvd_info (self):
+               if sys.platform.startswith ('win'):
+                       tkMessageBox.showerror ("Cannot show info", "The DVD information feature does not work on Windows")
+               else:
+                       dvdinfodlg = DVDInfoDialog (self, self.dvddevice.get())
+       
+       def body (self, master):
+               Tkinter.Label (master, text="DVD input options (see Misc Options for choosing subtitles/audio language)", fg="darkblue", wraplength=280).grid (column=0, row=0, columnspan=3)
+               
+               Tkinter.Label (master, text="Title/track #").grid (column=0, row=1)
+               
+               self.dvdtrack = Tkinter.StringVar ()
+               self.dvdtrack.set (1)
+               Tkinter.Entry (master, textvariable=self.dvdtrack).grid (column=1, row=1)
+               
+               Tkinter.Button (master, text="View DVD info...", command=self.on_dvd_info).grid (column=2, row=1)
+               
+               self.allchapters = Tkinter.IntVar ()
+               self.allchapters.set (1)
+               Tkinter.Checkbutton (master, variable=self.allchapters, text="Encode all chapters on track", onvalue=1, offvalue=0).grid (column=0, row=2, columnspan=2)
+               
+               Tkinter.Label (master, text="Start chapter #").grid (column=0, row=3)
+               
+               self.startchapter = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.startchapter).grid (column=1, row=3)
+               
+               Tkinter.Label (master, text="End chapter #").grid (column=0, row=4)
+               
+               self.endchapter = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.endchapter).grid (column=1, row=4)
+               
+               Tkinter.Label (master, text="DVD device (default: /dev/dvd)").grid (column=0, row=5)
+               
+               self.dvddevice = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.dvddevice).grid (column=1, row=5)
+               
+class MiscOptionsDialog (tkSimpleDialog.Dialog):
+       """ Class to configure miscellaneous mencoder specific options """
+       def apply (self):
+               self.result = ""
+               if self.startpos.get().strip() != "":
+                       self.result += "-ss " + self.startpos.get()
+               if self.endpos.get().strip() != "":
+                       self.result += " -endpos " + self.endpos.get()
+               if self.resamplerate.get().strip() != "":
+                       self.result += " -srate " + self.resamplerate.get()
+               if self.audiolang.get().strip() != "":
+                       self.result += " -alang " + self.audiolang.get()
+               if self.subtitlelang.get().strip() != "":
+                       self.result += " -slang " + self.subtitlelang.get()
+               if self.fourcc.get().strip() != "":
+                       self.result += " -ffourcc " + self.fourcc.get()
+                       
+               self.result = self.result.strip ()
+       
+       def body (self, master):
+               Tkinter.Label (master, text="Miscellaneous mencoder options (leave blank for defaults)", fg="darkblue").grid (column=0, row=0, columnspan=2)
+               
+               Tkinter.Label (master, text="Input stream options", fg="darkblue").grid (column=0, row=1, columnspan=3, pady=10)
+               
+               Tkinter.Label (master, text="Start encoding from (sec or hh:mm:ss)").grid (column=0, row=2)
+               
+               self.startpos = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.startpos).grid (column=1, row=2)
+               
+               Tkinter.Label (master, text="Stop encoding after (sec or hh:mm:ss or b/kb/mb)").grid (column=0, row=3)
+               self.endpos = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.endpos).grid (column=1, row=3)
+               
+               Tkinter.Label (master, text="Audio and subtitle (only if available) options", fg="darkblue").grid (column=0, row=4, columnspan=2, pady=10)
+               
+               Tkinter.Label (master, text="Resample audio (Hz)").grid (column=0, row=5)
+               
+               self.resamplerate = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.resamplerate).grid (column=1, row=5)           
+               
+               Tkinter.Label (master, text="Audio language (code)").grid (column=0, row=6)
+                               
+               self.audiolang = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.audiolang).grid (column=1, row=6)
+               
+               Tkinter.Label (master, text="Subtitle language (code)").grid (column=0, row=7)
+               
+               self.subtitlelang = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.subtitlelang).grid (column=1, row=7)
+               
+               Tkinter.Label (master, text="Advanced", fg="darkblue").grid (column=0, row=8, columnspan=2, pady=10)
+               
+               Tkinter.Label (master, text="Override video four character code").grid (column=0, row=9)
+               
+               self.fourcc = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.fourcc).grid (column=1, row=9)
+               
+class ProfileLoadDialog (tkSimpleDialog.Dialog):
+       """ Class to load a profile or simply delete existing profiles """
+       def apply (self):
+               self.result = self.conflist.get (Tkinter.ANCHOR)
+               if self.result.strip () == "":
+                       self.result = None
+
+       def load_profiles (self):
+               cfgfile = os.path.join (os.path.expanduser ("~"), ".biamoverc")
+               config = CP.SafeConfigParser ()
+               config.read (cfgfile)
+               
+               confsections = []
+               for section in config.sections ():
+                       self.conflist.insert (Tkinter.END, section)
+       
+       def on_delete_profile (self):
+               cfgfile = os.path.join (os.path.expanduser ("~"), ".biamoverc")
+               config = CP.SafeConfigParser ()
+               config.read (cfgfile)
+               
+               delsection = self.conflist.get (Tkinter.ANCHOR)
+               self.conflist.delete (Tkinter.ANCHOR)
+               
+               if (config.has_section (delsection)):
+                       config.remove_section (delsection)
+                       config.write (file (cfgfile, "w"))
+       
+       def body (self, master):
+               Tkinter.Label (master, text = "Load profile", fg="darkblue").grid (column=0, row=0, columnspan=2)
+               
+               frame = Tkinter.Frame(master)
+               scrollbar = Tkinter.Scrollbar(frame, orient=Tkinter.VERTICAL)
+               self.conflist = Tkinter.Listbox (frame, width=30, height=5, yscrollcommand=scrollbar.set)
+               scrollbar.config(command=self.conflist.yview)
+               scrollbar.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)
+               self.conflist.pack (side=Tkinter.LEFT, fill=Tkinter.BOTH)
+               frame.grid (column=0, row=1)
+               
+               Tkinter.Button (master, text="delete", command = self.on_delete_profile).grid (column=1, row=1)
+               
+               self.load_profiles ()
diff --git a/miscdialogs.pyc b/miscdialogs.pyc
new file mode 100644 (file)
index 0000000..654735c
Binary files /dev/null and b/miscdialogs.pyc differ
diff --git a/sample.avi b/sample.avi
new file mode 100644 (file)
index 0000000..1a7ef69
Binary files /dev/null and b/sample.avi differ
diff --git a/screens/biamove-main.jpg b/screens/biamove-main.jpg
new file mode 100644 (file)
index 0000000..44f8335
Binary files /dev/null and b/screens/biamove-main.jpg differ
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..8fc9064
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,15 @@
+# setup program for the BiaMovE application
+
+from distutils.core import setup
+
+setup ( name = "BiaMovE",
+       version = "0.2",
+       description = "BiaMovE - a mencoder graphical front-end written in Python/Tkinter",
+       keywords = "mencoder,gui,biamove,video encoding,video converting",
+       author = "V.Harishankar",
+       author_email = "v.harishankar@gmail.com",
+       license = "Licensed under the GNU/General Public License v3 (http://www.gnu.org/licenses/gpl.html)",
+       py_modules = [ "audiocodecdialogs", "videofilterdialogs", "videocodecdialogs", "videomuxerdialogs", "miscdialogs", "mainwindow" ],
+       scripts = [ "biamove.py" ],
+       platforms = [ "linux, windows" ]
+)
diff --git a/videocodecdialogs.py b/videocodecdialogs.py
new file mode 100644 (file)
index 0000000..d81e3dc
--- /dev/null
@@ -0,0 +1,264 @@
+# Video codec dialogs for the BiaMovE application
+
+import Tkinter
+import tkFileDialog
+import tkSimpleDialog
+import tkMessageBox
+
+class X264EncDialog (tkSimpleDialog.Dialog):
+       """H.264 video encoding options dialog"""
+       def apply (self):
+               self.result = "-x264encopts "
+               if (self.ratecontrolmode.get() == "abr"):
+                       self.result += "bitrate=" + self.bitrate.get() + ":qp_min=" + self.quantizermin.get() + ":qp_max=" +self.quantizermax.get()
+               elif (self.ratecontrolmode.get() == "qp"):
+                       self.result += "qp=" + self.quantizerfixed.get()
+               else:
+                       self.result += "crf=" + self.ratefactor.get()
+               self.result += ":subq=" + self.subpel.get().split()[0] + ":frameref=" + self.frameref.get()
+               
+               if self.cabac.get() == 0:
+                       self.result += ":nocabac"
+
+       def body (self, master):
+               Tkinter.Label (master, text="x264 video codec options (single pass only) (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=3)
+               
+               self.ratecontrolmode = Tkinter.StringVar ()
+               self.ratecontrolmode.set ("crf")
+               Tkinter.Radiobutton (master, variable=self.ratecontrolmode, text="Average bitrate mode", value="abr").grid (column=0, row=1)
+               Tkinter.Radiobutton (master, variable=self.ratecontrolmode, text="Fixed quantizer mode", value="qp").grid (column=0, row=4)
+               Tkinter.Radiobutton (master, variable=self.ratecontrolmode, text="Constant quality mode", value="crf").grid(column=0, row=5)
+               
+               Tkinter.Label (master, text="Bitrate").grid (column=1, row=1)
+               
+               self.bitrate = Tkinter.StringVar ()
+               self.bitrate.set (800)
+               Tkinter.Spinbox (master, textvariable=self.bitrate, from_=0, to=16000).grid (column=2, row=1)
+               
+               Tkinter.Label (master, text="Minimum quantizer (1 to 51)").grid (column=1, row=2)
+               
+               self.quantizermin = Tkinter.StringVar ()
+               self.quantizermin.set (10)
+               Tkinter.Spinbox (master, textvariable=self.quantizermin, from_=1, to=51).grid (column=2, row=2)
+               
+               Tkinter.Label (master, text="Maximum quantizer (1 to 51)").grid (column=1, row=3)
+               
+               self.quantizermax = Tkinter.StringVar ()
+               self.quantizermax.set (51)
+               Tkinter.Spinbox (master, textvariable=self.quantizermax, from_=1, to=51).grid (column=2, row=3)
+               
+               Tkinter.Label (master, text="Fixed quantizer (0 to 51)").grid (column=1, row=4)
+               
+               self.quantizerfixed = Tkinter.StringVar ()
+               self.quantizerfixed.set (20)
+               Tkinter.Spinbox (master, textvariable=self.quantizerfixed, from_=0, to=51).grid (column=2, row=4)
+               
+               Tkinter.Label (master, text="Rate factor (1.0 to 50.0)").grid (column=1, row=5)
+               
+               self.ratefactor = Tkinter.StringVar ()
+               self.ratefactor.set (15)
+               Tkinter.Spinbox (master, textvariable=self.ratefactor, from_=1, to=50).grid (column=2, row=5)
+               
+               Tkinter.Label (master, text="Subpel refinement quality").grid (column=0, row=6)
+               
+               self.subpel = Tkinter.StringVar ()
+               self.subpel.set ("5   Best quarterpixel precision motion estimation (default)")
+               Tkinter.OptionMenu (master, self.subpel, "1   Fullpixel precision motion estimation + fast qp refinement (fastest)", "2   Halfpixel precision motion estimation + fast qp refinement", "3   Halfpixel precision motion estimation + slower qp refinement", "4   Fast quarterpixel precision motion estimation + refinement", "5   Best quarterpixel precision motion estimation (default)", "6   Enables rate-distortion optimization of macroblock types in I- and P-frames", "7   Enables rate-distortion optimization of motion vectors and intra modes. (best)").grid (column=1, row=6, columnspan=2)
+               
+               Tkinter.Label (master, text="Reference frames (1 to 16)").grid (column=0, row=7)
+               
+               self.frameref = Tkinter.StringVar ()
+               self.frameref.set (1)
+               Tkinter.Spinbox (master, textvariable=self.frameref, from_=1, to=16).grid (column=1, row=7)
+               
+               self.cabac = Tkinter.IntVar ()
+               self.cabac.set (1)
+               Tkinter.Checkbutton (master, text="Use Context-Adaptive Binary Arithmetic Coding (cabac)", variable=self.cabac, onvalue=1, offvalue=0).grid (column=0, row=8, columnspan=3) 
+
+class XvidEncDialog (tkSimpleDialog.Dialog):
+       """XviD video codec options dialog"""
+       def apply (self):
+               self.result = "-xvidencopts profile=" + self.profile.get().split()[0]
+               if self.mode.get() == "cbr":
+                       self.result += ":bitrate=" + self.bitrate.get()
+               else:
+                       self.result += ":fixed_quant=" + self.quantizerfixed.get()
+               self.result += ":vhq=" + self.vhq.get().split()[0] + ":quant_type=" + self.quantizertype.get().split()[0]
+               
+               if self.grayscale.get() == 1:
+                       self.result += ":grayscale"
+               if self.cartoonmode.get() == 1:
+                       self.result += ":cartoon"
+               if self.autoaspect.get() == 1:
+                       self.result += ":autoaspect"
+               if self.interlacing.get() == 1:
+                       self.result += ":interlacing"
+               
+       def body (self, master):
+               Tkinter.Label (master, text="XviD video codec options (single pass only) (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=3)
+               
+               Tkinter.Label (master, text="XViD Profile").grid (column=0, row=1)
+               self.profile = Tkinter.StringVar ()
+               self.profile.set ("unrestricted   No restrictions (default)")
+               
+               Tkinter.OptionMenu (master, self.profile, "unrestricted   No restrictions (default)", "sp0   Simple profile at level 0", "sp1   Simple profile at level 1", "sp2   Simple profile at level 2", "sp3   Simple profile at level 3", "asp0   Advanced simple profile at level 0", "asp1   Advanced simple profile at level 1", "asp2   Advanced simple profile at level 2", "asp3   Advanced simple profile at level 3", "asp4   Advanced simple profile at level 4", "asp5   Advanced simple profile at level 5", "dxnhandheld   DXN handheld profile", "dxnportntsc   DXN portable NTSC profile", "dxnportpal   DXN portable PAL profile", "dxnhtntsc   DXN home theatre NTSC profile", "dxnhtpal   DXN home theatre PAL profile", "dxnhdtv   DXN HDTV profile").grid (column=1, row=1)
+               
+               self.mode = Tkinter.StringVar ()
+               self.mode.set ("cbr")
+               Tkinter.Radiobutton (master, variable=self.mode, text="Use constant bitrate mode", value="cbr").grid (column=0, row=2)
+               Tkinter.Radiobutton (master, variable=self.mode, text="Use fixed quantizer mode", value="quantizer").grid (column=0, row=3)
+               
+               Tkinter.Label (master, text="Bitrate (CBR mode)").grid (column=1, row=2)
+               
+               self.bitrate = Tkinter.StringVar ()
+               self.bitrate.set (687)
+               Tkinter.Spinbox (master, textvariable=self.bitrate, from_=0, to=16000).grid (column=2, row=2)
+               
+               Tkinter.Label (master, text="Fixed Quantizer (1 to 31)").grid (column=1, row=3)
+               
+               self.quantizerfixed = Tkinter.StringVar ()
+               self.quantizerfixed.set (2)
+               Tkinter.Spinbox (master, textvariable=self.quantizerfixed, from_=1, to=31).grid (column=2, row=3)
+               
+               Tkinter.Label (master, text="Motion search algorithm (vhq)").grid (column=0, row=4)
+               
+               self.vhq = Tkinter.StringVar ()
+               self.vhq.set ("1   mode decision (inter/intra MB) (default)")
+               Tkinter.OptionMenu (master, self.vhq, "0   off", "1   mode decision (inter/intra MB) (default)", "2   limited search", "3   medium search", "4   wide search").grid (column=1, row=4, columnspan=2)
+               
+               Tkinter.Label (master, text="Quantizer type").grid (column=0, row=5)
+               self.quantizertype = Tkinter.StringVar ()
+               self.quantizertype.set ("mpeg   (more detail at high bitrates)")
+               Tkinter.OptionMenu (master, self.quantizertype, "mpeg   (more detail at high bitrates)", "h263   (better smoothing at lower bitrates)").grid (column=1, row=5, columnspan=2)
+               
+               self.grayscale = Tkinter.IntVar ()
+               self.grayscale.set (0)
+               Tkinter.Checkbutton (master, variable=self.grayscale, text="Grayscale (discard chroma planes)", offvalue=0, onvalue=1).grid (column=0, row=6, columnspan=2)
+               
+               self.cartoonmode = Tkinter.IntVar ()
+               self.cartoonmode.set (0)
+               Tkinter.Checkbutton (master, variable=self.cartoonmode, text="Optimize for cartoon/anime", offvalue=0, onvalue=1).grid (column=2, row=6)
+
+               self.autoaspect = Tkinter.IntVar ()
+               self.autoaspect.set (0)
+               Tkinter.Checkbutton (master, variable=self.autoaspect, text="Automatically compute internal aspect ratio", offvalue=0, onvalue=1).grid (column=0, row=7, columnspan=2)
+
+               self.interlacing = Tkinter.IntVar ()
+               self.interlacing.set (0)
+               Tkinter.Checkbutton (master, variable=self.interlacing, text="Interlacing", offvalue=0, onvalue=1).grid (column=2, row=7, columnspan=3)
+
+class LAVCVideoDialog (tkSimpleDialog.Dialog):
+       """LAVC video codec options dialog """
+       def apply (self):
+               self.result = "-lavcopts " + "vcodec=" + self.videocodec.get().split()[0]
+               
+               if self.quantizertype.get() == "variable":
+                       self.result += ":vbitrate=" + self.bitrate.get() + ":vqmin=" + self.quantizermin.get() + ":vqmax=" + self.quantizermax.get()
+               else:
+                       self.result += ":vqscale=" + self.quantizerfixed.get()
+
+               self.result += ":mbd=" + self.mbdalgorithm.get().split()[0]
+               if self.v4mvectors.get() == 1:
+                       self.result += ":v4mv"
+               if self.grayscale.get() == 1:
+                       self.result += ":gray"
+               if self.autoaspect.get() == 1:
+                       self.result += ":autoaspect"
+       
+       def body (self, master):
+               Tkinter.Label (master, text="LAVC video codec options (single pass only) (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=3)
+               
+               Tkinter.Label (master, text="Video codec").grid (column=0, row=1)
+               
+               self.videocodec = Tkinter.StringVar ()
+               self.videocodec.set ("mpeg4   MPEG-4 (DivX 4/5)")
+               Tkinter.OptionMenu (master, self.videocodec, "asv1   ASUS Video v1", "asv2   ASUS Video v2", "dvvideo   Sony Digital Video", "ffv1   FFMpeg lossless video codec", "ffvhuff   Nonstandard 20% smaller HuffYUV using YV12", "flv   Sorenson H.263 used in Flash Video", "h261   H.261", "h263   H.263", "h263p   H.263+", "huffyuv   HuffYUV", "libtheora   Theora", "libx264   x264 H.264/AVC MPEG-4 Part 10", "libxvid   Xvid MPEG-4 Part 2 (ASP)", "ljpeg   Lossless JPEG", "mjpeg   Motion JPEG", "mpeg1video   MPEG-1 video", "mpeg2video   MPEG-2 video", "mpeg4   MPEG-4 (DivX 4/5)", "msmpeg4   DivX 3", "msmpeg4v2   MS MPEG4v2", "roqvideo   ID Software RoQ Video", "rv10   an old RealVideo codec", "snow   FFmpeg's experimental wavelet-based codec", "svq1   Apple Sorenson Video 1", "wmv1   Windows Media Video, version 1 (AKA WMV7)", "wmv2   Windows Media Video, version 2 (AKA WMV8)").grid (column=1, row=1, columnspan=2)
+               
+               self.quantizertype = Tkinter.StringVar ()
+               self.quantizertype.set ("variable")             
+               Tkinter.Radiobutton (master, variable=self.quantizertype, text="Variable quantizer", value="variable").grid (column=0, row=2)
+               Tkinter.Radiobutton (master, variable=self.quantizertype, text="Fixed quantizer", value="fixed").grid (column=0, row=5)
+
+               Tkinter.Label (master, text="Video bitrate").grid (column=1, row=2)
+               
+               self.bitrate = Tkinter.StringVar ()
+               self.bitrate.set (800)
+               Tkinter.Spinbox (master, textvariable=self.bitrate, from_=0, to=16000).grid (column=2, row=2)
+               
+               Tkinter.Label (master, text="Minimum quantizer (vqmin) (1 to 31)").grid (column=1, row=3)
+               
+               self.quantizermin = Tkinter.StringVar ()
+               self.quantizermin.set ("2")
+               Tkinter.Spinbox (master, textvariable=self.quantizermin, from_=1, to=31).grid (column=2, row=3)
+               
+               Tkinter.Label (master, text="Maximum quantizer (vqmax) (1 to 31)").grid (column=1, row=4)
+               
+               self.quantizermax = Tkinter.StringVar ()
+               self.quantizermax.set ("31")
+               Tkinter.Spinbox (master, textvariable=self.quantizermax, from_=1, to=31).grid (column=2, row=4)
+               
+               Tkinter.Label (master, text="Fixed quantizer (vqscale) (0 to 31)").grid (column=1, row=5)
+               
+               self.quantizerfixed = Tkinter.StringVar ()
+               self.quantizerfixed.set ("2")
+               Tkinter.Spinbox (master, textvariable=self.quantizerfixed, from_=0, to=31).grid (column=2, row=5)
+               
+               Tkinter.Label (master, text="Macroblock decision algorithm").grid (column=0, row=6)
+               
+               self.mbdalgorithm = Tkinter.StringVar ()
+               self.mbdalgorithm.set ("0   Use comparison function given by mbcmp (default)")
+               Tkinter.OptionMenu (master, self.mbdalgorithm, "0   Use comparison function given by mbcmp (default)", "1   Select the MB mode which needs the fewest bits (=vhq)", "2   Select the MB mode which has the best rate distortion").grid (column=1, row=6, columnspan=2)
+               
+               self.v4mvectors = Tkinter.IntVar ()
+               self.v4mvectors.set (0)
+               Tkinter.Checkbutton (master, text="Allow 4 motion vectors per macroblock (slightly better quality)", variable= self.v4mvectors, onvalue=1, offvalue=0).grid (column=0, row=7, columnspan=3)
+               
+               self.grayscale = Tkinter.IntVar ()
+               self.grayscale.set (0)
+               Tkinter.Checkbutton (master, text="Grayscale only encoding (faster)", variable=self.grayscale, onvalue=1, offvalue=0).grid (column=0, row=8, columnspan=3)
+               
+               self.autoaspect = Tkinter.IntVar ()
+               self.autoaspect.set (0)
+               Tkinter.Checkbutton (master, text="Automatically compute internal aspect ratio", variable=self.autoaspect, onvalue=1, offvalue=0).grid (column=0, row=9, columnspan=3)
+
+class NUVDialog (tkSimpleDialog.Dialog):
+       """Nuppel video codec options dialog """
+       def apply (self):
+               self.result = "-nuvopts q=" + self.qualitylevel.get() + ":c=" + self.chrominance.get() + ":l=" + self.luminance.get()
+               if self.disablelzo.get() == 1:
+                       self.result += ":nolzo"
+               else:
+                       self.result += ":lzo"
+               if self.disablertjpeg.get() == 1:
+                       self.result += ":raw"
+               else:
+                       self.result += ":rtjpeg"
+               
+       def body (self, master):
+               Tkinter.Label (master, text="Nuppel video encoding options", fg="darkblue").grid (column=0, row=0, columnspan=2)
+               
+               Tkinter.Label (master, text="Quality level (3 to 255)").grid (column=0, row=1)
+               
+               self.qualitylevel = Tkinter.StringVar ()
+               self.qualitylevel.set (255)
+               Tkinter.Spinbox (master, textvariable=self.qualitylevel, from_=3, to=255).grid (column=1, row=1)
+               
+               Tkinter.Label (master, text="Chrominance threshold (0 to 20)").grid (column=0, row=2)
+               
+               self.chrominance = Tkinter.StringVar ()
+               self.chrominance.set (1)
+               Tkinter.Spinbox (master, textvariable=self.chrominance, from_=0, to=20).grid (column=1, row=2)
+               
+               Tkinter.Label (master, text="Luminance threshold (0 to 20)").grid (column=0, row=3)
+               
+               self.luminance = Tkinter.StringVar ()
+               self.luminance.set (1)
+               Tkinter.Spinbox (master, textvariable=self.luminance, from_=0, to=20).grid (column=1, row=3)
+               
+               self.disablelzo = Tkinter.IntVar ()
+               self.disablelzo.set (0)
+               Tkinter.Checkbutton (master, text="Disable LZO compression", variable=self.disablelzo, onvalue=1, offvalue=0).grid (column=0, row=4, columnspan=2)
+               
+               self.disablertjpeg = Tkinter.IntVar ()
+               self.disablertjpeg.set (0)
+               Tkinter.Checkbutton (master, text="Disable RTJPEG encoding", variable=self.disablertjpeg, onvalue=1, offvalue=0).grid (column=0, row=5, columnspan=2)
diff --git a/videocodecdialogs.pyc b/videocodecdialogs.pyc
new file mode 100644 (file)
index 0000000..823ff1f
Binary files /dev/null and b/videocodecdialogs.pyc differ
diff --git a/videofilterdialogs.py b/videofilterdialogs.py
new file mode 100644 (file)
index 0000000..b4a4ab6
--- /dev/null
@@ -0,0 +1,297 @@
+# Video filter dialogs for the BiaMovE application
+
+import Tkinter
+import tkFileDialog
+import tkSimpleDialog
+import tkMessageBox
+
+class FilterPictureDialog (tkSimpleDialog.Dialog):
+       """Implements a picture dialog box for adjusting brightness, contrast etc."""
+       
+       def apply (self):
+               self.result = self.gamma.get () + ":" + self.contrast.get () + ":" + self.brightness.get() + ":" + self.saturation.get ()
+               
+       def body (self, master):
+               Tkinter.Label (master, text="Picture adjustments (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=2)
+               
+               Tkinter.Label (master, text="Gamma correction").grid (column=0, row=1)
+               
+               self.gamma = Tkinter.StringVar ()
+               self.gamma_scale = Tkinter.Scale (master, variable=self.gamma, from_=0.1, to=10, length=200, resolution=0.05,  orient=Tkinter.HORIZONTAL)
+               self.gamma_scale.set (1)
+               self.gamma_scale.grid (column=1, row=1)
+               
+               Tkinter.Label (master, text="Contrast").grid (column=0, row=2)
+               
+               self.contrast = Tkinter.StringVar ()
+               self.contrast_scale = Tkinter.Scale (master, variable=self.contrast, from_=-2, to=2, length=200, resolution=0.05,
+               orient=Tkinter.HORIZONTAL)
+               self.contrast_scale.set (1)
+               self.contrast_scale.grid (column=1, row=2)
+               
+               Tkinter.Label (master, text="Brightness").grid (column=0, row=3)
+               
+               self.brightness = Tkinter.StringVar ()
+               self.brightness_scale = Tkinter.Scale (master, variable=self.brightness, from_=-1, to=1, length=200,
+               resolution=0.05, orient=Tkinter.HORIZONTAL)
+               self.brightness_scale.set (0)
+               self.brightness_scale.grid (column=1, row=3)
+               
+               Tkinter.Label (master, text="Saturation").grid (column=0,row=4)
+               
+               self.saturation = Tkinter.StringVar ()
+               self.saturation_scale = Tkinter.Scale (master, variable=self.saturation, from_=0, to=3, length=200,
+               resolution=0.05, orient=Tkinter.HORIZONTAL)
+               self.saturation_scale.set (1)
+               self.saturation_scale.grid (column=1, row=4)
+
+class FilterCropDialog (tkSimpleDialog.Dialog):
+       """Implements the crop dialog box for cropping parts of the video"""
+       def apply (self):
+               self.result = self.crop_width.get() + ":" + self.crop_height.get()
+               
+               self.result += ":"
+               
+               if self.center_width.get() == 0:
+                       self.result += self.horizontal.get ()
+               self.result += ":"
+               if self.center_height.get() == 0:
+                       self.result += self.vertical.get ()
+               
+               self.result = self.result.strip (":")
+       
+       def body (self, master):
+               Tkinter.Label (master, text="Crop parameters (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=2)
+               Tkinter.Label (master, text="Width").grid (column=0, row=1)
+               
+               self.crop_width = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.crop_width).grid (column=1, row=1)
+               
+               Tkinter.Label (master, text="Height").grid (column=0, row=2)
+               
+               self.crop_height = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.crop_height).grid (column=1, row=2)
+               
+               Tkinter.Label (master, text="Position of video in cropped frame", fg="darkblue").grid (column=0, row=3, columnspan=2)
+               
+               self.center_width = Tkinter.IntVar ()
+               self.center_width.set (1)
+               Tkinter.Checkbutton (master, variable=self.center_width, text="Center horizontally", onvalue=1, offvalue=0).grid (column=0, row=4)
+               
+               self.center_height = Tkinter.IntVar ()
+               self.center_height.set (1)
+               Tkinter.Checkbutton (master, variable=self.center_height, text="Center vertically", onvalue=1, offvalue=0).grid (column=1, row=4)
+               
+               Tkinter.Label (master, text="Horizontal position").grid (column=0, row=5)
+               
+               self.horizontal = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.horizontal).grid (column=1, row=5)
+               
+               Tkinter.Label (master, text="Vertical position").grid (column=0, row=6)
+               
+               self.vertical = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.vertical).grid (column=1, row=6)
+
+class FilterExpandDialog (tkSimpleDialog.Dialog):
+       """Implements the expand dialog box for expanding the video"""
+       def apply (self):
+               if self.relative_width.get() == 1:
+                       self.result = "-" + self.expand_width.get()
+               else:
+                       self.result = self.expand_width.get()
+               if self.relative_height.get() == 1:
+                       self.result += ":-" + self.expand_height.get()
+               else:
+                       self.result += ":" + self.expand_height.get()
+               
+               self.result += ":"
+               if self.center_width.get() == 0:
+                       self.result += self.horizontal.get()
+               self.result += ":"
+               if self.center_height.get() == 0:
+                       self.result += self.vertical.get()
+                       
+               self.result += ":" + str (self.osdsubtitle.get())
+               
+       
+       def body (self, master):
+               Tkinter.Label (master, text="Expand parameters (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=3)
+               Tkinter.Label (master, text="Width").grid (column=0, row=1)
+               
+               self.expand_width = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.expand_width).grid (column=1, row=1)
+               
+               self.relative_width = Tkinter.IntVar ()
+               self.relative_width.set (0)
+               Tkinter.Checkbutton (master, variable = self.relative_width, text="Offset width (not absolute)", onvalue=1, offvalue=0).grid (column=2, row=1)
+               
+               Tkinter.Label (master, text="Height").grid (column=0, row=2)
+               
+               self.expand_height = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.expand_height).grid (column=1, row=2)
+               
+               self.relative_height = Tkinter.IntVar ()
+               self.relative_height.set (0)
+               Tkinter.Checkbutton (master, variable = self.relative_height, text="Offset height (not absolute)", onvalue=1, offvalue=0).grid (column=2, row=2)
+               
+               Tkinter.Label (master, text="Position of video in expanded frame", fg="darkblue").grid (column=0, row=3, columnspan=3)
+               
+               self.center_width = Tkinter.IntVar ()
+               self.center_width.set (1)
+               Tkinter.Checkbutton (master, variable=self.center_width, text="Center horizontally", onvalue=1, offvalue=0).grid (column=1, row=4)
+               
+               self.center_height = Tkinter.IntVar ()
+               self.center_height.set (1)
+               Tkinter.Checkbutton (master, variable=self.center_height, text="Center vertically", onvalue=1, offvalue=0).grid (column=2, row=4)
+               
+               Tkinter.Label (master, text="Horizontal position").grid (column=0, row=5)
+               
+               self.horizontal = Tkinter.StringVar ()
+               self.horizontal.set (0)
+               Tkinter.Entry (master, textvariable=self.horizontal).grid (column=1, row=5)
+               
+               Tkinter.Label (master, text="Vertical position").grid (column=0, row=6)
+               
+               self.vertical = Tkinter.StringVar ()
+               self.vertical.set (0)
+               Tkinter.Entry (master, textvariable=self.vertical).grid (column=1, row=6)
+               
+               self.osdsubtitle = Tkinter.IntVar ()
+               self.osdsubtitle.set (0)
+               Tkinter.Checkbutton (master, variable=self.osdsubtitle, text="OSD/Subtitle rendering", onvalue=1, offvalue=0).grid (column=0, row=7, columnspan=3)
+
+class FilterScaleDialog (tkSimpleDialog.Dialog):
+       """Implements the dialog box for scaling the video"""
+       def apply (self):
+               if self.width_mode.get() == "(specify manually)":
+                       self.result = self.width_value.get()
+               else:
+                       self.result = self.width_mode.get().split()[0]
+               if self.height_mode.get() == "(specify manually)":
+                       self.result += ":" + self.height_value.get()
+               else:
+                       self.result += ":" + self.height_mode.get().split()[0]
+               self.result += ":" + str(self.interlacing.get())
+               
+       def body (self, master):
+               Tkinter.Label (master, text="Video scale parameters (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=3)
+               
+               Tkinter.Label (master, text="Width").grid (column=0, row=1)
+               
+               self.width_mode = Tkinter.StringVar ()
+               self.width_mode.set ("(specify manually)")
+               Tkinter.OptionMenu (master, self.width_mode, "0   scaled d_width", "-1   original width", "-2   calculate from height using prescaled aspect ratio", "-3   calculate from height using original aspect ratio", "(specify manually)").grid (column=1, row=1)
+               
+               self.width_value = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.width_value).grid (column=2, row=1)
+               
+               Tkinter.Label (master, text="Height").grid (column=0, row=2)
+               
+               self.height_mode = Tkinter.StringVar ()
+               self.height_mode.set ("(specify manually)")
+               Tkinter.OptionMenu (master, self.height_mode, "0   scaled d_height", "-1   original height", "-2   calculate from width using prescaled aspect ratio", "-3   calculate from width using original aspect ratio", "(specify manually)").grid (column=1, row=2)
+               
+               self.height_value = Tkinter.StringVar ()
+               Tkinter.Entry (master, textvariable=self.height_value).grid (column=2, row=2)
+               
+               self.interlacing = Tkinter.IntVar ()
+               self.interlacing.set (0)
+               Tkinter.Checkbutton (master, variable=self.interlacing, text="Interaced scaling", onvalue=1, offvalue=0).grid (column=0, row=3, columnspan=3)
+
+class VideoFiltersDialog (tkSimpleDialog.Dialog):
+       """ Implement a dialog box to implement video filter
+       1. crop
+       2. scale
+       3. expand
+       4. force encoding duplicate frames (harddup)
+       5. picture adjustments (brightness contrast etc)"""
+       def on_crop_filter (self):
+               cropdlg = FilterCropDialog (self)
+               if cropdlg.result != None:
+                       self.crop_params.set (cropdlg.result)
+                       self.active_filters["crop"] = cropdlg.result
+                       
+                       if "crop" not in self.filterlist.get(0, Tkinter.END):
+                               self.filterlist.insert (Tkinter.END, "crop")
+                       
+       def on_scale_filter (self):
+               scaledlg = FilterScaleDialog (self)
+               if scaledlg.result != None:
+                       self.scale_params.set (scaledlg.result)
+                       self.active_filters["scale"] = scaledlg.result
+                       
+                       if "scale" not in self.filterlist.get(0, Tkinter.END):
+                               self.filterlist.insert (Tkinter.END, "scale")
+                               
+       def on_remove (self):
+               self.filterlist.delete (Tkinter.ANCHOR)
+               
+       def on_softskip_filter (self):
+               if "softskip" not in self.filterlist.get (0, Tkinter.END):
+                       self.filterlist.insert (Tkinter.END, "softskip")
+                       
+       def on_expand_filter (self):
+               expanddlg = FilterExpandDialog (self)
+               if expanddlg.result != None:
+                       self.expand_params.set (expanddlg.result)
+                       self.active_filters["expand"] = expanddlg.result
+                       
+                       if "expand" not in self.filterlist.get (0, Tkinter.END):
+                               self.filterlist.insert (Tkinter.END, "expand")
+                               
+       def on_picture_filter (self):
+               picturedlg = FilterPictureDialog (self)
+               if picturedlg.result != None:
+                       self.picture_params.set (picturedlg.result)
+                       self.active_filters["eq2"] = picturedlg.result
+                       
+                       if "eq2" not in self.filterlist.get (0, Tkinter.END):
+                               self.filterlist.insert (Tkinter.END, "eq2")
+       
+       def apply (self):
+               self.result = ""
+               for item in self.filterlist.get (0, Tkinter.END):
+                       if self.active_filters.has_key (item):
+                               self.result += item + "=" + self.active_filters[item]
+                       else:
+                               self.result += item
+                       self.result += ","
+
+               if self.harddup.get () == 1:
+                       self.result += "harddup"
+               self.result = self.result.strip (",")
+
+       def body (self, master):
+               Tkinter.Label (master, text="Setup video filters (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=4)
+               
+               Tkinter.Label (master, text="Active filters list").grid (column=0, row=1)
+               self.filterlist = Tkinter.Listbox (master, height=5,width=30)
+               self.filterlist.grid (column=1, row=1, rowspan=6)
+               Tkinter.Button (master, text="remove", command=self.on_remove).grid(column=1,row=1)
+               
+               Tkinter.Button (master, text="crop...", command=self.on_crop_filter).grid (column=2, row=2)
+               
+               self.crop_params = Tkinter.StringVar ()
+               Tkinter.Label (master, textvariable=self.crop_params).grid (column=3, row=2)
+               
+               Tkinter.Button (master, text="scale...", command=self.on_scale_filter).grid (column=2, row=3)
+               
+               self.scale_params = Tkinter.StringVar ()
+               Tkinter.Label (master, textvariable=self.scale_params).grid (column=3, row=3)
+               
+               Tkinter.Button (master, text="expand...", command=self.on_expand_filter).grid (column=2, row=4)
+               
+               self.expand_params = Tkinter.StringVar ()
+               Tkinter.Label (master, textvariable=self.expand_params).grid (column=3, row=4)
+               
+               Tkinter.Button (master, text="picture...", command=self.on_picture_filter).grid (column=2, row=5)
+               self.picture_params = Tkinter.StringVar ()
+               Tkinter.Label (master, textvariable=self.picture_params).grid (column=3, row=5)
+               
+               Tkinter.Button (master, text="softskip", command=self.on_softskip_filter).grid (column=2, row=6)
+               
+               self.harddup = Tkinter.IntVar ()
+               self.harddup.set (0)
+               Tkinter.Checkbutton (master, variable=self.harddup, text="Force duplicate frames (required for DVD-compliant MPEG-2 streams)", onvalue=1, offvalue=0).grid (column=0, row=7, columnspan=4)
+               
+               self.active_filters = {}
diff --git a/videofilterdialogs.pyc b/videofilterdialogs.pyc
new file mode 100644 (file)
index 0000000..fce02d7
Binary files /dev/null and b/videofilterdialogs.pyc differ
diff --git a/videomuxerdialogs.py b/videomuxerdialogs.py
new file mode 100644 (file)
index 0000000..850491a
--- /dev/null
@@ -0,0 +1,95 @@
+# Video muxer dialogs for the BiaMovE application
+
+import Tkinter
+import tkFileDialog
+import tkSimpleDialog
+import tkMessageBox
+
+class MPEGMuxerDialog (tkSimpleDialog.Dialog):
+       """MPEG container -mpegopts options dialog"""
+       def apply (self):
+               self.result = "-mpegopts format=" + self.format.get ()
+               if (self.vdelay.get() != "0"):
+                       self.result += ":vdelay=" + self.vdelay.get ()
+                       if (self.vdropaudio.get() == 1):
+                               self.result += ":drop"
+               if (self.adelay.get() != "0"):
+                       self.result += ":adelay=" + self.adelay.get ()
+               if (self.aspectratio.get() != "(not set)"):
+                       self.result += ":vaspect=" + self.aspectratio.get ()
+               if (self.framerate.get() != "(not set)"):
+                       self.result += ":vframerate=" + self.framerate.get ()
+               if (self.bitrate.get() != "0"):
+                       self.result += ":vbitrate=" + self.bitrate.get ()
+               if (self.settsaf.get() == 1):
+                       self.result += ":tsaf"
+               if (self.interleaving.get() == 1):
+                       self.result += ":interleaving2"
+
+       def body (self, master):
+               Tkinter.Label (master, text="MPEG muxer options (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=3)
+               
+               Tkinter.Label (master, text="Format").grid (column=0, row=1)
+               
+               self.format = Tkinter.StringVar ()
+               self.format.set ("mpeg2")
+               Tkinter.OptionMenu (master, self.format, "mpeg1", "mpeg2", "xvcd", "xsvcd", "dvd", "pes1", "pes2").grid (column=1, row=1)
+               
+               Tkinter.Label (master, text="Video delay (1 to 32760) ms").grid (column=0, row=2)
+               
+               self.vdelay = Tkinter.StringVar ()
+               self.vdelay.set (0)
+               Tkinter.Spinbox (master, textvariable=self.vdelay, from_=1, to=32760).grid (column=1, row=2)
+               
+               self.vdropaudio = Tkinter.IntVar ()
+               self.vdropaudio.set (0)
+               Tkinter.Checkbutton (master, text = "Drop leading audio", variable=self.vdropaudio, offvalue=0, onvalue=1).grid (column=2, row=2)
+               
+               Tkinter.Label (master, text="Audio delay (1 to 32760) ms").grid (column=0, row=3)
+               
+               self.adelay = Tkinter.StringVar ()
+               self.adelay.set (0)
+               Tkinter.Spinbox (master, textvariable=self.adelay, from_=1, to=32760).grid (column=1, row=3)
+               
+               Tkinter.Label (master, text="Aspect ratio").grid (column=0, row=4)
+               
+               self.aspectratio = Tkinter.StringVar ()
+               self.aspectratio.set ("(not set)")
+               Tkinter.OptionMenu (master, self.aspectratio, "(not set)", "1", "4/3", "16/9", "221/100").grid (column=1, row=4)
+               
+               Tkinter.Label (master, text="Frame rate").grid (column=0, row=5)
+               
+               self.framerate = Tkinter.StringVar ()
+               self.framerate.set ("(not set)")
+               Tkinter.OptionMenu (master, self.framerate, "(not set)", "24000/1001", "24", "25", "30000/1001", "30", "50", "60000/1001", "60").grid (column=1, row=5)
+               
+               Tkinter.Label (master, text="Video bitrate (0 to ignore)").grid (column=0, row=6)
+               
+               self.bitrate = Tkinter.StringVar ()
+               self.bitrate.set (0)
+               Tkinter.Spinbox (master, textvariable=self.bitrate, from_=0, to=16000).grid (column=1, row=6)
+               
+               self.settsaf = Tkinter.IntVar ()
+               self.settsaf.set (0)
+               Tkinter.Checkbutton (master, text="Set timestamp on all frames",variable=self.settsaf, onvalue=1, offvalue=0).grid (column=0, row=7, columnspan=3)
+               
+               self.interleaving = Tkinter.IntVar ()
+               self.interleaving.set (0)
+               Tkinter.Checkbutton (master, text="Interleaving 2", variable=self.interleaving, onvalue=1, offvalue=0).grid (column=0, row=8, columnspan=3)
+
+class LAVFMuxerDialog (tkSimpleDialog.Dialog):
+       """LAVF container -lavfopts options dialog"""
+       def apply (self):
+               if self.containerfmt.get () == "(autodetect from filename)":
+                       self.result = ""
+               else:
+                       self.result = "-lavfopts format=" + self.containerfmt.get().split()[0]
+       
+       def body (self, master):
+               Tkinter.Label(master, text="libavformat muxer options (simplified)", fg="darkblue").grid (column=0, row=0, columnspan=2)
+               
+               Tkinter.Label(master, text="Container format").grid (column=0, row=1)
+               
+               self.containerfmt = Tkinter.StringVar ()
+               self.containerfmt.set ("(autodetect from filename)")
+               Tkinter.OptionMenu (master, self.containerfmt, "(autodetect from filename)", "mpg   MPEG-1 systems or MPEG-2 PS", "asf   Advanced streaming format", "avi   Audio-video interleaved", "wav   Waveform audio", "swf   Macromedia Flash", "flv   Macromedia Flash video", "rm   Realaudio/Realvideo", "nut   NUT open container format (experimental)", "mov   QuickTime", "mp4   MPEG-4 format", "dv   Sony digital video container").grid (column=1, row=1)
diff --git a/videomuxerdialogs.pyc b/videomuxerdialogs.pyc
new file mode 100644 (file)
index 0000000..ed8fa47
Binary files /dev/null and b/videomuxerdialogs.pyc differ