Find And Remove Commercials From Recorded Tv Shows

Last Edited: 2021-04-18 04:03:14

Just say you wanted to remove some commercials from some legally obtained tv shows.  For instance, you use your DVR to record some tv shows you really like so you can watch them later.  You didn't like just scrape some transport streams from a very commercial-heavy provider and want to remove the pesky commercials for banks that allow you to overdraft your account with no fees, or whether or not a Mexican beer really helped someone realize their dream to be barber or an EDM DJ (I'm still working on that career change, BTW).  I'm digressing. 

I have these transport streams that end in .ts, but they contain the commercials as well.  Seems I don't know everything about ts, but it looks like the audio and video is programmatically timed.  My attempts to pull them into Premiere and remove the commercials worked, but when encoded, the sound fell out of sync a few seconds.  So it doesn't seem to be completely related as it wasn't 2 minutes out of sync, but in either case, that's a lot of work for poopy results.

Here's the workflow that I found works AND can be automated:

1. Encode the ts into mp4 with the commercials.

I feel like this smashes the video and audio together and locks it into place.  My first and normal attempt was with ffmpeg, and my second was with handbrake.  Since I'm attempting to automate this process for the 140 episodes I, er, DVR'd.

// this is using ffmpeg, older versions needed the -strict flag
$ ffmpeg -i tvshowS01E01.ts [-strict experimental] tvshowS01E01.unedited.mp4
// this is using handbrakeCLI
$ handbrakeCLI -i tvshowS01E01.ts -o tvshowS01E01.unedited.mp4 -e x264

2. find the commerical breaks

I manually did a couple of them for testing purposes and found handbrake to be a lot quicker than ffmpeg for my setups, however ffmpeg is required for the next couple steps.  ffmpeg has a built in "black detector" to find the pauses usually found before and after commercial breaks.

// find commercials
$ ffmpeg -i tvshowS01E01.unedited.mp4 -vf "blackdetect=d=0.5:pix_th=0.10" -an -f null - 2>&1 | grep blackdetect

This will return any breaks of a black screen over 1/2 a second.  I haven't not grepped the output but I'm guessing it comes out with more data.  Here's an example of the output of the above:

[blackdetect @ 0x5565723ecf00] black_start:0 black_end:1.04267 black_duration:1.04267
[blackdetect @ 0x5565723ecf00] black_start:21.476 black_end:21.976 black_duration:0.5
[blackdetect @ 0x5565723ecf00] black_start:132.843 black_end:134.643 black_duration:1.8
[blackdetect @ 0x5565723ecf00] black_start:270.9 black_end:273.349 black_duration:2.44957
[blackdetect @ 0x5565723ecf00] black_start:710.116 black_end:711.516 black_duration:1.4
[blackdetect @ 0x5565723ecf00] black_start:847.695 black_end:850.255 black_duration:2.55999
[blackdetect @ 0x5565723ecf00] black_start:1300.49 black_end:1303.19 black_duration:2.7
[blackdetect @ 0x5565723ecf00] black_start:1439.46 black_end:1441.07 black_duration:1.61126
[blackdetect @ 0x5565723ecf00] black_start:1704.74 black_end:1706.37 black_duration:1.63333

I found that the commercial breaks that I found manually were starting around 100-200 seconds, 750-900, and 1400-1500.  Using this we can see that the above probably has the meat I want to keep in these 4 segments:

0-133, 270-710, 848-1300, 1440->

3. Encode again using ffmpeg and trim out the commercials.

This clearly has a pretty well defined pattern to the filter_complex flag.  So far I've tried to have the filter meat in a text file and $(feed) or `feed` it into the command but ffmpeg doesn't like that at all.

$ ffmpeg -i tvshowS01E01.unedited.mp4 -filter_complex \
-map [outv] -map [outa] tvshowS01E01.mp4

I'm not sure if this command has to be all on one line but I feel like I tried it and it failed.  This will create your final file that should have the commercials removed.  Easy*.



Recent Posts