Skip to content

Instantly share code, notes, and snippets.

@SAPikachu
Created November 17, 2011 10:17
Show Gist options
  • Save SAPikachu/1372854 to your computer and use it in GitHub Desktop.
Save SAPikachu/1372854 to your computer and use it in GitHub Desktop.
import sys
import re
import os
def read_tc_v1(f, params):
frame_count = None
if "frame-count" in params:
frame_count = int(params["frame-count"])
parts = []
default_fps = None
for line in f:
line = line.strip()
if line.startswith("#"):
if frame_count is None:
m = re.match(r"^# vfr stats: .* (\d+) - total", line)
if m:
frame_count = int(m.group(1))
continue
if not line:
continue
if line.lower().startswith("assume "):
if default_fps:
raise ValueError("Found multiple assume line")
default_fps = float(line[7:].strip())
continue
if not default_fps:
raise ValueError("Missing assume line")
current_part = line.split(",")
parts.append([
int(current_part[0]),
int(current_part[1]),
float(current_part[2])])
parts.sort(key=lambda x: x[0])
if len(parts) == 0:
raise ValueError("Timecode file is empty")
if not frame_count:
frame_count = parts[-1][1] + 1
print("Warning: Frame count not specified, and this is not TIVTC-generated timecode file, using guessed frame count ({0})".format(frame_count))
ret = []
for i in range(frame_count):
while True:
if len(parts) == 0:
current_fps = default_fps
break
elif i < parts[0][0]:
current_fps = default_fps
break
elif i > parts[0][1]:
parts.pop(0)
continue
else:
current_fps = default_fps
break
ret.append(1000.0 / current_fps)
return ret
def read_tc_v2(f, params):
last_timestamp = None
ret = []
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
current_timestamp = float(line)
if last_timestamp is not None:
ret.append(current_timestamp - last_timestamp)
last_timestamp = current_timestamp
if last_timestamp:
if "default-fps" in params:
ret.append(1000.0 / float(params["default-fps"]))
else:
ret.append(ret[-1])
return ret
# !! returns duration for each frame
def read_tc(fn, params):
try:
with open(fn, "r") as f:
while True:
line = f.readline()
if not line:
raise ValueError("File is empty")
sys.exit(1)
line = line.strip()
if not line:
continue
if line.lower() == "# timecode format v1":
return read_tc_v1(f, params)
elif line.lower() == "# timecode format v2":
return read_tc_v2(f, params)
else:
raise ValueError("Invalid header")
except ValueError as e:
raise ValueError("Invalid timecode file {0}: {1}".format(fn, e.args))
def do_append(files, output):
tc = []
for f in files:
tc += read_tc(f["name"], f["params"])
with open(output, "w") as f:
f.write("# timecode format v2\n")
current_timestamp = 0.0
for x in tc:
f.write("{0:6f}".format(current_timestamp))
f.write("\n")
current_timestamp += x
def parse_options(options):
files = []
current_file = None
options = list(options)
while options:
current_option = options.pop(0)
if current_option.startswith("--"):
current_file["params"][current_option[2:]] = options.pop(0)
continue
else:
if current_file:
files.append(current_file)
current_file = {
"name": current_option,
"params": {},
}
if len(files) < 2:
return None
return {
"files": files,
"output": current_file["name"],
}
def print_usage():
script_name = os.path.basename(sys.argv[0])
print("Usage:")
print("{0} <input 1> <input 2> [<input N> ...] <output>" \
.format(script_name))
print("")
print("Example:")
print("{0} tcin_1.txt tcin_2.txt tcout.txt".format(script_name))
print("")
print("Timecode V1 files are supported, but if it isn't generated by TIVTC, you need to specify frame count like:")
print("{0} tcv1.txt --frame-count 34567 tcv2.txt tcout.txt".format(script_name))
pass
if __name__ == "__main__":
options = parse_options(sys.argv[1:])
if not options:
print_usage()
sys.exit(1)
do_append(**options)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment