summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Wey2009-03-07 17:02:16 +0100
committerMike Wey2009-03-07 17:02:16 +0100
commita872d637bd880832087d5b51313591f9675275ec (patch)
treea1918274c52cb569a7e9d3868937069cb98ee3a3
initial commit
-rw-r--r--.hgignore5
-rw-r--r--BitrateCalculator.d350
-rw-r--r--Gui.d683
-rw-r--r--dsss.conf8
-rw-r--r--gpl.txt339
5 files changed, 1385 insertions, 0 deletions
diff --git a/.hgignore b/.hgignore
new file mode 100644
index 0000000..1baaf95
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,5 @@
+syntax: glob
+
+dsss_objs/*
+dsss.last
+bitratecalc
diff --git a/BitrateCalculator.d b/BitrateCalculator.d
new file mode 100644
index 0000000..9947004
--- /dev/null
+++ b/BitrateCalculator.d
@@ -0,0 +1,350 @@
+// ****************************************************************************
+// This is a slightly modified version of the BitrateCalculator.cs
+// from MeGUI (http://sourceforge.net/projects/megui).
+//
+// Copyright (C) 2005 Doom9
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed; the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// ****************************************************************************
+
+module BitrateCalculator;
+
+import tango.math.Math;
+
+///Arrays with the storage mediums, and there sizes.
+char[][] storageMediums =
+ ["1/4 CD", "1/2 CD", "1 CD", "2 CD", "3 CD",
+ "1/3 DVD-R", "1/4 DVD-R", "1/5 DVD-R", "DVD-5", "DVD-9"];
+int[] storageMediumSizeKB =
+ [179200, 358400, 716800, 1433600, 2150400, 1501184,
+ 1126400, 901120, 4586496, 8333760,];
+
+///Arrays with the framerates.
+double[] FrameRate = [23.967, 24.0, 25.0, 29.97, 30.0, 50.0, 59.94, 60.0];
+char[][] frameRates = ["23.967", "24.0", "25.0", "29.97", "30.0", "50.0", "59.94", "60.0"];
+
+///The audio types used for the calculations.
+enum AudioType { MP4AAC, RAWAAC, AC3, DTS, MP2, CBRMP3, VBRMP3, VORBIS }
+char[][] audioTypes = ["MP4-AAC", "RAW-AAC", "AC3", "DTS", "MP2", "CBR-MP3", "VBR-MP3", "Ogg"];
+
+///Videocodec used for calculations.
+enum VideoCodec { Lavc, X264, Snow, XviD }
+char[][] videoCodecs = ["Lavc", "X264", "Snow", "XviD"];
+
+///Container used.
+enum ContainerType { MKV, MP4, AVI }
+char[][] containerTypes = ["MKV", "MP4", "AVI"];
+
+///Info about the audio stream.
+struct AudioStream
+{
+ long SizeBytes;
+ AudioType Type;
+}
+
+///Bitrate Calculations
+public class BitrateCalculator
+{
+ private const double mp4OverheadWithBframes = 10.4;
+ private const double mp4OverheadWithoutBframes = 4.3;
+ private const double aviVideoOverhead = 24;
+ private const double cbrMP3Overhead = 23.75;
+ private const double vbrMP3Overhead = 40;
+ private const double ac3Overhead = 23.75;
+ private const int AACBlockSize = 1024;
+ private const int AC3BlockSize = 1536;
+ private const int MP3BlockSize = 1152;
+ private const int VorbisBlockSize = 1024;
+ private const int mkvAudioTrackHeaderSize = 140;
+ private const int mkvVorbisTrackHeaderSize = 4096;
+ private const uint mkvIframeOverhead = 26;
+ private const uint mkvPframeOverhead = 13;
+ private const uint mkvBframeOverhead = 16;
+
+ this(){}
+
+ /// calculates the video bitrate for a video to be put into the MP4 container
+ /// Params:
+ /// audioStreams = the audio streams to be muxed
+ /// desiredOutputSize = the desired size of the muxed output
+ /// nbOfFrames = number of frames of the source
+ /// useBframes = whether we have b-frames; the video
+ /// framerate = framerate of the video
+ /// videoSize = size of the raw video stream
+ /// Returns: the calculated bitrate
+ private int calculateMP4VideoBitrate(AudioStream[] audioStreams, long desiredOutputSizeBytes, ulong nbOfFrames,
+ bool useBframes, double framerate, out int videoSizeKB)
+ {
+ double mp4Overhead = this.getMP4Overhead(useBframes);
+ double totalOverhead = cast(double)nbOfFrames * mp4Overhead;
+ double nbOfSeconds = cast(double)nbOfFrames / framerate;
+ long audioSize = 0;
+ foreach (AudioStream stream; audioStreams)
+ {
+ audioSize += stream.SizeBytes;
+ }
+ long videoTargetSize = desiredOutputSizeBytes - audioSize - cast(long)totalOverhead;
+ videoSizeKB = rndint(videoTargetSize / 1024);
+ long sizeInBits = videoTargetSize * 8;
+ int bitrate = rndint(sizeInBits / (nbOfSeconds * 1000));
+ return bitrate;
+ }
+
+ /// calculates the size of a muxed mp4 file given the desired video bitrate and the audio streams to be muxed
+ /// Params:
+ /// audioStreams = the audio streams to be muxed with the video
+ /// desiredBitrate = the desired video bitrate
+ /// nbOfFrames = the number of frames of the video source
+ /// useBframes = whether the sources uses b-frames
+ /// framerate = the framerate of the source
+ /// rawVideoSize = the raw video size the stream will have; the container
+ /// Returns: the size of the mp4 file; KB
+ private long calculateMP4Size(AudioStream[] audioStreams, int desiredBitrate, ulong nbOfFrames, bool useBframes, double framerate, out int rawVideoSize)
+ {
+ double mp4Overhead = this.getMP4Overhead(useBframes);
+ double totalOverhead = cast(double)nbOfFrames * mp4Overhead;
+ double nbOfSeconds = cast(double)nbOfFrames / framerate;
+ double bytesPerSecond = desiredBitrate * 1000 / 8;
+ long videoSize = cast(long)(nbOfSeconds * bytesPerSecond);
+ rawVideoSize = rndint(videoSize / 1024);
+ long audioSize = 0;
+ foreach (AudioStream stream; audioStreams)
+ {
+ audioSize += stream.SizeBytes;
+ }
+ long size = videoSize + audioSize + cast(long)totalOverhead;
+ return size / 1024L;
+ }
+
+ /// calculates the bitrate a video with the given properties needs to have; order to be placed into a matroska file along with the
+ /// given audio tracks and end up having the desired size
+ /// Params:
+ /// audioStreams = te audio streams to be muxed with this video
+ /// desiredOutputSize = the final size of this file
+ /// nbOfFrames = number of frames of the video
+ /// framerate = framerate of the video
+ /// useBframes = whether the video uses b-frames
+ /// videoSize = size of the raw video stream; KB
+ /// Returns: the video bitrate; kbit/s
+ private int calculateMKVVideoBitrate(AudioStream[] audioStreams, long desiredOutputSize, ulong nbOfFrames, double framerate, bool useBframes, out int videoSize)
+ {
+ double totalOverhead = 0.0;
+ ulong nbIframes = nbOfFrames / 10;
+ ulong nbBframes = 0;
+ if (useBframes)
+ nbBframes = (nbOfFrames - nbIframes) / 2;
+ ulong nbPframes = nbOfFrames - nbIframes - nbBframes;
+ totalOverhead = cast(double)(4300 + 1400 + nbIframes * mkvIframeOverhead + nbPframes * mkvPframeOverhead +
+ nbBframes * mkvBframeOverhead);
+ double nbOfSeconds = cast(double)nbOfFrames / framerate;
+ totalOverhead += nbOfSeconds / 2.0 * 12; // 12 bytes per cluster
+ long audioSize = 0L;
+ double audioOverhead = 0;
+ foreach (AudioStream stream; audioStreams)
+ {
+ audioSize += stream.SizeBytes;
+ audioOverhead += getMKVAudioOverhead(stream.Type, 48000, nbOfSeconds);
+ }
+ long videoTargetSize = desiredOutputSize - audioSize - cast(long)audioOverhead -
+ cast(long)totalOverhead;
+ videoSize = rndint(videoTargetSize / 1024);
+ long sizeInBits = videoTargetSize * 8;
+ int bitrate = rndint(sizeInBits / (nbOfSeconds * 1000));
+ return bitrate;
+ }
+
+ /// calculates what size a given video and audio stream(s) will have at a given video bitrate
+ /// Params:
+ /// audioStreams = the audio streams to be considered
+ /// desiredBitrate = the desired video bitrate
+ /// nbOfFrames = number of frames of the video source
+ /// framerate = framerate of the video source
+ /// useBframes = whether we use b-frames for the video
+ /// rawVideoSize = the raw size of the video stream; KB
+ /// Returns: the size of the final file; KB
+ private long calculateMKVSize(AudioStream[] audioStreams, int desiredBitrate, ulong nbOfFrames, double framerate, bool useBframes, out int rawVideoSize)
+ {
+ double totalOverhead = 0.0;
+ ulong nbIframes = nbOfFrames / 10;
+ ulong nbBframes = 0;
+ if (useBframes)
+ nbBframes = (nbOfFrames - nbIframes) / 2;
+ ulong nbPframes = nbOfFrames - nbIframes - nbBframes;
+ totalOverhead = cast(double)(4300 + 1400 + nbIframes * mkvIframeOverhead + nbPframes * mkvPframeOverhead +
+ nbBframes * mkvBframeOverhead);
+ double nbOfSeconds = cast(double)nbOfFrames / framerate;
+ totalOverhead += nbOfSeconds / 2.0 * 12; // 12 bytes per cluster
+
+ long audioSize = 0L;
+ double audioOverhead = 0;
+ foreach (AudioStream stream; audioStreams)
+ {
+ audioSize += stream.SizeBytes;
+ audioOverhead += getMKVAudioOverhead(stream.Type, 48000, nbOfSeconds);
+ }
+
+ totalOverhead += audioOverhead;
+ double bytesPerSecond = desiredBitrate * 1000 / 8;
+ long videoSize = cast(long)(nbOfSeconds * bytesPerSecond);
+ rawVideoSize = rndint(videoSize / 1024);
+ long size = videoSize + audioSize + cast(long)totalOverhead;
+ return size / 1024L;
+ }
+
+ /// gets the overhead a given audio type will incurr; the matroska container
+ /// given its length and sampling rate
+ /// Params:
+ /// AudioType = type of the audio track
+ /// samplingRate = sampling rate of the audio track
+ /// length = length of the audio track
+ /// Returns: overhead this audio track will incurr
+ public int getMKVAudioOverhead(AudioType audioType, int samplingRate, double length)
+ {
+ if (audioType == 0)
+ return 0;
+ int nbSamples = rndint(cast(double)samplingRate * length);
+ int headerSize = mkvAudioTrackHeaderSize;
+ int samplesPerBlock = 0;
+ if (audioType == AudioType.MP4AAC)
+ samplesPerBlock = AACBlockSize;
+ else if (audioType == AudioType.VBRMP3 || audioType == AudioType.CBRMP3)
+ samplesPerBlock = MP3BlockSize;
+ else if (audioType == AudioType.AC3)
+ samplesPerBlock = AC3BlockSize;
+ else if (audioType == AudioType.VORBIS)
+ {
+ samplesPerBlock = VorbisBlockSize;
+ headerSize = mkvVorbisTrackHeaderSize;
+ }
+ else // unknown types.. we presume the same overhead as for DTS
+ {
+ samplesPerBlock = AC3BlockSize;
+ }
+ double blockOverhead = cast(double)nbSamples / cast(double)samplesPerBlock * 22.0 / 8.0;
+ int overhead = rndint(headerSize + 5 * length + blockOverhead);
+ return overhead;
+ }
+
+ /// calculates the AVI bitrate given the desired audio streams and video stream properties
+ /// Params:
+ /// audioStreams = the audio streams to be muxed to the video
+ /// desiredOutputSize = the desired final filesize
+ /// nbOfFrames = the number of frames of the source
+ /// framerate = the framerate of the source
+ /// videoSize = the size of the raw video stream
+ /// Returns: the bitrate; kbit/s
+ private int calculateAVIBitrate(AudioStream[] audioStreams, long desiredOutputSize, ulong nbOfFrames, double framerate, out int videoSize)
+ {
+ double videoOverhead = cast(double)nbOfFrames * aviVideoOverhead;
+ double nbOfSeconds = cast(double)nbOfFrames / framerate;
+ double totalOverhead = videoOverhead;
+ long audioSize = 0;
+ foreach (AudioStream stream; audioStreams)
+ {
+ audioSize += stream.SizeBytes;
+ if (stream.SizeBytes > 0)
+ {
+ double audioOverhead = getAviAudioOverhead(stream.Type);
+ totalOverhead += audioOverhead * nbOfFrames;
+ }
+ }
+ long videoTargetSize = desiredOutputSize - audioSize - cast(long)totalOverhead;
+ videoSize = rndint(videoTargetSize / 1024);
+ long sizeInBits = videoTargetSize * 8;
+ int bitrate = rndint(sizeInBits / (nbOfSeconds * 1000));
+ return bitrate;
+ }
+
+ private long calculateAVISize(AudioStream[] audioStreams, int desiredBitrate, ulong nbOfFrames, double framerate, out int rawVideoSize)
+ {
+ double videoOverhead = this.aviVideoOverhead;
+ double nbOfSeconds = cast(double)nbOfFrames / framerate;
+ long audioSize = 0L;
+ double audioOverhead = 0;
+ foreach (AudioStream stream; audioStreams)
+ {
+ audioSize += stream.SizeBytes;
+ if (stream.SizeBytes > 0)
+ audioOverhead += getAviAudioOverhead(stream.Type) * nbOfFrames;
+ }
+ double totalOverhead = videoOverhead + audioOverhead;
+ double bytesPerSecond = desiredBitrate * 1000 / 8;
+ long videoSize = cast(long)(nbOfSeconds * bytesPerSecond);
+ rawVideoSize = rndint(videoSize / 1024);
+ long size = videoSize + cast(long)audioSize + cast(long)totalOverhead;
+ return size / 1024L;
+ }
+
+ /// gets the avi container overhead given the type of audio file to be muxed
+ /// Params:
+ /// AudioType = the type of audio; question
+ /// Returns: the overhead per video frame for the given audio type
+ public double getAviAudioOverhead(AudioType audioType)
+ {
+ double audioOverhead = 0;
+ if (audioType == AudioType.AC3)
+ audioOverhead = ac3Overhead;
+ else if (audioType == AudioType.CBRMP3)
+ audioOverhead = cbrMP3Overhead;
+ else if (audioType == AudioType.VBRMP3)
+ audioOverhead = vbrMP3Overhead;
+ else if (audioType == AudioType.MP4AAC)
+ audioOverhead = 0;
+ else
+ audioOverhead = 0;
+ return audioOverhead;
+ }
+
+ ///
+ public int CalculateBitrateKBits(VideoCodec codec, bool useBframes, ContainerType container, AudioStream[] audioStreams, long desiredOutputSizeBytes, ulong nbOfFrames, double framerate, out int videoSizeKB)
+ {
+ if (container == ContainerType.MP4)
+ return calculateMP4VideoBitrate(audioStreams, desiredOutputSizeBytes, nbOfFrames, useBframes, framerate, videoSizeKB);
+ if (container == ContainerType.AVI)
+ return calculateAVIBitrate(audioStreams, desiredOutputSizeBytes, nbOfFrames, framerate, videoSizeKB);
+ if (container == ContainerType.MKV)
+ return calculateMKVVideoBitrate(audioStreams, desiredOutputSizeBytes, nbOfFrames, framerate, useBframes, videoSizeKB);
+
+ videoSizeKB = 0;
+ return 0;
+ }
+
+ ///
+ public long CalculateFileSizeKB(VideoCodec codec, bool useBframes, ContainerType container, AudioStream[] audioStreams, int desiredBitrate, ulong nbOfFrames, double framerate, out int rawVideoSize)
+ {
+ if (container == ContainerType.MP4)
+ return calculateMP4Size(audioStreams, desiredBitrate, nbOfFrames, useBframes, framerate, rawVideoSize);
+ if (container == ContainerType.AVI)
+ return calculateAVISize(audioStreams, desiredBitrate, nbOfFrames, framerate, rawVideoSize);
+ if (container == ContainerType.MKV)
+ return calculateMKVSize(audioStreams, desiredBitrate, nbOfFrames, framerate, useBframes, rawVideoSize);
+
+ rawVideoSize = 0;
+ return 0;
+ }
+
+ /// gets the video container overhead per frame given the b-frame choice
+ /// Params:
+ /// useBframes = whether we have b-frames; the source or not (causes a great increase; overhead)
+ /// Returns: the overhead per video frame
+ private double getMP4Overhead(bool useBframes)
+ {
+ if (useBframes)
+ return cast(double)mp4OverheadWithBframes;
+ else
+ return cast(double)mp4OverheadWithoutBframes;
+ }
+}
diff --git a/Gui.d b/Gui.d
new file mode 100644
index 0000000..d88e19d
--- /dev/null
+++ b/Gui.d
@@ -0,0 +1,683 @@
+module Gui;
+
+import gtk.Main;
+import gtk.MainWindow;
+import gtk.Alignment;
+import gtk.Button;
+import gtk.ToggleButton;
+import gtk.CheckButton;
+import gtk.RadioButton;
+import gtk.ComboBox;
+import gtk.SpinButton;
+import gtk.Label;
+import gtk.Frame;
+import gtk.HBox;
+import gtk.VBox;
+import gtk.Table;
+import gtk.Widget;
+import gtkc.gtktypes;
+import glib.ListSG;
+import tango.math.Math;
+
+import tango.io.Stdout;
+
+import BitrateCalculator;
+
+void main(char[][] args)
+{
+ Main.init(args);
+ new BitrateWindow();
+ Main.run();
+}
+
+public class BitrateWindow : MainWindow
+{
+ VideoFrame videoFrame;
+ AudioFrame audioFrame1;
+ AudioFrame audioFrame2;
+ ComboBox codecCombo;
+ ComboBox containCombo;
+ RadioButton fileRadio;
+ SpinButton sizeKBSpin;
+ SpinButton sizeMBSpin;
+ ComboBox mediumCombo;
+ RadioButton bitrRadio;
+ SpinButton bitrSpin;
+ SpinButton videoSizeKBSpin;
+ SpinButton videoSizeMBSpin;
+
+ bool handlingEvents;
+
+ this()
+ {
+ super("Bitrate Calculator");
+
+ Initialize();
+ CreateLayout();
+ SetDefaults();
+ SetEvents();
+
+ showAll();
+ }
+
+ void Initialize()
+ {
+ //Video
+ videoFrame = new VideoFrame;
+
+ //Audio
+ audioFrame1 = new AudioFrame("Audio 1");
+ audioFrame2 = new AudioFrame("Audio 2");
+
+ //Codec
+ codecCombo = new ComboBox(true);
+ foreach(char[] string; videoCodecs) codecCombo.appendText(string);
+
+ //Container
+ containCombo = new ComboBox(true);
+ foreach(char[] string; containerTypes) containCombo.appendText(string);
+
+ //Size
+ fileRadio = new RadioButton(cast(ListSG)null, "File Size");
+ sizeKBSpin = new SpinButton(0, int.max, 1);
+ sizeMBSpin = new SpinButton(0, int.max, 1);
+ mediumCombo = new ComboBox(true);
+ foreach(char[] string; storageMediums) mediumCombo.appendText(string);
+
+ //Results
+ bitrRadio = new RadioButton(fileRadio, "Average Bitrate");
+ bitrSpin = new SpinButton(0, int.max, 1);
+ videoSizeKBSpin = new SpinButton(0, int.max, 1);
+ videoSizeMBSpin = new SpinButton(0, int.max, 1);
+ }
+
+ void CreateLayout()
+ {
+ //Audio
+ HBox audioBox = new HBox(false, 4);
+ audioBox.add(audioFrame1);
+ audioBox.add(audioFrame2);
+
+ //Codec
+ Frame codecFrame = new Frame("Codec");
+
+ Alignment codecAlign = new Alignment(0, 0.5, 0.2, 0);
+ codecAlign.setPadding(4, 4, 4, 4);
+ codecAlign.add(codecCombo);
+
+ codecFrame.add(codecAlign);
+
+ //Container
+ Frame containFrame = new Frame("Container");
+
+ Alignment containAlign = new Alignment(0, 0.5, 0.2, 0);
+ containAlign.setPadding(4, 4, 4, 4);
+ containAlign.add(containCombo);
+
+ containFrame.add(containAlign);
+
+ //Size
+ Frame sizeFrame = new Frame("Total size");
+ Table sizeTable = new Table(3, 3, false);
+ sizeTable.setRowSpacings(5);
+ sizeTable.setColSpacings(5);
+
+ Alignment sizeAlign = new Alignment(0, 0.5, 0.2, 0);
+ sizeAlign.setPadding(4, 4, 4, 4);
+ sizeFrame.add(sizeAlign);
+
+ sizeTable.attachDefaults(fileRadio, 0, 1, 0, 1);
+ sizeTable.attachDefaults(sizeKBSpin, 1, 2, 0, 1);
+ sizeTable.attachDefaults(new Label("KB"), 2, 3, 0, 1);
+ sizeTable.attachDefaults(sizeMBSpin, 1, 2, 1, 2);
+ sizeTable.attachDefaults(new Label("MB"), 2, 3, 1, 2);
+ sizeTable.attachDefaults(new Label("Storage medium"), 0, 1, 2, 3);
+ sizeTable.attachDefaults(mediumCombo, 1, 2, 2, 3);
+ sizeAlign.add(sizeTable);
+
+ //Results
+ Frame resultFrame = new Frame("Results");
+ Table resultTable = new Table(3, 3, false);
+ resultTable.setRowSpacings(5);
+ resultTable.setColSpacings(5);
+
+ Alignment resultAlign = new Alignment(0, 0.5, 0.2, 0);
+ resultAlign.setPadding(4, 4, 4, 4);
+ resultFrame.add(resultAlign);
+
+ Alignment fileSizeAlign = new Alignment(1, 0.5, 0, 0);
+ fileSizeAlign.add(new Label("Video file size"));
+
+ resultTable.attachDefaults(bitrRadio, 0, 1, 0, 1);
+ resultTable.attachDefaults(bitrSpin, 1, 2, 0, 1);
+ resultTable.attachDefaults(new Label("kbit/s"), 2, 3, 0, 1);
+ resultTable.attachDefaults(fileSizeAlign, 0, 1, 1, 2);
+ resultTable.attachDefaults(videoSizeKBSpin, 1, 2, 1, 2);
+ resultTable.attachDefaults(new Label("KB"), 2, 3, 1, 2);
+ resultTable.attachDefaults(videoSizeMBSpin, 1, 2, 2, 3);
+ resultTable.attachDefaults(new Label("MB"), 2, 3, 2, 3);
+ resultAlign.add(resultTable);
+
+ //Left
+ VBox leftBox = new VBox(false, 4);
+
+ leftBox.add(videoFrame);
+ leftBox.add(audioBox);
+
+ //Right
+ VBox rightBox = new VBox(false, 4);
+
+ Alignment closeAlign = new Alignment(1, 1, 0.1, 0);
+ closeAlign.add(new Button(StockID.CLOSE, &OnClose));
+
+ rightBox.packStart(codecFrame, false, false, 0);
+ rightBox.packStart(containFrame, false, false, 0);
+ rightBox.packStart(sizeFrame, false, false, 0);
+ rightBox.packStart(resultFrame, false, false, 0);
+ rightBox.add(closeAlign);
+
+ //top
+ HBox topBox = new HBox(false, 6);
+ topBox.setBorderWidth(4);
+
+ topBox.add(leftBox);
+ topBox.add(rightBox);
+
+ this.add(topBox);
+ }
+
+ void SetDefaults()
+ {
+ handlingEvents = true;
+
+ codecCombo.setActive(1);
+ containCombo.setActive(0);
+ sizeKBSpin.setValue(storageMediumSizeKB[8]);
+ sizeMBSpin.setValue(rndint(cast(double)storageMediumSizeKB[8] / 1024));
+ mediumCombo.setActive(8);
+
+ handlingEvents = false;
+ }
+
+ void SetEvents()
+ {
+ videoFrame.addOnFramesChanged( &onFramesChanged);
+ videoFrame.addOnBFramesChanged(&onBFramesChanged);
+
+ audioFrame1.addOnAudioChanged(&onAudioChanged);
+ audioFrame2.addOnAudioChanged(&onAudioChanged);
+
+ codecCombo.addOnChanged( &OnCodecContainerChange);
+ containCombo.addOnChanged( &OnCodecContainerChange);
+
+ sizeKBSpin.addOnValueChanged( &OnSizeChange);
+ sizeMBSpin.addOnValueChanged( &OnSizeChange);
+ mediumCombo.addOnChanged( &OnMediumChange);
+
+ bitrSpin.addOnValueChanged( &OnBitrateChange);
+ videoSizeKBSpin.addOnValueChanged( &OnVideoSizeChange);
+ videoSizeMBSpin.addOnValueChanged( &OnVideoSizeChange);
+ }
+
+ public void onFramesChanged()
+ {
+ audioFrame1.setLengthInSeconds(videoFrame.getTotalLengthInSeconds);
+ audioFrame2.setLengthInSeconds(videoFrame.getTotalLengthInSeconds);
+
+ Calculate();
+ }
+
+ public void onBFramesChanged()
+ {
+ Calculate();
+ }
+
+ public void onAudioChanged()
+ {
+ Calculate();
+ }
+
+ public void OnCodecContainerChange(ComboBox cmb)
+ {
+ Calculate();
+ }
+
+ public void OnSizeChange(SpinButton spin)
+ {
+ if (handlingEvents) return;
+ handlingEvents = true;
+
+ fileRadio.setActive(true);
+
+ if(spin is sizeKBSpin)
+ sizeMBSpin.setValue(rndint(sizeKBSpin.getValue() / 1024));
+ else
+ sizeKBSpin.setValue(sizeMBSpin.getValueAsInt() * 1024);
+
+ Calculate();
+
+ handlingEvents = false;
+ }
+
+ public void OnMediumChange(ComboBox cmb)
+ {
+ if (handlingEvents) return;
+ handlingEvents = true;
+
+ fileRadio.setActive(true);
+
+ sizeKBSpin.setValue(storageMediumSizeKB[mediumCombo.getActive()]);
+ sizeMBSpin.setValue(rndint(cast(double)storageMediumSizeKB[mediumCombo.getActive()] / 1024));
+
+ Calculate();
+
+ handlingEvents = false;
+ }
+
+ public void OnBitrateChange(SpinButton spin)
+ {
+ if (handlingEvents) return;
+ handlingEvents = true;
+
+ bitrRadio.setActive(true);
+
+ Calculate();
+
+ handlingEvents = false;
+ }
+
+ public void OnVideoSizeChange(SpinButton spin)
+ {
+ if (handlingEvents) return;
+ handlingEvents = true;
+
+ bitrRadio.setActive(true);
+
+ Stdout(handlingEvents).newline;
+
+ if(spin is videoSizeMBSpin)
+ videoSizeMBSpin.setValue(rndint(videoSizeKBSpin.getValue() / 1024));
+ else
+ videoSizeKBSpin.setValue(videoSizeMBSpin.getValueAsInt() * 1024);
+
+ Stdout(handlingEvents).newline;
+
+ Calculate();
+
+ handlingEvents = false;
+ }
+
+
+ public void OnClose(Button btn)
+ {
+ Main.exit(0);
+ }
+
+ void Calculate()
+ {
+ handlingEvents = true;
+
+ BitrateCalculator bitr = new BitrateCalculator();
+
+ VideoCodec codec = cast(VideoCodec)codecCombo.getActive();
+ bool useBframes = videoFrame.getUseBFrames();
+ ContainerType container = cast(ContainerType)containCombo.getActive();
+ AudioStream [] audioStreams;
+ int nbOfFrames = videoFrame.getFrames();
+ double framerate = videoFrame.getFrameRate();
+ int videoSizeKB;
+
+ if(audioFrame1.getAudioStream.SizeBytes > 0)
+ audioStreams ~= audioFrame1.getAudioStream;
+ if(audioFrame2.getAudioStream.SizeBytes > 0)
+ audioStreams ~= audioFrame2.getAudioStream;
+
+ if(bitrRadio.getActive() == true) // calculate FileSize
+ {
+ int desiredBitrate = bitrSpin.getValueAsInt();
+
+ int sizeKB = bitr.CalculateFileSizeKB(codec, useBframes, container, audioStreams, desiredBitrate, nbOfFrames, framerate, videoSizeKB);
+
+ sizeKBSpin.setValue(sizeKB);
+ sizeMBSpin.setValue(rndint(cast(double)sizeKB / 1024));
+ }
+ else // calculate Bitrate
+ {
+ long desiredOutputSizeBytes = sizeKBSpin.getValueAsInt() * 1024L;
+
+ bitrSpin.setValue(bitr.CalculateBitrateKBits(codec, useBframes, container, audioStreams, desiredOutputSizeBytes, nbOfFrames, framerate, videoSizeKB));
+ }
+
+ videoSizeKBSpin.setValue(videoSizeKB);
+ videoSizeMBSpin.setValue(rndint(cast(double)videoSizeKB / 1024));
+
+ handlingEvents = false;
+ }
+}
+
+class VideoFrame : Frame
+{
+ void delegate()[] onFramesChangedDelegates;
+ void delegate()[] onBFramesChangedDelegates;
+
+ SpinButton hourSpin;
+ SpinButton minSpin;
+ SpinButton secSpin;
+ SpinButton totalSecSpin;
+ ComboBox frameRateCombo;
+ SpinButton framesSpin;
+ CheckButton bFramesCheckBtn;
+
+ bool handlingEvents;
+
+ public this(char[] title = "Video")
+ {
+ super(title);
+
+ hourSpin = new SpinButton(0, 40, 1);
+ hourSpin.setWidthChars(3);
+ minSpin = new SpinButton(0, 59, 1);
+ minSpin.setWidthChars(3);
+ secSpin = new SpinButton(0, 59, 1);
+ secSpin.setWidthChars(3);
+
+ HBox timeBox = new HBox(false, 4);
+ timeBox.add(new Label("Hours"));
+ timeBox.add(hourSpin);
+ timeBox.add(new Label("Minutes"));
+ timeBox.add(minSpin);
+ timeBox.add(new Label("Seconds"));
+ timeBox.add(secSpin);
+
+ totalSecSpin = new SpinButton(0, 363599, 1);
+ frameRateCombo = new ComboBox(true);
+ foreach(char[] string; frameRates) frameRateCombo.appendText(string);
+ framesSpin = new SpinButton(0, 9089975, 1);
+ bFramesCheckBtn = new CheckButton("B-frames");
+
+ Table videoTable = new Table(4, 2, false);
+ videoTable.setRowSpacings(5);
+ videoTable.attachDefaults(Alignment.west(new Label("Total lenght in seconds")), 0, 1, 0, 1);
+ videoTable.attachDefaults(totalSecSpin, 1, 2, 0, 1);
+ videoTable.attachDefaults(Alignment.west(new Label("Framerate")), 0, 1, 1, 2);
+ videoTable.attachDefaults(frameRateCombo, 1, 2, 1, 2);
+ videoTable.attachDefaults(Alignment.west(new Label("Number of frames")), 0, 1, 2, 3);
+ videoTable.attachDefaults(framesSpin, 1, 2, 2, 3);
+ videoTable.attachDefaults(bFramesCheckBtn, 0, 2, 3, 4);
+
+ VBox videoBox = new VBox(false, 4);
+ videoBox.setBorderWidth(4);
+ videoBox.add(timeBox);
+ videoBox.add(videoTable);
+
+ this.add(videoBox);
+
+ hourSpin.addOnValueChanged( &onTimeChanged);
+ minSpin.addOnValueChanged( &onTimeChanged);
+ secSpin.addOnValueChanged( &onTimeChanged);
+ totalSecSpin.addOnValueChanged( &onSecondsChanged);
+ frameRateCombo.addOnChanged( &onFrameRateChanged);
+ framesSpin.addOnValueChanged( &onFramesChanged);
+ bFramesCheckBtn.addOnToggled( &onBFramesChanged);
+
+ hourSpin.grabFocus();
+ frameRateCombo.setActive(2);
+ bFramesCheckBtn.setActive(true);
+ }
+
+ int getTotalLengthInSeconds()
+ { return totalSecSpin.getValueAsInt(); }
+
+ double getFrameRate()
+ { return FrameRate[frameRateCombo.getActive()]; }
+
+ int getFrames()
+ { return framesSpin.getValueAsInt(); }
+
+ bool getUseBFrames()
+ { return cast(bool)bFramesCheckBtn.getActive(); }
+
+ void addOnFramesChanged(void delegate() dlg)
+ {
+ onFramesChangedDelegates ~= dlg;
+ }
+ void framesChanged()
+ {
+ foreach(dlg; onFramesChangedDelegates)
+ dlg();
+ }
+
+ void addOnBFramesChanged(void delegate() dlg)
+ {
+ onBFramesChangedDelegates ~= dlg;
+ }
+ void bFramesChanged()
+ {
+ foreach(dlg; onBFramesChangedDelegates)
+ dlg();
+ }
+
+ void onTimeChanged(SpinButton sb)
+ {
+ if (handlingEvents) return;
+ handlingEvents = true;
+
+ int seconds = hourSpin.getValueAsInt * 3600;
+ seconds += minSpin.getValueAsInt * 60;
+ seconds += secSpin.getValueAsInt;
+
+ totalSecSpin.setValue(seconds);
+
+ framesSpin.setValue(cast(int)(seconds * FrameRate[frameRateCombo.getActive()]));
+ framesChanged();
+
+ handlingEvents = false;
+ }
+
+ void onSecondsChanged(SpinButton sb)
+ {
+ if (handlingEvents) return;
+ handlingEvents = true;
+
+ CalculateTime();
+
+ framesSpin.setValue(cast(int)(totalSecSpin.getValue() * FrameRate[frameRateCombo.getActive()]));
+ framesChanged();
+
+ handlingEvents = false;
+ }
+
+ void onFrameRateChanged(ComboBox cb)
+ {
+ framesSpin.setValue(rndint(totalSecSpin.getValue() * FrameRate[frameRateCombo.getActive()]));
+ }
+
+ void onFramesChanged(SpinButton sb)
+ {
+ if (handlingEvents) return;
+ handlingEvents = true;
+
+ framesChanged();
+
+ totalSecSpin.setValue(rndint(framesSpin.getValue() / FrameRate[frameRateCombo.getActive()]));
+
+ CalculateTime();
+
+ handlingEvents = false;
+ }
+
+ void onBFramesChanged(ToggleButton tb)
+ {
+ bFramesChanged();
+ }
+
+ public void CalculateTime()
+ {
+ int seconds = totalSecSpin.getValueAsInt();
+
+ hourSpin.setValue(cast(int)floor(seconds / 3600));
+ seconds -= hourSpin.getValueAsInt() * 3600;
+
+ minSpin.setValue(cast(int)floor(seconds / 60));
+ seconds -= minSpin.getValueAsInt() * 60;
+
+ secSpin.setValue(seconds);
+ }
+}
+
+class AudioFrame : Frame
+{
+ void delegate()[] onAudioChangedDelegates;
+
+ SpinButton bitrSpin;
+ SpinButton sizeKBSpin;
+ SpinButton sizeMBSpin;
+ ComboBox typeCombo;
+
+ bool handlingEvents;
+ int totalLengthInSeconds;
+ AudioStream audioStream;
+
+ public this(char[] title = "Audio")
+ {
+ super(title);
+
+ bitrSpin = new SpinButton(0, 1000, 1);
+ sizeKBSpin = new SpinButton(0, int.max, 1);
+ sizeMBSpin = new SpinButton(0, int.max, 1);
+ typeCombo = new ComboBox(true);
+ foreach(char[] string; audioTypes) typeCombo.appendText(string);
+
+ Alignment clearAlign = new Alignment(1, 0.5, 0.2, 0);
+ clearAlign.add(new Button(StockID.CLEAR, &OnClearAudio));
+
+ HBox kbBox = new HBox(false, 0);
+ kbBox.add(sizeKBSpin);
+ kbBox.add(new Label("KB"));
+
+ HBox mbBox = new HBox(false, 0);
+ mbBox.add(sizeMBSpin);
+ mbBox.add(new Label("MB"));
+
+ HBox typeBox = new HBox(false, 0);
+ typeBox.add(new Label("Type"));
+ typeBox.add(typeCombo);
+
+ VBox audioBox = new VBox(false, 4);
+ audioBox.setBorderWidth(4);
+ audioBox.add(new Label("Bitrate"));
+ audioBox.add(bitrSpin);
+ audioBox.add(new Label("Size"));
+ audioBox.add(kbBox);
+ audioBox.add(mbBox);
+ audioBox.add(typeBox);
+ audioBox.add(clearAlign);
+
+ this.add(audioBox);
+
+ bitrSpin.addOnValueChanged( &OnAudioBitrateChange);
+ sizeKBSpin.addOnValueChanged( &OnAudioSizeChange);
+ sizeMBSpin.addOnValueChanged( &OnAudioSizeChange);
+ typeCombo.addOnChanged( &OnAudioTypeChange);
+
+ typeCombo.setActive(0);
+ }
+
+ void setLengthInSeconds(int length)
+ {
+ totalLengthInSeconds = length;
+ CalculateAudioSize();
+ }
+
+ AudioStream getAudioStream()
+ {
+ return audioStream;
+ }
+
+ void addOnAudioChanged(void delegate() dlg)
+ {
+ onAudioChangedDelegates ~= dlg;
+ }
+ void audioChanged()
+ {
+ foreach(dlg; onAudioChangedDelegates)
+ dlg();
+ }
+
+ public void OnAudioBitrateChange(SpinButton spin)
+ {
+ if (handlingEvents) return;
+ handlingEvents = true;
+
+ CalculateAudioSize();
+ audioChanged();
+
+ handlingEvents = false;
+ }
+
+ public void OnAudioSizeChange(SpinButton spin)
+ {
+ if (handlingEvents) return;
+ handlingEvents = true;
+
+ if(spin is sizeMBSpin)
+ {
+ sizeKBSpin.setValue(sizeMBSpin.getValueAsInt() * 1024);
+ audioStream.SizeBytes = sizeKBSpin.getValueAsInt() * 1024;
+ }
+ else if(spin is sizeKBSpin)
+ {
+ sizeMBSpin.setValue(rndint(sizeKBSpin.getValue() / 1024));
+ audioStream.SizeBytes = sizeKBSpin.getValueAsInt() * 1024;
+ }
+
+ audioChanged();
+ CalculateAudioBitrate();
+
+ handlingEvents = false;
+ }
+
+ public void OnAudioTypeChange(ComboBox cmb)
+ {
+ audioStream.Type = cast(AudioType)typeCombo.getActive();
+ audioChanged();
+ }
+
+ public void OnClearAudio(Button btn)
+ {
+ bitrSpin.setValue(0);
+ sizeKBSpin.setValue(0);
+ sizeMBSpin.setValue(0);
+ typeCombo.setActive(0);
+
+ audioStream = AudioStream.init;
+ audioChanged();
+ }
+
+ void CalculateAudioSize()
+ {
+ double CalculateSize(int bitrate)
+ {
+ double bytesPerSecond = cast(double)bitrate * 1000 / 8;
+ return (totalLengthInSeconds * bytesPerSecond);
+ return 100;
+ }
+
+ double sizeInBytes = CalculateSize(bitrSpin.getValueAsInt());
+
+ audioStream.SizeBytes = rndlong(sizeInBytes);
+ sizeKBSpin.setValue(rndint(sizeInBytes / 1024));
+ sizeMBSpin.setValue(rndint(sizeInBytes / 1024 / 1024));
+ }
+
+ void CalculateAudioBitrate()
+ {
+ int CalculateBitrate(long sizeInBytes)
+ {
+ double bytesPerSecond = sizeInBytes / totalLengthInSeconds;
+ return cast(int)floor(bytesPerSecond * 8 / 1000);
+ }
+
+ bitrSpin.setValue(CalculateBitrate(audioStream.SizeBytes));
+ }
+}
diff --git a/dsss.conf b/dsss.conf
new file mode 100644
index 0000000..5aa6e2f
--- /dev/null
+++ b/dsss.conf
@@ -0,0 +1,8 @@
+requires = gtkD
+
+[Gui.d]
+type = binary
+target = bitratecalc
+buildflags = -L-ldl
+
+postbuild = strip bitratecalc
diff --git a/gpl.txt b/gpl.txt
new file mode 100644
index 0000000..9285110
--- /dev/null
+++ b/gpl.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.