Beispiel #1
0
 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
Beispiel #2
0
 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
Beispiel #3
0
 def EncoderVersion(self):
     version_output = subprocess.check_output(
         [encoder.Tool('ffmpeg'), '-version'])
     match = re.match('(ffmpeg .*) Copyright', version_output)
     if match:
         return match.group(0)
     raise encoder.Error('ffmpeg did not find its version string')
Beispiel #4
0
 def Score(self, encoding):
   result = encoding.result
   if not result:
     raise encoder.Error('Trying to score an encoding without result')
   score = self.score_function(encoding.bitrate, result)
   # Weakly penalize long command lines.
   score -= len(encoding.encoder.parameters.values) * 0.00001
   return score
Beispiel #5
0
 def EncoderVersion(self):
     try:
         subprocess.check_output([encoder.Tool('TAppEncoderStatic')])
     except subprocess.CalledProcessError, err:
         helptext = str(err.output)
         for line in helptext.split('\n'):
             if re.match('HM software:', line):
                 return line
         raise encoder.Error('HM version string not found')
Beispiel #6
0
 def Score(self, encoding, scoredir=None):
     if scoredir is None:
         result = encoding.result
     else:
         result = self.context.cache.ReadEncodingResult(encoding,
                                                        scoredir=scoredir)
     if not result:
         raise encoder.Error('Trying to score an encoding without result')
     score = self.score_function(encoding.bitrate, result)
     # Weakly penalize long command lines.
     score -= len(encoding.encoder.parameters.values) * 0.00001
     return score
Beispiel #7
0
 def EncoderVersion(self):
     # The vpxenc command line tool outputs the version number of the
     # encoder as part of its error message on illegal arguments.
     try:
         subprocess.check_output([encoder.Tool('vpxenc')],
                                 stderr=subprocess.STDOUT)
     except Exception, err:
         version_output = str(err.output)
         for line in version_output.split('\n'):
             match = re.match(r'\s+vp9\s+- (.+)$', line)
             if match:
                 return match.group(1)
         raise encoder.Error('Did not find vp9 version string')
Beispiel #8
0
class Vp9Codec(file_codec.FileCodec):
    def __init__(self, name='vp9'):
        super(Vp9Codec, self).__init__(name)
        self.extension = 'webm'
        self.option_set = encoder.OptionSet(
            encoder.IntegerOption('cpu-used', 0, 16),
            # The "best" option gives encodes that are too slow to be useful.
            encoder.ChoiceOption(['good', 'rt']).Mandatory(),
            encoder.IntegerOption('passes', 1, 2),
        )

    def StartEncoder(self, context):
        return encoder.Encoder(
            context,
            encoder.OptionValueSet(
                self.option_set,
                '--passes=1 --good --noise-sensitivity=0 --cpu-used=5'))

    def EncodeCommandLine(self, parameters, bitrate, videofile, encodedfile):
        commandline = (encoder.Tool('vpxenc') + ' ' + parameters.ToString() +
                       ' --target-bitrate=' + str(bitrate) + ' --fps=' +
                       str(videofile.framerate) + '/1' + ' -w ' +
                       str(videofile.width) + ' -h ' + str(videofile.height) +
                       ' ' + videofile.filename + ' --codec=vp9 ' + ' -o ' +
                       encodedfile)
        return commandline

    def DecodeCommandLine(self, videofile, encodedfile, yuvfile):
        commandline = '%s %s --i420 -o %s' % (encoder.Tool("vpxdec"),
                                              encodedfile, yuvfile)
        return commandline

    def ResultData(self, encodedfile):
        more_results = {}
        more_results['frame'] = file_codec.MatroskaFrameInfo(encodedfile)
        return more_results

    def EncoderVersion(self):
        # The vpxenc command line tool outputs the version number of the
        # encoder as part of its error message on illegal arguments.
        try:
            subprocess.check_output([encoder.Tool('vpxenc')],
                                    stderr=subprocess.STDOUT)
        except Exception, err:
            version_output = str(err.output)
            for line in version_output.split('\n'):
                match = re.match(r'\s+vp9\s+- (.+)$', line)
                if match:
                    return match.group(1)
            raise encoder.Error('Did not find vp9 version string')
        raise encoder.Error('Getting vp9 version from help message failed')
Beispiel #9
0
class HevcCodec(file_codec.FileCodec):
    def __init__(self, name='hevc', formatter=None):
        self.name = name
        self.codecname = 'hevc'
        self.extension = 'hevc'
        super(HevcCodec, self).__init__(name, formatter=formatter)

    def StartEncoder(self, context):
        return encoder.Encoder(context,
                               encoder.OptionValueSet(self.option_set, ''))

    def EncodeCommandLine(self, parameters, bitrate, videofile, encodedfile):
        commandline = (
            '%s --SourceWidth=%d ---SourceHeight=%d '
            '-c %s '
            '--FrameRate=%d --InputFile=%s '
            '--FramesToBeEncoded=%d '
            '--IntraPeriod=-1 '
            '%s --TargetBitrate=%d --BitstreamFile=%s' % (
                encoder.Tool('TAppEncoderStatic'),
                videofile.width,
                videofile.height,
                encoder.Tool('hevc_ra_main.cfg'),  # Configuration file
                videofile.framerate,
                videofile.filename,
                videofile.FrameCount(),
                parameters.ToString(),
                bitrate,
                encodedfile))
        return commandline

    def DecodeCommandLine(self, videofile, encodedfile, yuvfile):
        commandline = "%s --BitstreamFile=%s --ReconFile=%s" % (
            encoder.Tool('TAppDecoderStatic'), encodedfile, yuvfile)
        return commandline

    def EncoderVersion(self):
        try:
            subprocess.check_output([encoder.Tool('TAppEncoderStatic')])
        except subprocess.CalledProcessError, err:
            helptext = str(err.output)
            for line in helptext.split('\n'):
                if re.match('HM software:', line):
                    return line
            raise encoder.Error('HM version string not found')
        raise encoder.Error('HM did not return help text as expected')
Beispiel #10
0
 def VerifyEncode(self, parameters, bitrate, videofile, workdir):
     """Returns true if a new encode of the file gives exactly the same file."""
     old_encoded_file = '%s/%s.%s' % (workdir, videofile.basename,
                                      self.extension)
     if not os.path.isfile(old_encoded_file):
         raise encoder.Error('Old encoded file missing: %s' %
                             old_encoded_file)
     new_encoded_file = '%s/%s_verify.%s' % (workdir, videofile.basename,
                                             self.extension)
     self._EncodeFile(parameters, bitrate, videofile, new_encoded_file)
     if not VideoFilesEqual(old_encoded_file, new_encoded_file,
                            self.extension):
         # If there is a difference, we leave the new encoded file so that
         # they can be compared by hand if desired.
         return False
     os.unlink(new_encoded_file)
     return True
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)
Beispiel #12
0
def FinishWorkDir(dirname):
    # Verification of validity
    if encoder_configuration.conf.sysdir() != dirname:
        raise encoder.Error('FinishWorkDir got dirname %s but expected %s' %
                            (dirname, encoder_configuration.conf.sysdir()))
    shutil.rmtree(dirname)
Beispiel #13
0
def EmptyWorkDirectory():
    dirname = encoder_configuration.conf.workdir()
    if not dirname.startswith(tempfile.gettempdir()):
        raise encoder.Error('Workdir is %s, not a tempfile' % dirname)
    shutil.rmtree(dirname)
    os.mkdir(dirname)
Beispiel #14
0
def PickCodec(name):
    if name is None:
        name = 'vp8'
    if name in CODEC_MAP:
        return CODEC_MAP[name].constructor()
    raise encoder.Error('Unrecognized codec name %s' % name)
Beispiel #15
0
 def EncoderVersion(self):
     raise encoder.Error('File codecs must define their own version')
Beispiel #16
0
def ShortName(name):
    """Return a pretty but short name for the codec."""
    if name in codec_map:
        return codec_map[name].shortname
    raise encoder.Error('Unrecognized codec name %s' % name)
Beispiel #17
0
def LongName(name):
    """Return a pretty but long name for the codec."""
    if name in codec_map:
        return codec_map[name].longname
    raise encoder.Error('Unrecognized codec name %s' % name)
Beispiel #18
0
def FinishWorkDir(dirname):
  # Verification of validity
  if os.environ['CODEC_WORKDIR'] != dirname:
    raise encoder.Error('Dirname was wrong in FinishWorkDir')
  shutil.rmtree(dirname)
Beispiel #19
0
 def EncodeCommandLine(self, parameters, bitrate, videofile, encodedfile):
     """This function returns the command line that should be executed
 in order to turn an YUV file into an encoded file."""
     # pylint: disable=W0613,R0201
     raise encoder.Error('EncodeCommandLine not defined')
Beispiel #20
0
class Vp8Codec(file_codec.FileCodec):
    def __init__(self, name='vp8'):
        super(Vp8Codec, self).__init__(name)
        self.extension = 'webm'
        self.option_set = encoder.OptionSet(
            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.
            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.
            # 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']),
            encoder.IntegerOption('cpu-used', -16, 16),
        )

    def StartEncoder(self, context):
        return encoder.Encoder(
            context,
            encoder.OptionValueSet(
                self.option_set, '--lag-in-frames=0 '
                '--kf-min-dist=3000 '
                '--kf-max-dist=3000 --cpu-used=0 --static-thresh=0 '
                '--token-parts=1 --end-usage=cbr --min-q=2 --max-q=56 '
                '--undershoot-pct=100 --overshoot-pct=15 --buf-sz=1000 '
                '--buf-initial-sz=800 --buf-optimal-sz=1000 --max-intra-rate=1200 '
                '--resize-allowed=0 --drop-frame=0 '
                '--passes=1 --good --noise-sensitivity=0'))

    def ConfigurationFixups(self, config):
        # In RT mode, vp8 will change encoding based on elapsed time if
        # cpu-used is positive, thus making encodings unstable.
        # Negative values give stable encodings, with -1
        # being the slowest variant.
        if config.HasValue('good/best/rt'):
            if config.GetValue('good/best/rt') == 'rt':
                if (not config.HasValue('cpu-used')
                        or int(config.GetValue('cpu-used')) >= 0):
                    return config.ChangeValue('cpu-used', '-1')
        return config

    def EncodeCommandLine(self, parameters, bitrate, videofile, encodedfile):
        commandline = (encoder.Tool('vpxenc') + ' ' + parameters.ToString() +
                       ' --target-bitrate=' + str(bitrate) + ' --fps=' +
                       str(videofile.framerate) + '/1' + ' -w ' +
                       str(videofile.width) + ' -h ' + str(videofile.height) +
                       ' ' + videofile.filename + ' --codec=vp8 ' + ' -o ' +
                       encodedfile)
        return commandline

    def DecodeCommandLine(self, videofile, encodedfile, yuvfile):
        commandline = '%s -i %s %s' % (encoder.Tool("ffmpeg"), encodedfile,
                                       yuvfile)
        return commandline

    def ResultData(self, encodedfile):
        more_results = {}
        more_results['frame'] = file_codec.MatroskaFrameInfo(encodedfile)
        return more_results

    def EncoderVersion(self):
        # The vpxenc command line tool outputs the version number of the
        # encoder as part of its error message on illegal arguments.
        try:
            subprocess.check_output([encoder.Tool('vpxenc')],
                                    stderr=subprocess.STDOUT)
        except Exception, err:
            version_output = str(err.output)
            for line in version_output.split('\n'):
                match = re.match(r'\s+vp8\s+- (.+)$', line)
                if match:
                    return match.group(1)
            raise encoder.Error('Did not find vp8 version string')
        raise encoder.Error('Getting version from vp8 help message failed')