Added a number of new codecs as options.
Some supporting cleanups including changing --cq parameter
to be a --codec parameter.
Change-Id: Ib699a91787654b620bcf4b19b25bb11932d8900b
diff --git a/.gitignore b/.gitignore
index b25c15b..54b205f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,12 @@
+# Files and extensions that GIT should not bother mentioning.
+*.pyc
*~
+# Directories not under GIT control
+/logs
+/video
+/mpeg_video
+/stats
+/tweaker/vp8
+/tweaker/h261
+/tweaker/h263
+/tweaker/mjpeg
diff --git a/tweaker/best_is_scored b/tweaker/best_is_scored
index a02a217..a9f67c3 100755
--- a/tweaker/best_is_scored
+++ b/tweaker/best_is_scored
@@ -1,9 +1,7 @@
#!/usr/bin/python
"""Make sure the best encoding for a rate/file has a score.
-Usage: vp8tweaker [--cq] <rate> <videofile>
-
-This script consults the run database for the VP8 codec,
+This script consults the run database for the codec,
picks the best encoding so far, and makes sure it's executed.
This ensures that at least one executed encoding exists for this
parameter set.
@@ -12,23 +10,19 @@
import argparse
import sys
-from vp8 import Vp8Codec
-from vp8_cq import Vp8CodecCqMode
-from encoder import Videofile
+import encoder
+import pick_codec
def main():
parser = argparse.ArgumentParser()
parser.add_argument('rate')
parser.add_argument('videofile')
- parser.add_argument("--cq", action="store_true", dest="cq_mode")
+ parser.add_argument('--codec')
args = parser.parse_args()
- videofile = Videofile(args.videofile)
+ videofile = encoder.Videofile(args.videofile)
- if args.cq_mode:
- codec = Vp8CodecCqMode()
- else:
- codec = Vp8Codec()
+ codec = pick_codec.PickCodec(args.codec)
bitrate = int(args.rate)
@@ -40,6 +34,7 @@
bestsofar.Store()
print "Best encoder is", bestsofar.encoder.Hashname(), \
"score", bestsofar.Score()
+ return 0
if __name__ == '__main__':
sys.exit(main())
diff --git a/tweaker/best_mpeg_settings b/tweaker/best_mpeg_settings
index 982d41d..7663ada 100755
--- a/tweaker/best_mpeg_settings
+++ b/tweaker/best_mpeg_settings
@@ -3,16 +3,25 @@
# List the best MPEG settings for CQ mode encodings.
#
-import mpeg_settings
-from encoder import Videofile
-from vp8_cq import Vp8CodecCqMode
+import argparse
+import sys
-def ListOne(file_stem, rate):
+import encoder
+import mpeg_settings
+
+import pick_codec
+
+def ListOne(codec, file_stem, rate, run_score):
"""Output one line describing the best encoding for this file."""
file = '../mpeg_video/' + file_stem
- videofile = Videofile(file)
- codec = Vp8CodecCqMode()
+ videofile = encoder.Videofile(file)
bestsofar = codec.BestEncoding(rate, videofile)
+ if not bestsofar.Score():
+ if run_score:
+ bestsofar.Execute()
+ bestsofar.Store()
+ else:
+ return (0, 0)
cq = bestsofar.encoder.OptionValue('min-q')
# Compute how many percent we are below the target bitrate.
# Numbers far below the target indicate room for improvement.
@@ -24,18 +33,32 @@
file_stem, rate,\
bestsofar.result['bitrate'], bestsofar.result['psnr'], \
bitsleft, '%'
- return bitsleft
+ return (1, bitsleft)
-def ListBest():
+def ListBest(codec, run_score):
count = 0
wasted = 0.0
+ overrun = 0
for classname in mpeg_settings.files.keys():
for file in mpeg_settings.files[classname]:
for rate in mpeg_settings.rates[classname]:
- count += 1
- wasted += ListOne(file, rate)
+ (this_count, this_wasted) = ListOne(codec, file, rate, run_score)
+ count += this_count
+ wasted += this_wasted
+ if wasted < 0.0:
+ overrun += 1
print "Average waste ", wasted / count, "%"
+ print "Number scored: %d, over target rate %d" % (count, overrun)
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--codec', default = 'vp8_cq')
+ parser.add_argument('--score', action='store_true', default=False)
+ args = parser.parse_args()
+ codec = pick_codec.PickCodec(args.codec)
+ ListBest(codec, args.score)
+ return 0
if __name__ == '__main__':
- ListBest()
+ sys.exit(main())
diff --git a/tweaker/compare_codecs b/tweaker/compare_codecs
new file mode 100755
index 0000000..f93ae28
--- /dev/null
+++ b/tweaker/compare_codecs
@@ -0,0 +1,39 @@
+#!/usr/bin/python
+#
+# Compare a number of codecs for what they do when presented with the
+# "MPEG" test suite.
+#
+# Outputs a table with the samples down and the codecs across, giving
+# bitrate and PSNR for each target.
+#
+import argparse
+import sys
+
+import mpeg_settings
+import encoder
+import pick_codec
+
+def ListOneTarget(rate, videofile):
+ print '%-28.28s %5d ' % (videofile.basename, rate),
+ for codec_name in ('h261', 'h263', 'mjpeg', 'vp8'):
+ codec = pick_codec.PickCodec(codec_name)
+ bestsofar = codec.BestEncoding(rate, videofile)
+ assert(bestsofar.Score())
+ print '%6d %4.1f' % (bestsofar.result['bitrate'], bestsofar.result['psnr']),
+ print ''
+
+def ListResults():
+ print '%-28s %5s %11s %11s %11s %11s' % (
+ 'File', 'Rate', 'H.261', 'H.263p', 'MJPEG', 'VP8')
+ for classname in mpeg_settings.files.keys():
+ for filename in mpeg_settings.files[classname]:
+ videofile = encoder.Videofile(filename)
+ for rate in mpeg_settings.rates[classname]:
+ ListOneTarget(rate, videofile)
+
+def main():
+ ListResults()
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/tweaker/encoder.py b/tweaker/encoder.py
index 71550b8..6f37c5c 100644
--- a/tweaker/encoder.py
+++ b/tweaker/encoder.py
@@ -129,13 +129,24 @@
raise Error("Unable to parse filename " + filename)
self.basename = os.path.splitext(os.path.basename(filename))[0]
+ def MeasuredBitrate(self, encodedsize):
+ """Returns bitrate of an encoded file in kilobits per second.
+
+ Argument: Encoded file size in bytes.
+ """
+ # YUV is 8 bits per pixel for Y, 1/4 that for each of U and V.
+ framesize = self.width * self.height * 3 / 2
+ framecount = os.path.getsize(self.filename) / framesize
+ encodedframesize = encodedsize / framecount
+ return encodedframesize * self.framerate * 8 / 1000
class Codec(object):
"""Abstract class representing a codec.
Subclasses must define the name, options and start_encoder variables
"""
- def __init__(self, cache=None):
+ def __init__(self, name, cache=None):
+ self.name = name
if cache:
self.cache = cache
else:
@@ -159,6 +170,7 @@
return config
def RandomlyChangeConfig(self, parameters):
+ assert(len(self.options) >= 1)
option_to_change = self.options[random.randint(0, len(self.options)-1)]
config = option_to_change.RandomlyPatchConfig(parameters)
return self.ConfigurationFixups(config)
diff --git a/tweaker/encoder_unittest.py b/tweaker/encoder_unittest.py
index 8be1c57..99c4f2f 100755
--- a/tweaker/encoder_unittest.py
+++ b/tweaker/encoder_unittest.py
@@ -8,8 +8,7 @@
class DummyCodec(encoder.Codec):
def __init__(self):
- super(DummyCodec, self).__init__(encoder.EncodingMemoryCache(self))
- self.name = 'dummy'
+ super(DummyCodec, self).__init__('dummy', encoder.EncodingMemoryCache(self))
self.extension = 'fake'
self.options = [
encoder.Option('score', ['0', '5', '10']),
@@ -79,6 +78,12 @@
config = '--foo=5'
self.assertEqual(option.RandomlyPatchConfig(config), '--foo=6')
+ def test_ChoiceOption(self):
+ config = '--foo'
+ option = encoder.ChoiceOption(['foo', 'bar'])
+ newconfig = option.RandomlyPatchConfig(config)
+ self.assertEqual(newconfig, '--bar')
+
class TestCodec(unittest.TestCase):
def setUp(self):
@@ -94,7 +99,6 @@
codec.BestEncoding(100, self.videofile).Store()
encoding = codec.BestEncoding(100, self.videofile)
self.assertEqual(encoding.videofile, self.videofile)
-
def test_BestEncodingExecuteGivesScore(self):
codec = DummyCodec()
codec.BestEncoding(100, self.videofile).Execute().Store()
diff --git a/tweaker/ffmpeg.py b/tweaker/ffmpeg.py
new file mode 100644
index 0000000..5d83402
--- /dev/null
+++ b/tweaker/ffmpeg.py
@@ -0,0 +1,71 @@
+"""Framework for specifying encoders from ffmpeg.
+
+This uses ffmpeg for encoding and decoding.
+The default FFMPEG encoder uses mpeg4, so that we can see if it's roughly
+compatible with the vpxenc-produced qualities.
+"""
+import os
+import re
+import subprocess
+
+import encoder
+
+class FfmpegCodec(encoder.Codec):
+ def __init__(self, name='ffmpeg-mpeg4'):
+ # Subclasses need to override name, codecname and extension.
+ # At the moment, no parameters are defined.
+ self.name = name
+ self.codecname = 'mpeg4'
+ self.extension = 'avi'
+ super(FfmpegCodec, self).__init__(name)
+ self.options = [
+ ]
+ self.start_encoder = encoder.Encoder(self, '')
+
+ def Execute(self, parameters, bitrate, videofile, workdir):
+ commandline = (
+ '../bin/ffmpeg %s -s %dx%d -i %s -codec:v %s -b:v %dk -y %s/%s.%s' % (
+ parameters, videofile.width, videofile.height,
+ videofile.filename, self.codecname,
+ bitrate, workdir, videofile.basename, self.extension))
+ print commandline
+ returncode = subprocess.call(commandline, shell=True)
+ if returncode:
+ raise Exception("Encode failed with returncode " + str(returncode))
+ return self.Measure(bitrate, videofile, workdir)
+
+ def Measure(self, bitrate, videofile, workdir):
+ result = {}
+ tempyuvfile = "%s/%stempyuvfile.yuv" % (workdir, videofile.basename)
+ if os.path.isfile(tempyuvfile):
+ print "Removing tempfile before decode:", tempyuvfile
+ os.unlink(tempyuvfile)
+ commandline = "../bin/ffmpeg -codec:v %s -i %s/%s.%s %s" % (
+ self.codecname,
+ workdir, videofile.basename, self.extension, tempyuvfile)
+ print commandline
+ returncode = subprocess.call(commandline, shell=True)
+ if returncode:
+ raise encoder.Error('Decode failed')
+ bitrate = videofile.MeasuredBitrate(
+ os.path.getsize('%s/%s.%s' % (workdir, videofile.basename,
+ self.extension)))
+ commandline = "../bin/psnr %s %s %d %d 9999" % (
+ videofile.filename, tempyuvfile, videofile.width,
+ videofile.height)
+ print commandline
+ psnr = subprocess.check_output(commandline, shell=True)
+ print "Bitrate", bitrate, "PSNR", psnr
+ result['bitrate'] = int(bitrate)
+ result['psnr'] = float(psnr)
+ os.unlink(tempyuvfile)
+ return result
+
+ def ScoreResult(self, target_bitrate, result):
+ if not result:
+ return None
+ score = result['psnr']
+ if result['bitrate'] > int(target_bitrate):
+ score -= (result['bitrate'] - int(target_bitrate)) * 0.1
+ return score
+
diff --git a/tweaker/h261.py b/tweaker/h261.py
new file mode 100644
index 0000000..71c1b19
--- /dev/null
+++ b/tweaker/h261.py
@@ -0,0 +1,69 @@
+"""H.261 codec.
+
+This uses ffmpeg for encoding and decoding.
+"""
+import os
+import re
+import subprocess
+
+import encoder
+import ffmpeg
+
+class H261Codec(ffmpeg.FfmpegCodec):
+ def __init__(self, name='h261'):
+ super(H261Codec, self).__init__(name)
+ self.codecname = 'h261'
+ self.extension = 'h261'
+ self.start_encoder = encoder.Encoder(self, """\
+ """)
+
+ def Execute(self, parameters, bitrate, videofile, workdir):
+ # TODO(hta): Merge the common parts of this with vp8.Execute.
+ commandline = (
+ '../bin/ffmpeg %s -s %dx%d -i %s -codec:v %s -b:v %dk -y -s 352x288 %s/%s.%s' % (
+ parameters, videofile.width, videofile.height,
+ videofile.filename, self.codecname,
+ str(bitrate), workdir, videofile.basename, self.extension))
+
+ print commandline
+ returncode = subprocess.call(commandline, shell=True)
+ if returncode:
+ raise Exception("Encode failed with returncode " + str(returncode))
+ return self.Measure(bitrate, videofile, workdir)
+
+ def Measure(self, bitrate, videofile, workdir):
+ result = {}
+ tempyuvfile = "%s/%stempyuvfile.yuv" % (workdir, videofile.basename)
+ if os.path.isfile(tempyuvfile):
+ print "Removing tempfile before decode:", tempyuvfile
+ os.unlink(tempyuvfile)
+ # The special thing here is that it rescales back to the original size.
+ # TODO(hta): Factor out the difference by itself.
+ commandline = "../bin/ffmpeg -i %s/%s.h261 -s %sx%s %s" % (
+ workdir, videofile.basename, videofile.width, videofile.height,
+ tempyuvfile)
+ print commandline
+ returncode = subprocess.call(commandline, shell=True)
+ if returncode:
+ raise encoder.Error('Decode failed')
+ bitrate = videofile.MeasuredBitrate(
+ os.path.getsize('%s/%s.h261' % (workdir, videofile.basename)))
+ commandline = "../bin/psnr %s %s %d %d 9999" % (
+ videofile.filename, tempyuvfile, videofile.width,
+ videofile.height)
+ print commandline
+ psnr = subprocess.check_output(commandline, shell=True)
+ print "Bitrate", bitrate, "PSNR", psnr
+ result['bitrate'] = int(bitrate)
+ result['psnr'] = float(psnr)
+ os.unlink(tempyuvfile)
+ return result
+
+ def ScoreResult(self, target_bitrate, result):
+ if not result:
+ return None
+ score = result['psnr']
+ if result['bitrate'] > int(target_bitrate):
+ score -= (result['bitrate'] - int(target_bitrate)) * 0.1
+ return score
+
diff --git a/tweaker/h263.py b/tweaker/h263.py
new file mode 100644
index 0000000..162c773
--- /dev/null
+++ b/tweaker/h263.py
@@ -0,0 +1,11 @@
+"""H.263 codec.
+We use the H.263+ variant for its free scalability.
+"""
+
+import ffmpeg
+
+class H263Codec(ffmpeg.FfmpegCodec):
+ def __init__(self, name='h263'):
+ super(H263Codec, self).__init__(name)
+ self.codecname = 'h263p'
+ self.extension = 'avi'
diff --git a/tweaker/listconfigs b/tweaker/listconfigs
index 97098e0..a4d62ae 100755
--- a/tweaker/listconfigs
+++ b/tweaker/listconfigs
@@ -4,28 +4,23 @@
"""
import argparse
-import re
import sys
-from vp8 import Vp8Codec
-from vp8_cq import Vp8CodecCqMode
-from encoder import Videofile
+import encoder
+import pick_codec
+
def main():
parser = argparse.ArgumentParser()
parser.add_argument('rate')
parser.add_argument('videofile')
- parser.add_argument("--cq", action="store_true", dest="cq_mode")
+ parser.add_argument("--codec")
+
args = parser.parse_args()
- print "CQ mode is", args.cq_mode
+ videofile = encoder.Videofile(args.videofile)
- videofile = Videofile(args.videofile)
-
- if args.cq_mode:
- codec = Vp8CodecCqMode()
- else:
- codec = Vp8Codec()
+ codec = pick_codec.PickCodec(args.codec)
bitrate = int(args.rate)
@@ -37,6 +32,5 @@
print encoding.encoder.Hashname(), best, minq, encoding.Score(), \
encoding.result
-
if __name__ == '__main__':
sys.exit(main())
diff --git a/tweaker/mjpeg.py b/tweaker/mjpeg.py
new file mode 100644
index 0000000..4c662e7
--- /dev/null
+++ b/tweaker/mjpeg.py
@@ -0,0 +1,19 @@
+"""Motion JPEG codec.
+
+This uses ffmpeg for encoding and decoding.
+"""
+import os
+import re
+import subprocess
+
+import encoder
+import ffmpeg
+
+class MotionJpegCodec(ffmpeg.FfmpegCodec):
+ def __init__(self, name='mjpeg'):
+ super(MotionJpegCodec, self).__init__(name)
+ self.codecname = 'mjpeg'
+ self.extension = 'mjpeg'
+ self.options = [
+ ]
+ self.start_encoder = encoder.Encoder(self, '')
diff --git a/tweaker/pick_codec.py b/tweaker/pick_codec.py
new file mode 100644
index 0000000..184d66a
--- /dev/null
+++ b/tweaker/pick_codec.py
@@ -0,0 +1,27 @@
+"""A codec picker."""
+
+import encoder
+import h261
+import h263
+import mjpeg
+import vp8
+import vp8_cq
+import ffmpeg
+
+codec_map = {
+ 'vp8': vp8.Vp8Codec,
+ 'vp8_cq' : vp8_cq.Vp8CodecCqMode,
+ 'ffmpeg' : ffmpeg.FfmpegCodec,
+ 'mjpeg' : mjpeg.MotionJpegCodec,
+ 'h261': h261.H261Codec,
+ 'h263': h263.H263Codec
+}
+
+def PickCodec(name):
+ if name is None:
+ name = 'vp8'
+ if name in codec_map:
+ return codec_map[name]()
+ raise encoder.Error('Unrecognized codec name %s' % name)
+
+
diff --git a/tweaker/vp8.py b/tweaker/vp8.py
index 026be21..5c20b46 100644
--- a/tweaker/vp8.py
+++ b/tweaker/vp8.py
@@ -9,33 +9,29 @@
import os
import subprocess
-from encoder import Codec
-from encoder import Encoder
-from encoder import Option
-from encoder import ChoiceOption
+import encoder
-class Vp8Codec(Codec):
- def __init__(self):
- self.name = 'vp8'
- super(Vp8Codec, self).__init__()
+class Vp8Codec(encoder.Codec):
+ def __init__(self, name='vp8'):
+ super(Vp8Codec, self).__init__(name)
self.extension = 'webm'
self.options = [
- Option('overshoot-pct', ['0', '15', '30', '45']),
- Option('undershoot-pct', ['0', '25', '50', '75', '100']),
+ encoder.Option('overshoot-pct', ['0', '15', '30', '45']),
+ encoder.Option('undershoot-pct', ['0', '25', '50', '75', '100']),
# CQ mode is not considered for end-usage at the moment.
- Option('end-usage', ['cbr', 'vbr']),
+ encoder.Option('end-usage', ['cbr', 'vbr']),
# End-usage cq doesn't really make sense unless we also set q to something
# between min and max. This is being checked.
- # Option('end-usage', ['cbr', 'vbr', 'cq']),
- Option('end-usage', ['cbr', 'vbr']),
- Option('min-q', ['0', '2', '4', '8', '16', '24']),
- Option('max-q', ['32', '56', '63']),
- Option('buf-sz', ['200', '500', '1000', '2000', '4000', '8000', '16000']),
- Option('buf-initial-sz', ['200', '400', '800', '1000', '2000', '4000', '8000', '16000']),
- Option('max-intra-rate', ['100', '200', '400', '600', '800', '1200']),
- ChoiceOption(['good', 'best', 'rt']),
+ # encoder.Option('end-usage', ['cbr', 'vbr', 'cq']),
+ encoder.Option('end-usage', ['cbr', 'vbr']),
+ encoder.Option('min-q', ['0', '2', '4', '8', '16', '24']),
+ encoder.Option('max-q', ['32', '56', '63']),
+ encoder.Option('buf-sz', ['200', '500', '1000', '2000', '4000', '8000', '16000']),
+ encoder.Option('buf-initial-sz', ['200', '400', '800', '1000', '2000', '4000', '8000', '16000']),
+ encoder.Option('max-intra-rate', ['100', '200', '400', '600', '800', '1200']),
+ encoder.ChoiceOption(['good', 'best', 'rt']),
]
- self.start_encoder = Encoder(self, """ --lag-in-frames=0 \
+ self.start_encoder = encoder.Encoder(self, """ --lag-in-frames=0 \
--kf-min-dist=3000 \
--kf-max-dist=3000 --cpu-used=0 --static-thresh=0 \
--token-parts=1 --drop-frame=0 --end-usage=cbr --min-q=2 --max-q=56 \
@@ -44,6 +40,7 @@
--resize-allowed=0 --drop-frame=0 --passes=1 --good --noise-sensitivity=0 """)
def Execute(self, parameters, bitrate, videofile, workdir):
+ nullinput = open('/dev/null', 'r')
commandline = ("../bin/vpxenc " + parameters
+ ' --target-bitrate=' + str(bitrate)
+ ' --fps=' + str(videofile.framerate) + '/1'
@@ -56,7 +53,7 @@
with open('/dev/null', 'r') as nullinput:
returncode = subprocess.call(commandline, shell=True, stdin=nullinput)
if returncode:
- raise Exception("Encode failed with returncode " + str(returncode))
+ raise Exception("Encode failed with returncode %d" % returncode)
return self.Measure(bitrate, videofile, workdir)
def Measure(self, bitrate, videofile, workdir):
diff --git a/tweaker/vp8_cq.py b/tweaker/vp8_cq.py
index 73c6861..dbaf83c 100644
--- a/tweaker/vp8_cq.py
+++ b/tweaker/vp8_cq.py
@@ -9,15 +9,12 @@
import subprocess
import encoder
-
import vp8
-
class Vp8CodecCqMode(vp8.Vp8Codec):
def __init__(self):
- super(Vp8CodecCqMode, self).__init__()
+ super(Vp8CodecCqMode, self).__init__('vp8-cq')
# Set the parts that are different from the VP8 codec.
- self.name = 'vp8-cq'
self.options = [
encoder.IntegerOption('min-q', 0, 63),
encoder.ChoiceOption(['good', 'best', 'rt']),
diff --git a/tweaker/vp8_cq_unittest.py b/tweaker/vp8_cq_unittest.py
index e58fad8..87cea6a 100755
--- a/tweaker/vp8_cq_unittest.py
+++ b/tweaker/vp8_cq_unittest.py
@@ -9,6 +9,7 @@
class TestVp8Cq(unittest.TestCase):
def test_Init(self):
codec = vp8_cq.Vp8CodecCqMode()
+ self.assertEqual('vp8-cq', codec.name)
# Verifying that the default config's value for min-q is still 32.
# This is required for later tests to work properly.
self.assertEqual('32', encoder.Option('min-q').GetValue(
diff --git a/tweaker/vp8_unittest.py b/tweaker/vp8_unittest.py
index 5010e5f..e586141 100755
--- a/tweaker/vp8_unittest.py
+++ b/tweaker/vp8_unittest.py
@@ -9,6 +9,7 @@
class TestVp8(unittest.TestCase):
def test_Init(self):
codec = vp8.Vp8Codec()
+ self.assertEqual(codec.name, 'vp8')
def test_ScoreResult(self):
codec = vp8.Vp8Codec()
diff --git a/tweaker/vp8tweaker b/tweaker/vp8tweaker
index da1e5c7..005f675 100755
--- a/tweaker/vp8tweaker
+++ b/tweaker/vp8tweaker
@@ -13,9 +13,8 @@
import argparse
import sys
-import vp8
import encoder
-import vp8_cq
+import pick_codec
def main():
parser = argparse.ArgumentParser()
@@ -23,21 +22,23 @@
parser.add_argument('videofile')
parser.add_argument("--loop", action="store_true", dest="loop")
parser.add_argument("--until_score", type=float)
- parser.add_argument("--cq", action="store_true", dest="cq_mode")
+ parser.add_argument("--codec")
args = parser.parse_args()
print "Loop is", args.loop
- print "CQ mode is", args.cq_mode
print "Until score is", args.until_score
videofile = encoder.Videofile(args.videofile)
- if args.cq_mode:
- codec = vp8_cq.Vp8CodecCqMode()
- else:
- codec = vp8.Vp8Codec()
-
bitrate = int(args.rate)
+ args = parser.parse_args()
+
+ print "Loop is", args.loop
+ print "Codec is", args.codec
+
+ videofile = encoder.Videofile(args.videofile)
+
+ codec = pick_codec.PickCodec(args.codec)
while True:
bestsofar = codec.BestEncoding(bitrate, videofile)