Adding metadata to videos using ffmpeg
I've been maintaining a movie archive for years now. Every year or so I go over what I have and do a clean-up if necessary.
This time I've decided to add metadata about the title, year, IMDb links, artists, etc. to videos. I've written about a way to do it on PowerShell, but nothing comes closer to the joy I get from writing in Python.
ffmpeg command
ffmpeg supports practically anything under the sun, including adding metadata. This answer on StackOverflow put me on the right path. With ffmpeg, adding metadata is simply including -metadata key=value
arguments in the command:
ffmpeg -i video.mkv -c copy -movflags use_metadata_tags -map_metadata 0 -metadata title="Hello World" -metadata year=2020 video.metadata.mkv
when split into lines:
ffmpeg -i video.mkv `
-c copy `
-movflags use_metadata_tags `
-map_metadata 0 `
-metadata title="Hello World" `
-metadata year=2020 `
video.metadata.mkv
Some important points:
- Use
-c copy
to copy streams directly without encoding. - Use
-map_metadata 0
to copy over existing meta tags without changing them[1].
Not all containers support every metadata. For reference you can check Matroska spec for MKV and Kodi docs for MP4.
Python script
import subprocess
from pathlib import Path
from typing import Dict
def add_metadata(video: Path,
meta: Dict[str, str],
save_path: Path = None,
overwrite: bool = True):
if not save_path:
save_path = video.with_suffix('.metadata' + video.suffix)
metadata_args = []
for k, v in meta.items():
metadata_args.extend([
'-metadata', f'{k}={v}'
])
args = [
'ffmpeg',
'-v', 'quiet',
'-i', str(video.absolute()),
'-movflags', 'use_metadata_tags',
'-map_metadata', '0',
*metadata_args,
'-c', 'copy',
str(save_path)
]
if overwrite:
args.append('-y')
proc = subprocess.run(args, stdout=subprocess.PIPE)
proc.check_returncode()
if __name__ == '__main__':
vid = Path(r'video.mp4')
add_metadata(
vid,
meta=dict(
title=vid.stem,
comment=vid.stem,
year=2020,
),
)
add_metadata
function takes arbitrary key:value parameters and turns them into ffmpeg arguments.