From: Harishankar Date: Thu, 26 Feb 2009 16:59:04 +0000 (+0530) Subject: Initial commit X-Git-Url: https://harishankar.org/repos/?p=biamove.git;a=commitdiff_plain;h=81d67ae9cd2c27ac180871c69be6dcf79e8daf88 Initial commit --- 81d67ae9cd2c27ac180871c69be6dcf79e8daf88 diff --git a/MANIFEST b/MANIFEST new file mode 100644 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 index 0000000..3533cd5 --- /dev/null +++ b/audiocodecdialogs.py @@ -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 index 0000000..a0b2215 Binary files /dev/null and b/audiocodecdialogs.pyc differ diff --git a/biamove.py b/biamove.py new file mode 100755 index 0000000..e1ad659 --- /dev/null +++ b/biamove.py @@ -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 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 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 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 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 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 index 0000000..174f35e --- /dev/null +++ b/doc/biamove-doc.docbook @@ -0,0 +1,94 @@ +BiaMovE"> + +Mencoder"> +FFMpeg">]> + + &bia; documentation + + + &author; + V + + + A short guide to video encoding using &bia; (via &menc;) + + + + Introduction + + &bia; (pronounced "by-a-movie") is a graphical user interface to &menc;, 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. + + + 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? + + + Why &menc; + + Why &menc; and why not &ffmpeg;? Well, for one, &menc; can wrap around &ffmpeg; libraries using libavcodec. 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. + + + + Philosophy + + 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. + + + &bia; is not a tool for the newbie though. It is just a thin (albeit useful) GUI wrapper to &menc;. It does not: + + Check for the sanity of your &menc; configuration, nor does it check for codec availability on your setup. + Does not verify the sanity of your options. It just passes on your choices to the underlying &menc; command line. + + + + 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 video encoding basics and also study the &menc; manual pages in depth. + + + + + Video encoding basics + + 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 concepts section for definitions to common terms specific to digital audio/video technologies. + + + If you are of the "just want to rip my DVDs to my iPod" type, feel free to skip this section. + + + The problems + + 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 MPlayer as well as the encoder. + + + 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, MPEG-4, H.264, DivX, XViD 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 Apple iPod is a case in point). + + + 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;. + + + &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. + + + + Concepts + + Bitrate + + 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). + + + 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. + + + + Framerate + + 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 (PAL, NTSC 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. + + + The higher the framerate, smoother the animation. Usually 25 to 30 fps is more than enough for the human eye. + + + + + + \ No newline at end of file diff --git a/doc/biamove-doc.html b/doc/biamove-doc.html new file mode 100644 index 0000000..fbd2a53 --- /dev/null +++ b/doc/biamove-doc.html @@ -0,0 +1,376 @@ + +BiaMovE documentation

BiaMovE documentation

Harishankar V

A short guide to video encoding using BiaMovE (via Mencoder)


Table of Contents
1. Introduction
Why Mencoder
Philosophy
2. Video encoding basics
The problems
Concepts
Bitrate
Framerate

Chapter 1. Introduction

BiaMovE (pronounced "by-a-movie") is a graphical user interface to Mencoder, an extremely powerful and versatile cross-platform video encoding command-line utility. The problem with Mencoder is that it is very complex and non-trivial to lay users. +

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 Mencoder 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? +


Why Mencoder

Why Mencoder and why not FFMpeg? Well, for one, Mencoder can wrap around FFMpeg libraries using libavcodec. Secondly I found using the FFMpeg command line much easier than Mencoder and felt that it would be better to write a GUI around Mencoder instead. +


Philosophy

When I wrote BiaMovE I wanted to mainly explore the codec-specific options of Mencoder. I did so because video/audio codecs are extremely complex creatures. I cannot pretend that I understood everything I read in the Mencoder manual pages. With BiaMovE I've tried to hide a little bit of the complexity, but without restricting the advanced user. +

BiaMovE is not a tool for the newbie though. It is just a thin (albeit useful) GUI wrapper to Mencoder. It does not: +

  • Check for the sanity of your Mencoder configuration, nor does it check for codec availability on your setup.

  • Does not verify the sanity of your options. It just passes on your choices to the underlying Mencoder command line.

+

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 video encoding basics and also study the Mencoder manual pages in depth. +


Chapter 2. Video encoding basics

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 BiaMovE and Mencoder. 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 concepts section for definitions to common terms specific to digital audio/video technologies. +

If you are of the "just want to rip my DVDs to my iPod" type, feel free to skip this section. +


The problems

For most people simply using a command-line tool like Mencoder can be a daunting task. The Mencoder manual page alone is scary enough, because it documents both the player MPlayer as well as the encoder. +

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, MPEG-4, H.264, DivX, XViD 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 Apple iPod™ is a case in point). +

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 Mencoder. +

BiaMovE cannot overcome these problems for you for the reasons already mentioned earlier. However reading these notes should help you avoid some of the pitfalls. +


Concepts

Bitrate

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). +

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. +


Framerate

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 (PAL, NTSC 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. +

The higher the framerate, smoother the animation. Usually 25 to 30 fps is more than enough for the human eye. +

\ No newline at end of file diff --git a/doc/biamove-doc.pdf b/doc/biamove-doc.pdf new file mode 100644 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 index 0000000..f696d69 --- /dev/null +++ b/mainwindow.py @@ -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 index 0000000..6c7e9df Binary files /dev/null and b/mainwindow.pyc differ diff --git a/miscdialogs.py b/miscdialogs.py new file mode 100644 index 0000000..6753dd3 --- /dev/null +++ b/miscdialogs.py @@ -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 index 0000000..654735c Binary files /dev/null and b/miscdialogs.pyc differ diff --git a/sample.avi b/sample.avi new file mode 100644 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 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 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 index 0000000..d81e3dc --- /dev/null +++ b/videocodecdialogs.py @@ -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 index 0000000..823ff1f Binary files /dev/null and b/videocodecdialogs.pyc differ diff --git a/videofilterdialogs.py b/videofilterdialogs.py new file mode 100644 index 0000000..b4a4ab6 --- /dev/null +++ b/videofilterdialogs.py @@ -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 index 0000000..fce02d7 Binary files /dev/null and b/videofilterdialogs.pyc differ diff --git a/videomuxerdialogs.py b/videomuxerdialogs.py new file mode 100644 index 0000000..850491a --- /dev/null +++ b/videomuxerdialogs.py @@ -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 index 0000000..ed8fa47 Binary files /dev/null and b/videomuxerdialogs.pyc differ