Skip to content

Instantly share code, notes, and snippets.

@amzon-ex
Last active April 8, 2022 15:05
Show Gist options
  • Save amzon-ex/7913b503fa2e08f33946863fc26b8366 to your computer and use it in GitHub Desktop.
Save amzon-ex/7913b503fa2e08f33946863fc26b8366 to your computer and use it in GitHub Desktop.
Create chapters in a video using ffmpeg+python
import sys
import subprocess
import re
argslen = len(sys.argv)
vidfile = sys.argv[1]
chapfile = sys.argv[2]
mdfile = 'mdfile.txt'
subprocess.call(['ffmpeg', '-y', '-v', 'error', '-i', vidfile, '-f', 'ffmetadata', mdfile])
outsub = subprocess.check_output(['ffprobe', '-v', 'error',\
'-show_entries', 'format=duration',\
'-of', 'default=noprint_wrappers=1:nokey=1',\
vidfile]).decode()
endts = float(outsub.strip())
print(f'Reading chapters from {chapfile}...')
chapdata = []
with open(chapfile, 'r') as f:
for line in f:
ts, cname = line.split(" ", 1)
tsparts = list(filter(None, re.split("[.:]+", ts)))
tsargs = len(tsparts)
multiplier = 1
tss = 0
# Check if milliseconds argument given
if(ts.find('.') != -1):
tsms = float(tsparts[-1])
for part in range(2, tsargs + 1):
tss += multiplier * float(tsparts[-part])
multiplier *= 60
tsms = 1000 * tss + tsms
else:
for part in range(1, tsargs + 1):
tss += multiplier * float(tsparts[-part])
multiplier *= 60
tsms = 1000 * tss
chapdata.append([int(tsms), cname])
chapnum = len(chapdata)
chaptext = ""
for i in range(chapnum):
cstart = chapdata[i][0]
if (i < (chapnum - 1)):
cend = chapdata[i+1][0] - 1
else:
cend = int(1000 * endts)
cname = chapdata[i][1]
chaptext += f"""
[CHAPTER]
TIMEBASE=1/1000
START={cstart}
END={cend}
title={cname}"""
with open(mdfile, 'a') as f:
f.write(chaptext)
vidfilename, vidfileformat = vidfile.split('.', 1)
modvidfile = vidfilename + '_wch.' + vidfileformat
outstatus = subprocess.run(['ffmpeg', '-loglevel', 'error', '-stats', '-i', vidfile, '-i', mdfile,\
'-map_metadata', '1', '-codec', 'copy',\
modvidfile])
if (outstatus.returncode == 0):
print(f'Chapters successfully written to {modvidfile}!')
@amzon-ex
Copy link
Author

amzon-ex commented Apr 8, 2022

This short, crude script takes in as argument

  • a video file anyvideo.ext
  • a text file with chapters anyname.txt
    like so:
python vidchapper.py anyvideo.ext anyname.txt

You need to have python installed (of course, silly!), and ffmpeg: it should also be added to path.

To view chapters, you need a suitable player. VLC is able to display chapters - I don't know of any other (yet).


Chapters text file should be in the format:

hh:mm:ss.mls chapname1
hh:mm:ss:mls chapname2
.
.

hh, mm, mls stand for hours, minutes, milliseconds respectively and are optional, depending on your requirement and the length of the video. ss stands for seconds and should always be provided, even if 0. The separators are important.

Sample chapter file:

9:30 Hello World
10:57.348 Bye World

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment