scripts/generate_video_filmstrip_standalone.py (82 lines of code) (raw):
#!/usr/bin/env python
# run like:
# /generate_video_thumbnails_standalone.py video.mp4 cutmax
import sys
import os
import subprocess
import json
from pathlib import Path
# setup input file, output file naming conventions
ifile = sys.argv[1];
filename = Path(ifile);
filenamebase = os.path.splitext(filename)[0]
ofnamebase = os.path.basename(filenamebase)
print("input file: ", ifile)
print("ofilenamebase: ", ofnamebase)
#imgformat = "png"
imgformat = "webp"
# Find duration of input video file in milliseconds
def video_duration(ivideo):
dur=0;
if os.path.exists(ivideo):
result = subprocess.run(['ffprobe', '-v', 'error', '-show_entries', 'format=duration', '-of', 'default=noprint_wrappers=1:nokey=1', ivideo], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
dur = float(result.stdout)
else:
dur = float(0)
return dur * 1000;
durms=video_duration(ifile)
print("duration in ms: ", durms)
# limits, hard max is 10sec.
hardmax = 10 * 1000;
maxvlen = int(sys.argv[2]);
def minimum(a, b):
if a < b:
return a
else:
return b
def minimum_vlen():
a = minimum(maxvlen, hardmax)
b = minimum(a, durms)
return b
print("max length of video: ", minimum_vlen())
# serialiaztion dictionary for json
filmstrip_dict = {}
# Extract frame from video stream at specified points.
# Either pick a set number of result thumbnails (say 12) spaced discretely over entire duration
# or an offset from the beginning given an interval in seconds (250ms = .25s)
# from
# https://tinyurl.com/32m4ywhx
# "This example will seek to the position of 0h:0m:14sec:435msec and
# output one frame (-frames:v 1) from that position into a PNG file.
#ffmpeg -i input.flv -ss 00:00:14.435 -frames:v 1 out.png
# partition number is integer of total segments t
def generate_video_filmstrip_partition_n(ivideo, totaln):
cspace = ' '
for i in range(totaln):
print(i)
timecoden = (i/totaln) * durms
if timecoden < 60:
thumbflag = "-ss 00:00:" + str(timecoden) + cspace + "-update -frames:v 1"
else:
timecodemin = int(timecoden/60)
timecodesec = timecoden - timecodemin;
thumbflag = "-ss 00:" + str(timecodemin) + ":" + str(timecodesec) + cspace + "-update -frames:v 1"
ofname = f"{filenamebase}_{i:02d}.{imgformat}"
fcommand="ffmpeg -i " + ifile + cspace + thumbflag + cspace + ofname
#print(str(timecoden) + cspace + fcommand)
os.system(fcommand)
filmstrip_dict[str(i)] = f"{ofnamebase}_{i:02d}.{imgformat}"
# intervaln is integer of interval between frames in milliseconds (ms)
def generate_video_filmstrip_interval(ivideo, intervaln):
cspace = ' '
totaln = int(minimum_vlen() / intervaln)
offset = 0;
for i in range(totaln):
print(i)
timecodems = offset + (intervaln * i);
timecoden = float(timecodems / 1000);
if timecoden < 60:
thumbflag = "-ss 00:00:" + str(timecoden) + cspace + "-frames:v 1"
else:
timecodemin = int(timecoden/60)
timecodesec = timecoden - timecodemin;
thumbflag = "-ss 00:" + str(timecodemin) + ":" + str(timecodesec) + cspace + "-frames:v 1"
#timecodestr = f"{timecoden:.2f}"
timecodestr = f"{timecodems:05}"
ofname = f"{filenamebase}_{timecodestr}.{imgformat}"
fcommand="ffmpeg -i " + ifile + cspace + thumbflag + cspace + ofname
#print(str(timecoden) + cspace + fcommand)
os.system(fcommand)
filmstrip_dict[timecodestr] = f"{ofnamebase}_{timecodestr}.{imgformat}"
# Assume ivideo.json file created during extraction.
# 2024-11-11-android-chrome-amazon.mp4
# 2024-11-11-android-chrome-amazon-video.json
def serialize_data(ivideo, filmstrip_res, tdict, ofname):
vdict = {}
ivideoj = ivideo.replace(".mp4", "-video.json")
if os.path.exists(ivideoj):
with open(ivideoj, 'r') as vj:
vdata_dict = json.load(vj)
vdict["video"] = vdata_dict
vdict["filmstrip_interval"] = filmstrip_res
vdict["filmstrip"] = tdict
with open(ofname, 'w') as f:
json.dump(vdict, f, indent=2)
#generate_video_filmstrip_partition_n(ifile, 12)
generate_video_filmstrip_interval(ifile, 100)
serialize_data(ifile, 100, filmstrip_dict, filenamebase + "-filmstrip.json")