I'm writing a Python script using subprocess to hardcode subtitles onto a video. My code builds a complex filter graph for ffmpeg's -vf argument, which includes burning in multiple layers of styled subtitles from an SRT file.
The script works perfectly for most files, but it fails whenever the subtitle filename contains a single quote (apostrophe), for example, That's It and That's All.srt.
When the script encounters such a file, the ffmpeg process fails immediately and doesn't create an output file. This causes a downstream KeyError: 'streams' in my code when it later tries to run ffprobe on the non-existent output file, but the root cause is the ffmpeg command failing silently.
The only solution I've found is to programmatically rename the file to remove the apostrophe, which I want to avoid.
The first time I encountered this, I read through the output log and saw that ffmpeg was removing the apostrophes itself from the string path passed to ffmpeg in the code.
[Parsed_subtitles_1 @ 000002c435dce5c0] Unable to open C:/FUBAR/Season 01/FUBAR - S01E08 - Thats It and Thats All.srt
Here is a simplified example of how the -vf filter string and the final ffmpeg command are constructed in my script:
import subprocess
from pathlib import Path
# --- Example of a problematic file path ---
source_video_path = Path(r"C:\videos\FUBAR - S01E08 - That's It and That's All.mkv")
subtitle_path = source_video_path.with_suffix('.srt')
# --- This is how I build the filter string ---
video_filter = 'crop=1920:800:0:140' # Example starting filter
# The subtitle path is formatted for the filter string
# NOTE: My real code finds this path dynamically.
formatted_subtitle_path = str(subtitle_path).replace('\\', '/')
# A simplified version of my style loop
style_string = "FontName=Segoe UI,FontSize=18,PrimaryColour=&H00FFFFFF"
# The filename is placed inside single quotes in the filter
video_filter += f",subtitles=filename='{formatted_subtitle_path}':force_style='{style_string}'"
# --- The final ffmpeg command list ---
command = [
'ffmpeg.exe',
'-y',
'-i', str(source_video_path),
'-vf', video_filter,
'-c:a', 'copy',
'output.mkv',
]
print("--- Generated FFmpeg Command ---")
# Using print to show how Python sees the arguments before execution
for i, arg in enumerate(command):
print(f"Arg[{i}]: {arg}")
# When run, ffmpeg fails on this command because of the ' in the filename.
# process = subprocess.run(command, text=True, capture_output=True)
# print("\n--- FFmpeg Output ---")
# print(process.stderr)
I understand the problem is that the single quote in That's It prematurely terminates the filename='...' string within the -vf filter. I have tried several common methods to escape it, but none have worked:
formatted_subtitle_path with various escape sequences before building the filter string.replace("'", r"\'")replace("'", r"\\'")replace("'", r"\\\'")Shell Quoting Trick: I also tried the ''' method.
replace("'", r"'\''")
Using Double Quotes: I tried changing the filter string to wrap the filename in double quotes, but ffmpeg still seems to fail.
video_filter += f""",subtitles=filename="{formatted_subtitle_path}":force_style=...
None of these attempts have succeeded; the ffmpeg process always fails to start or errors out immediately.
What is the definitive, cross-platform way to format the filename string for ffmpeg's subtitles filter so that it can correctly handle paths containing single quotes?
Rather than fighting the eccentricities of the escaping and file path handling of the filename you're providing in the video filter vf line, why not just copy the subtitle file to a temp file so you can pass a simplified path without any ' characters in it?
You can explicitly call cleanup() on the temp file / dir if you need as well once the task has completed.
import shutil
if subtitle_path.exists():
# Create temp directory and copy subtitle file
temp_dir = Path(tempfile.gettempdir())
temp_subtitle_path = temp_dir / "subtitles.srt"
shutil.copy2(subtitle_path, temp_subtitle_path)
print(f"Subtitle file copied to: {temp_subtitle_path}")
else:
print(f"Warning: Subtitle file not found at {subtitle_path}")