Skip to content

Instantly share code, notes, and snippets.

@tophf
Created October 19, 2015 15:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tophf/1fc58d26c1d343ee5035 to your computer and use it in GitHub Desktop.
Save tophf/1fc58d26c1d343ee5035 to your computer and use it in GitHub Desktop.
Convert qp-file to simple chapters file using timecodes v1 file
#!python3
import sys, re, bisect, collections, argparse
def run():
parser = HelpfulParser()
parser.add_argument('qpfile', type=argparse.FileType('r'),
help='the source qp file')
parser.add_argument('timecodesfile', type=argparse.FileType('r'),
help='the source timecodes v1 file')
parser.add_argument('chaptersfile', type=argparse.FileType('w'), nargs='?', default=sys.stdout,
help='the output simple chapters file, omitted = stdout')
args = parser.parse_args()
timecodes = get_timecodes(args.timecodesfile)
frametimes = (get_frame_time(frame, timecodes) for frame in get_frames(args.qpfile))
chapters = (get_chapter(i, ft) for i, ft in enumerate(frametimes))
print('\n'.join(chapters), file=args.chaptersfile)
class HelpfulParser(argparse.ArgumentParser):
def error(self, message):
print_error('error:', message)
self.print_help(file=sys.stderr)
sys.exit(1)
def get_frames(file):
return [int(get_first_word(line)) for line in file.readlines() if re.match(r'^\s*\d+\s+', line)]
def get_timecodes(file):
txt = file.read()
if not txt.startswith('# timecode format v1'):
return None
Timecodes = collections.namedtuple('Timecodes', ['frame','time','fps','basefps'])
tc = Timecodes([], [], [], fix_fps(float(re.sub('^.+?Assume ([0-9.]+).+$',r'\1',txt,1,re.S))))
f2prev = 0
t = 0.0
for line in txt.splitlines():
tokens = line.split(',')
if line and line[0].isdigit() and len(tokens)==3:
f1 = int(tokens[0])
f2 = int(tokens[1]) + 1
fps = fix_fps(float(tokens[2]))
if f1 != f2prev:
tc.frame.append(f2prev)
tc.time.append(t)
tc.fps.append(tc.basefps)
t += (f1-f2prev)/tc.basefps
tc.frame.append(f1)
tc.time.append(t)
tc.fps.append(fps)
t += (f2-f1)/fps
f2prev = f2
tc.frame.append(f2)
tc.time.append(t)
tc.fps.append(tc.basefps)
if tc.frame[0] != 0:
tc.frame.insert(0, 0)
tc.time.insert(0, 0)
tc.fps.insert(tc.basefps)
return tc
def get_frame_time(frame, timecodes):
i = bisect.bisect(timecodes.frame, frame) - 1
t = timecodes.time[i] + (frame - timecodes.frame[i]) / timecodes.fps[i]
return t
def get_chapter(index, time):
return "CHAPTER{i:02d}={h:02.0f}:{m:02.0f}:{s:06.3f}\n"\
"CHAPTER{i:02d}NAME=".format(i=index+1, h=time//3600, m=time//60%60, s=time%60)
def get_first_word(s):
return s.strip().split(' ',1)[0]
def fix_fps(fps):
return next(f for f in [24/1.001, 30/1.001, 25, fps] if abs(fps-f) < 0.001)
def print_color(color, *args, **kwargs):
if not hasattr(print_color, 'console'):
import ctypes, struct
print_color.console = ctypes.windll.kernel32.GetStdHandle(-12) # STD_ERROR_HANDLE
CSBI = ctypes.create_string_buffer(22)
ctypes.windll.kernel32.GetConsoleScreenBufferInfo(print_color.console, CSBI)
print_color.wattr = struct.unpack_from('=H', CSBI.raw, 8)[0]
print_color.colors = {'black':0, 'darkblue':1, 'darkgreen':2, 'darkcyan':3,
'darkred':4, 'darkmagenta':5, 'darkyellow':6, 'lightgray':7,
'darkgray':8, 'blue':9, 'green':10, 'cyan':11,
'red':12, 'magenta':13, 'yellow':14, 'white':15}
ctypes.windll.kernel32.SetConsoleTextAttribute(print_color.console,
color if isinstance(color, int) else print_color.colors.get(color.lower(), print_color.wattr))
print(*args, **kwargs)
ctypes.windll.kernel32.SetConsoleTextAttribute(print_color.console, print_color.wattr)
def print_error(*args, **kwargs):
print_color('red', *args, file=sys.stderr, **kwargs)
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment