Created
April 7, 2012 04:20
-
-
Save astrataro/2325004 to your computer and use it in GitHub Desktop.
TAEC(Tiny Avc Encode Consultant).py 0.3.3mod2 ( add level=5.2 and profile=high10/high422/high444p, update for python 3 )
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# coding: utf-8 | |
#**************************************************************************** | |
# TAEC(Tiny Avc Encode Consultant).py | |
# written by Chikezun | |
# modified by 06_taro | |
# Reference literature: | |
# Rec. ITU-T H.264 (06/2011) – Superseded version | |
# インプレス標準教科書シリーズ改訂版 H.264/AVC教科書 | |
# 著者:(監修)大久保 榮/(編者)角野 眞也、菊池 義浩、鈴木 輝彦 | |
# http://en.wikipedia.org/wiki/H.264/MPEG-4_AVC | |
# 猫科研究所( http://www.up-cat.net/ ) | |
# x264(vbv-maxrate,vbv-bufsize,profile,level),H.264(Profile/Level) | |
# | |
#**************************************************************************** | |
__version__ = '0.3.3mod2' | |
import sys | |
import getopt | |
import math | |
def set_default(): | |
width = int(1280) | |
height = int(720) | |
fpsnum = int(30000) | |
fpsden = int(1001) | |
profile = 'high' | |
mode = 'progressive' | |
return [[width, height], [fpsnum, fpsden], profile, mode] | |
def usage(): | |
param = set_default() | |
print ( "\nUsage: taec.py [options]\n" ) | |
print ( " -r, --resolution <string> :set 'width x height' ('%ix%i')" % tuple(param[0]) ) | |
print ( " -f, --fps <string> :set 'fpsnum / fpsden' ('%i/%i')" % tuple(param[1]) ) | |
print ( " -p, --profile <string> :set 'profile' ('%s')" % param[2] ) | |
print ( " -i, --interlaced :specify interlaced mode (not specified)" ) | |
print ( " -v, --version :display version" ) | |
print ( " -h, --help :display this help and exit\n" ) | |
def check_res_and_fps(arg, r_or_f): | |
try: | |
param = [abs(int(i)) for i in arg.split('x' * r_or_f or '/')] | |
if len(param) != 2: | |
raise SyntaxError | |
except: | |
print ( "\nERROR : invalid %s setting." % ('resolution' * r_or_f or 'fps') ) | |
usage() | |
sys.exit() | |
else: | |
return param | |
def check_profile(profile, ipflag): | |
if profile in ('baseline', 'main', 'high', 'high10', 'high422', 'high444p'): | |
if profile != 'baseline' or ipflag != 'interlaced': | |
return 1 | |
else: | |
print ( "\nERROR : baseline cannot accept interlaced." ) | |
print ( "\nERROR : invalid profile setting." ) | |
usage() | |
sys.exit() | |
def calc_bs(resolution, fps, ipflag): | |
fstmp = [int(math.ceil(i / 16.0)) for i in resolution] | |
fs = dbp = fstmp[0] * fstmp[1] | |
mbps = fs * fps[0] // fps[1] | |
if ipflag == 'interlaced': | |
dbp += fstmp[0] * (fstmp[1] % 2) | |
return [mbps, fs, dbp] | |
def calc_lv(bs, ipflag, spec): | |
for i in spec: | |
if bs[0] <= i[1] and bs[1] <= i[2] and bs[2] <= i[3]: | |
return i[0] | |
if ipflag == 'interlaced': | |
print ( "ERROR : interlaced encoding cannot be done to this video." ) | |
print ( "ERROR : there is no suitable setting." ) | |
usage() | |
sys.exit() | |
def calc_result(profile, bitstream, line): | |
vbv = [int(i * ((profile == 'high') * 1.25 or (profile == 'high10') * 3 or (profile == 'high422') * 4 or (profile == 'high444p') * 4 or 1)) for i in line[4]] | |
ref = [16 * (i > 16) or i for i in [line[3] // bitstream[2]]] | |
return tuple([line[0]] + vbv + ref) | |
def display_result(level, profile, bitstream, spec): | |
index = [i[0] for i in spec] | |
try: | |
for i in range(len(index)): | |
if index[i] == level: | |
line = spec[i] | |
print ( "%5s%12i%13i%8i" % calc_result(profile, bitstream, line) ) | |
level = index[i + 1] | |
except: | |
return 0 | |
def get_spec(): | |
#H.264/AVC spec [(level, MaxMBPs, MaxFS, MaxDbpMBs, [MaxBR, MaxCPB], ipflag]} | |
return [('1.0', 1485, 99, 396, [ 64, 175], 'p'), | |
('1b ', 1485, 99, 396, [ 128, 350], 'p'), | |
('1.1', 3000, 396, 900, [ 192, 500], 'p'), | |
('1.2', 6000, 396, 2376, [ 384, 1000], 'p'), | |
('1.3', 11880, 396, 2376, [ 768, 2000], 'p'), | |
('2.0', 11880, 396, 2376, [ 2000, 2000], 'p'), | |
('2.1', 19800, 792, 4752, [ 4000, 4000], 'i'), | |
('2.2', 20250, 1620, 8100, [ 4000, 4000], 'i'), | |
('3.0', 40500, 1620, 8100, [ 10000, 10000], 'i'), | |
('3.1', 108000, 3600, 18000, [ 14000, 14000], 'i'), | |
('3.2', 216000, 5120, 20480, [ 20000, 20000], 'i'), | |
('4.0', 245760, 8192, 32768, [ 20000, 25000], 'i'), | |
('4.1', 245760, 8192, 32768, [ 50000, 62500], 'i'), | |
('4.2', 491520, 8192, 34816, [ 50000, 62500], 'p'), | |
('5.0', 589824, 22080, 110400, [135000, 135000], 'p'), | |
('5.1', 983040, 36864, 184320, [240000, 240000], 'p'), | |
('5.2', 2073600, 36864, 184320, [240000, 240000], 'p')] | |
def set_param(opts, param): | |
for opt, arg in opts: | |
if opt in ("-r", "--resolution"): | |
param[0] = check_res_and_fps(arg, 1) | |
elif opt in ("-f", "--fps"): | |
param[1] = check_res_and_fps(arg, 0) | |
elif opt in ("-p", "--profile"): | |
param[2] = arg | |
elif opt in ("-i", "--interlaced"): | |
param[3] = 'interlaced' | |
elif opt in ("-h", "--help"): | |
usage() | |
sys.exit() | |
elif opt in ("-v", "--version"): | |
print ( "tiny avc encode consultant %s" % __version__ ) | |
sys.exit() | |
return param | |
if __name__ == '__main__': | |
try: | |
opts, args = getopt.getopt(sys.argv[1:], "r:f:p:ihv", | |
["resolution=","fps=","profile=","interlaced","help","version"]) | |
except: | |
usage() | |
sys.exit() | |
param = set_default() | |
if len(opts) > 0: | |
param = set_param(opts, param) | |
else: | |
usage() | |
check_profile(param[2], param[3]) | |
print () | |
print ( " resolution : %i x %i" % tuple(param[0]) ) | |
print ( " fps : %i / %i" % tuple(param[1]) ) | |
print ( " profile : %s" % param[2] ) | |
print ( " encoding mode : %s\n" % param[3] ) | |
bitstream = calc_bs(param[0], param[1], param[3]) | |
print ( " MBPS ... %6iMB/s" % bitstream[0] ) | |
print ( " FS ... %6iMBs" % bitstream[1] ) | |
print ( " DPB ... %6iMBs\n" % bitstream[2] ) | |
if param[3] == 'interlaced': | |
avcspec = [i for i in get_spec() if i[5] == 'i'] | |
else: | |
avcspec = get_spec() | |
minlv = calc_lv(bitstream, param[3], avcspec) | |
print ( " suitable settings are ...\n" ) | |
print ( " level vbv-maxrate vbv-bufsize max-ref" ) | |
print ( " ----------------------------------------" ) | |
display_result(minlv, param[2], bitstream, avcspec) | |
#changelog | |
# 2010/12/19 0.1.0 公開 | |
# 2010/12/19 0.1.1 いろいろ計算がおかしかったのを修正 | |
# 2010/12/20 0.2.0 lambda式面白い | |
# 2010/12/21 0.3.0 リスト内包とgetoptの存在を知る | |
# 〃 0.3.1 getoptの長文形式における要引数要素に=を付けていなかったのを修正 | |
# 2010/01/02 0.3.2 処理が重複する関数(check_resolution, check_fps)をひとつにまとめた | |
# 2011/03/17 0.3.3 cosmetics | |
# 2012/04/07 0.3.3mod1 add level=5.2 and profile=high10/high422/high444p | |
# 2012/10/05 0.3.3mod2 update for python 3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment