I have 65 .mov video files named tape_01.mov, tape_02.mov, …, tape_65.mov. Each is about 2.5 hours long and takes up many gigabytes. They are digital copies of what were VHS tapes (my family's "home movies").
Each 2.5-hour .mov video file contains many "chapters" (in the sense that sometimes the scene ends in a fade to a black screen, and then a new scene fades in).
My main goal is have the 65 large files sliced into smaller files by chapter. And I want that to be done automatically via detection of the black frames between "scenes".
Could I use ffmpeg (or anything) to pass in the 65 original filenames and have it automatically iterate over each video and chop it down, naming the resulting pieces tape_01-ch_01.mov, tape_01-ch_02.mov, tape_01-ch_03.mov, etc? And I want it to do it without re-encoding (I want it to be a simple lossless slice).
How can I do this?
Here are the steps I want:
- Iterate over a folder of .mov files (named tape_01.mov, tape_02.mov, …, tape_65.mov) to export them as mp4 files (named tape_01.mp4, tape_02.mp4, …, tape_65.mp4). I want the compression settings to be easy to configure for this step. The original .mov files should still exist after the .mp4 files are created.
- Iterate over the mp4 files: for each mp4 file, generate a text file that specifies the start time and duration of black segments between "scenes". Each mp4 can have 0 or more of these black scene breaks. The start time and duration should be precise to a fraction of a second. HH:MM:SS format is not precise enough.
- I'll then be able to manually double-check these text files to see whether they correctly identify scene changes (black segments). I can adjust the timings if I want.
- Another script will read each mp4 file and its txt file and split (in a super fast and lossless way) the mp4 into as many pieces as necessary based on the lines of the text file (the timings indicated there). The splits should happen in the middle of each black segment. Here is a sample mp4 file (with audio removed for privacy purposes) that has fade-to-black scene changes. The original mp4 files should remain untouched as the smaller mp4 files are created. The smaller mp4 files should have the naming scheme of tape_01_001.mp4, tape_01_002.mp4, tape_01_003.mp4, etc.
- Bonus! It would be awesome if another script could then iterate over the small mp4 files and generate one .png image for each that is a mosaic of screenshots like this person is trying for: Meaningful thumbnails for a Video using FFmpeg
I'd like these scripts to be shell scripts that I can run in Mac, Ubuntu, and Windows Git Bash.
Best Answer
Here are two PowerShell scripts to split long videos into smaller chapters by black scenes .
Save them as Detect_black.ps1 and Cut_black.ps1. Download ffmpeg for Windows and tell the script the path to your ffmpeg.exe and your video folder under the option section.
Both scripts won't touch existing video files, they remain untouched.
However, you will get a couple of new files at the same place where your input videos are
First script to run: Detect_black.ps1
How does it work
The first script iterates through all video files which matches a specified extension and doesn't match the pattern
*_???.*
, since new video chapters were named<filename>_###.<ext>
and we want to exclude them.It searches all black scenes and writes the start timestamp and black scene duration to a new CSV file named
<video_name>_cutpoints.txt
It also calculates cut points as shown:
cutpoint = black_start + black_duration / 2
. Later, the video gets segmented at these timestamps.The cutpoints.txt file for your sample video would show:
After a run, you can manipulate the cut points manually if wished. If you run the script again, all old content gets overwritten. Be careful when manually editing and save your work elsewhere.
For the sample video the ffmpeg command to detect black scenes is
There are 3 important numbers which are editable in the script's option section
d=4
means only black scenes longer than 4 seconds are detectedpic_th=0.98
is the threshold for considering a picture as "black" (in percent)pix=0.15
sets the threshold for considering a pixel as "black" (in luminance). Since you have old VHS videos, you don't have completely black scenes in your videos. The default value 10 won't work and I had to increase the threshold slightlyIf anything goes wrong, check the corresponding logfile called
<video_name>__ffmpeg.log
. If the following lines are missing, increase the numbers mentioned above until you detect all black scenes:Second script to run: cut_black.ps1
How does it work
The second script iterates over all video files in the same way the first script has done. It reads in only the cut timestamps from the corresponding
cutpoints.txt
of a video.Next, it puts together a suitable filename for chapter files and tells ffmpeg to segment the video. Currently the videos are sliced without re-encoding (superfast and lossless). Due to this, there might be 1-2s inaccuracy with cut point timestamps because ffmpeg can only cut at key_frames. Since we just copy and don't re-encode, we cannot insert key_frames on our own.
The command for the sample video would be
If anything goes wrong, have a look at the corresponding ffmpeg.log
References
Todo
Ask OP if CSV format is better than a text file as cut point file, so you can edit them with Excel a little bit easier» Implemented
Implement a way to format timestamps as [hh]:[mm]:[ss],[milliseconds] rather than only seconds» Implemented
Implement a ffmpeg command to create mosaik png files for each chapter» Implemented
Elaborate if-c copy
is enough for OP's scenario or of we need to fully re-encode.Seems like Ryan is already on it.