LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (https://www.linuxquestions.org/questions/linux-software-2/)
-   -   How to crop a video of its black borders (https://www.linuxquestions.org/questions/linux-software-2/how-to-crop-a-video-of-its-black-borders-4175687242/)

GPGAgent 12-21-2020 01:23 PM

How to crop a video of its black borders
 
1 Attachment(s)
You can use HandBrakeCLI to encode a video and it will automatically crop the black borders, works well unless something on screen gets in the way, see the attached image.


The CBS-Justice tag spoils this


So you can use ffmpeg to detect the black borders and to give you the crop parameters



Code:

ffmpeg -hide_banner -loglevel info  -ss 10:00 -i CBS_Justice.mts  -vframes 2 -vf "cropdetect=24:16:0" -f null -
This will output this
Code:

    Metadata:
      encoder        : Lavc58.54.100 pcm_s16le
[Parsed_cropdetect_0 @ 0x5567e808af80] x1:69 x2:474 y1:0 y2:575 w:400 h:576 x:72 y:0 pts:74772 t:0.830800 crop=400:576:72:0
frame=    2 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.80 bitrate=N/A speed=69.5x   
video:1kB audio:9kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

The next step is to extract the crop=400:576:72:0 bit so you can use awk
Code:

/PROC$ awk '/crop=/ {print $14}' CROPDATA.txt
crop=400:576:72:0
jonke@charlie:/media/jonke/HITA_500GB/FILES/FUGITIVETEST/PROC$

I saved the output from ffmpeg to CROPDATA.txt


The next step is put this all into a script and this is it
Code:

#!/bin/bash
renice 19 -p $$
# detect the cropping parameters
FFREPORT=file=CROPDATA.txt:level=32 ffmpeg -hide_banner -loglevel quiet -ss 10:00 -i CBS_Justice-10282020-0348.mts  -vframes 2 -vf "cropdetect=24:16:0" -f null -

# Extract the cropping paramaters for the -vf switch
CROP=`awk  '/crop=/ {print $14}' CROPDATA.txt`

# run ffmpeg using the cropping parameters
FFREPORT=file=cropit.log:level=24 ffmpeg -hide_banner -ss 9:50 -t 10  -i CBS_Justice-10282020-0348.mts -vf $CROP cropit.mp4
# loglevels quiet -8 | fatal 8 | error 16| warning 24 | (info 32) | verbose 40 | debug 48 trace 56
echo "finished okay"

I'll be making the start point of the cropdetect, and the input video file an argument to the script, but what I would like is a critique on the script, could it be improved or is there an entirely different way of cropping out black borders?

ondoho 12-21-2020 02:39 PM

Instead of relying on a fragile detection algorithm, I'd simply take a screenshot of the video (assuming that the black borders remain unchanged throughout the video), calculate the pixel dimensions I need to crop, and crop it with ffmpeg.

computersavvy 12-21-2020 03:05 PM

Quote:

Originally Posted by GPGAgent (Post 6198212)
You can use HandBrakeCLI to encode a video and it will automatically crop the black borders, works well unless something on screen gets in the way, see the attached image.


The CBS-Justice tag spoils this


So you can use ffmpeg to detect the black borders and to give you the crop parameters



Code:

ffmpeg -hide_banner -loglevel info  -ss 10:00 -i CBS_Justice.mts  -vframes 2 -vf "cropdetect=24:16:0" -f null -
This will output this
Code:

    Metadata:
      encoder        : Lavc58.54.100 pcm_s16le
[Parsed_cropdetect_0 @ 0x5567e808af80] x1:69 x2:474 y1:0 y2:575 w:400 h:576 x:72 y:0 pts:74772 t:0.830800 crop=400:576:72:0
frame=    2 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.80 bitrate=N/A speed=69.5x   
video:1kB audio:9kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

The next step is to extract the crop=400:576:72:0 bit so you can use awk
Code:

/PROC$ awk '/crop=/ {print $14}' CROPDATA.txt
crop=400:576:72:0
jonke@charlie:/media/jonke/HITA_500GB/FILES/FUGITIVETEST/PROC$

I saved the output from ffmpeg to CROPDATA.txt


The next step is put this all into a script and this is it
Code:

#!/bin/bash
renice 19 -p $$
# detect the cropping parameters
FFREPORT=file=CROPDATA.txt:level=32 ffmpeg -hide_banner -loglevel quiet -ss 10:00 -i CBS_Justice-10282020-0348.mts  -vframes 2 -vf "cropdetect=24:16:0" -f null -

# Extract the cropping paramaters for the -vf switch
CROP=`awk  '/crop=/ {print $14}' CROPDATA.txt`

# run ffmpeg using the cropping parameters
FFREPORT=file=cropit.log:level=24 ffmpeg -hide_banner -ss 9:50 -t 10  -i CBS_Justice-10282020-0348.mts -vf $CROP cropit.mp4
# loglevels quiet -8 | fatal 8 | error 16| warning 24 | (info 32) | verbose 40 | debug 48 trace 56
echo "finished okay"

I'll be making the start point of the cropdetect, and the input video file an argument to the script, but what I would like is a critique on the script, could it be improved or is there an entirely different way of cropping out black borders?

The latest version of devedeng will do this for you. It uses ffmpeg as a back end and handles it seamlessly.

teckk 12-21-2020 04:36 PM

Quote:

ffmpeg -hide_banner -ss 9:50 -t 10 -i CBS_Justice-10282020-0348.mts -vf $CROP cropit.mp4
I have a couple of questions.
What is the output of:
Code:

ffprobe CBS_Justice-10282020-0348.mts
If that transport stream is an mpeg2, and you are making a .mp4 out of it, ffmpeg will reencode it. Is that what you want? Every time you reencode you loose quality. You did not specify -c:a copy -c:v copy

This will reencode the video. Look at what ffmpeg's defaults are.
Code:

ffmpeg -i file.ts -vf crop=700:400:0:2 out.mp4
I would specify the parameters for the reencode. I would find the crop manually, Auto crop will remove part of the video probably, I've never found that to work as good.

Do you want to crop without reencoding or resizing?
Code:

ffmpeg -i Input.ts -c copy -bsf:v h264_metadata=crop_left=20:crop_right=20:crop_top=10:crop_bottom=10 output.ts

GPGAgent 12-21-2020 05:28 PM

Quote:

Originally Posted by ondoho (Post 6198240)
Instead of relying on a fragile detection algorithm, I'd simply take a screenshot of the video (assuming that the black borders remain unchanged throughout the video), calculate the pixel dimensions I need to crop, and crop it with ffmpeg.

That's what I've done in the past, bit tedious if you have 20+ videos to crop tho', and I'm a believer of getting the 'puter to do the work.


Things that an go wrong:
1 You detect the wrong bit of video
2 The crop=nn:nn:nn:nn isn't the 14th column
3 There are multiple crop= sequences in the data output file
4 Many things I havn't thought of


BTW I do assume the black borders remain the same throughout the video

GPGAgent 12-21-2020 05:32 PM

Quote:

Originally Posted by computersavvy (Post 6198257)
The latest version of devedeng will do this for you. It uses ffmpeg as a back end and handles it seamlessly.

Looks interesting, but it isn't command line is it? I'll try it out tho', not had time at the moment.


I do need a script I can the just loop through my collection of videos and just leave it to run.

GPGAgent 12-21-2020 05:37 PM

Quote:

Originally Posted by teckk (Post 6198294)
I have a couple of questions.
What is the output of:
Code:

ffprobe CBS_Justice-10282020-0348.mts
Code:

$ ffprobe CBS_Justice-10282020-0348.mts
ffprobe version 4.2.4-1ubuntu0.1 Copyright (c) 2007-2020 the FFmpeg developers
  built with gcc 9 (Ubuntu 9.3.0-10ubuntu2)
  configuration: --prefix=/usr --extra-version=1ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
  WARNING: library configuration mismatch
  avcodec    configuration: --prefix=/usr --extra-version=1ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared --enable-version3 --disable-doc --disable-programs --enable-libaribb24 --enable-liblensfun --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libtesseract --enable-libvo_amrwbenc
  libavutil      56. 31.100 / 56. 31.100
  libavcodec    58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter    7. 57.100 /  7. 57.100
  libavresample  4.  0.  0 /  4.  0.  0
  libswscale      5.  5.100 /  5.  5.100
  libswresample  3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
[mpeg2video @ 0x55bbb31e2940] Invalid frame dimensions 0x0.
    Last message repeated 1 times
[mpegts @ 0x55bbb3177240] PES packet size mismatch
Input #0, mpegts, from 'CBS_Justice-10282020-0348.mts':
  Duration: 00:54:00.75, start: 45829.134400, bitrate: 2536 kb/s
  Program 25792
  Program 25920
  Program 26176
  Program 26240
  Program 26304
  Program 26368
  Program 26560
  Program 26624
  Program 26752
  Program 27040
  Program 27200
  Program 27424
  Program 27456
  Program 27584
  Program 27616
  Program 27680
  Program 27712
  Program 27744
    Stream #0:0[0xb7d]: Video: mpeg2video (Main) ([2][0][0][0] / 0x0002), yuv420p(tv, top first), 544x576 [SAR 32:17 DAR 16:9], 25 fps, 25 tbr, 90k tbn, 50 tbc
    Stream #0:1[0xb7e](eng): Audio: mp2 ([3][0][0][0] / 0x0003), 48000 Hz, stereo, fltp, 128 kb/s
  Program 27776
  Program 27872
  Program 27904
  Program 27968
  Program 28000
  Program 28096
  Program 28160
  Program 28224
  Program 28256
  Program 28288

If that transport stream is an mpeg2, and you are making a .mp4 out of it, ffmpeg will reencode it. Is that what you want? Every time you reencode you loose quality. You did not specify -c:a copy -c:v copy

This will reencode the video. Look at what ffmpeg's defaults are.
Code:

ffmpeg -i file.ts -vf crop=700:400:0:2 out.mp4
I would specify the parameters for the reencode. I would find the crop manually, Auto crop will remove part of the video probably, I've never found that to work as good.

Do you want to crop without reencoding or resizing?
Code:

ffmpeg -i Input.ts -c copy -bsf:v h264_metadata=crop_left=20:crop_right=20:crop_top=10:crop_bottom=10 output.ts


You're dead right I should have used -acodec copy, I just rushed the last bit - my evening meal was waiting for me and the missus would have been upset if I was late - know what I mean?

GPGAgent 12-22-2020 06:02 AM

Quote:

Originally Posted by teckk (Post 6198294)
I have a couple of questions.
What is the output of:
Code:

ffprobe CBS_Justice-10282020-0348.mts
If that transport stream is an mpeg2, and you are making a .mp4 out of it, ffmpeg will reencode it. Is that what you want? Every time you reencode you loose quality. You did not specify -c:a copy -c:v copy

Input file is mts and I want mp4 files out so yes I do re-encode these files, and yes I may lose (not loose) a bit of quality, but that's acceptable.

And you cannot use copy when re-encoding - here's the error message
Code:

Filtergraph 'crop=400:576:72:0' was defined for video output stream 0:0 but codec copy was selected.
Filtering and streamcopy cannot be used together.

Filtering requires the input video to be fully decoded into raw video, then the raw video is processed by the filter(s), then it is encoded.

It does take time but I run this through a driver script that will process about 20 or 30 videos - takes a little while which is why I do it this way.

Setting up the driver script only takes 5 mins or so then the 'puter does all the work - neat innit!

teckk 12-22-2020 08:21 AM

Code:

And you cannot use copy when re-encoding
No you can't, but you can crop without reencoding. If you have a .mp4 file that is x264 for example. You can make that a transport stream, crop it, and put it back into a .mp4 container without doing any reencoding. You seem to already know that. Good deal.

GPGAgent 12-22-2020 08:25 AM

Okay folks, I've added this autodetect feature into my script, it's pretty ugly and I'm sure I could improve it but it works and does what I want

Basically I user a driver script
Code:

#!/bin/bash
#                        $1      $2    $3  $4    $5    $6    $7    8-9 10-11 12-13
#                      detect  file    preset CRF  st1  en1  st2  en2 - up to five cuts
# ./CutAndEncode-v2.sh 10:00  MAH.mts faster  26  10:00  41:14 53:53 57:42 1:09:17
# -preset  ultrafast superfast veryfast faster fast medium (default) slow veryslow
#
#
#                      detect file                          preset crf  s1    e1
../CropCutAndEncode-V2.sh 19:00 CBS_Justice-12022020-0348.mts veryfast 26  11:50 26:49 30:32 40:30 44:45 52:17

which calls CropCutAndEncode-V2.sh

Code:

#!/bin/bash
renice 19 -p $$
# detect black borders automatically
# ffmpeg -ss 90 -i input.mp4 -vframes 10 -vf cropdetect -f null -
#
#                        $1      $2      $3  $4    $5    $6    7  8-9 10-11 12-13 14-15 
#                  detect file    preset crf  st1  en1  st2  en2 - up to five cuts
# ./CutAndEncode.sh 10:00 MAH.mts faster 26    41:14 53:53 57:42 1:09:17
# -preset  ultrafast superfast veryfast faster fast medium (default) slow veryslow


# presets are ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow

LOGFILE="00CropCutAndEncode-V2.log"

# detect the cropping parameters
FFREPORT=file=CROPDATA.txt:level=32 ffmpeg -hide_banner -loglevel quiet -ss $1 -i $2  -vframes 2 -vf "cropdetect=24:16:0" -f null -

shift 1 # remove the detect time from the argument list and continue processing as usual

# Extract the cropping paramaters for the -vf switch
CROP=`awk  '/crop=/ {print $14}' CROPDATA.txt`
VF="$CROP,yadif"

# run ffmpeg using the cropping parameters
#FFREPORT=file=cropit.log:level=24 ffmpeg -hide_banner -ss 9:50 -t 10  -i CBS_Justice-10282020-0348.mts -vf $CROP  -c:a copy -c:v copy cropit2.mp4
# loglevels quiet -8 | fatal 8 | error 16| warning 24 | (info 32) | verbose 40 | debug 48 trace 56
echo "finished okay"

echo "CropCutAndEncode-V2.sh" > ${LOGFILE}
echo "======================" >> ${LOGFILE}
echot() {
            echo “$*” | tee -a ${LOGFILE}
}

rm 00Tmp*.mp4
cnt=1
for P in "$@"
do
case $cnt in
    1) FN=$P;;          # file name CBS_Justice-10282020-0348.mts
    2) PRESET=$P;;      # superfast
    3) CRF=$P;;        # crf value 26
#  4) VF=${P};;        # crop=400:576:72:0,scale=576:400 or just crop=400:576:72:0
    4) ST=$P;;          # start point of first clip
    5) EN=$P            #  end point of first clip
      echot "Cut $cnt of $FN start at $ST and end at $EN"
      ffmpeg -ss $ST -to $EN -i "$FN" -vf ${VF} -c:v libx265 -crf $CRF -preset $PRESET  00Tmp-01.mp4
      echot "ffmpeg -ss $ST -to $EN -i "$FN" -vf ${VF} -c:v libx265 -crf $CRF -preset $PRESET  00Tmp-01.mp4";;

    6) ST=$P;;
    7) EN=$P
      echot "Cut $cnt of $FN start at $ST and end at $EN"
      ffmpeg -ss $ST -to $EN -i "$FN" -vf  ${VF} -c:v libx265  -crf $CRF  -preset $PRESET  00Tmp-02.mp4
      echot "ffmpeg -ss $ST -to $EN -i "$FN" -vf  ${VF} -c:v libx265  -crf $CRF  -preset $PRESET  00Tmp-02.mp4";;
 
    8)  ST=$P;;
    9)  EN=$P
      echot "Cut $cnt of $FN start at $ST and end at $EN"
    ffmpeg -ss $ST -to $EN -i "$FN" -vf  ${VF} -c:v libx265  -crf $CRF -preset $PRESET  00Tmp-03.mp4
    echot "ffmpeg -ss $ST -to $EN -i "$FN" -vf  ${VF} -c:v libx265  -crf $CRF -preset $PRESET  00Tmp-03.mp4";;

    10) ST=$P;;
    11) EN=$P
      echo "Cut $cnt of $FN start at $ST and end at $EN"
    ffmpeg -ss $ST -to $EN -i "$FN" -vf  ${VF} -c:v libx265  -crf $CRF  -preset $PRESET  00Tmp-04.mp4
    echot "ffmpeg -ss $ST -to $EN -i "$FN" -vf  ${VF} -c:v libx265  -crf $CRF  -preset $PRESET  00Tmp-04.mp4";;

    12) ST=$P;;
    13) EN=$P
      echo "Cut $cnt of $FN start at $ST and end at $EN"
    ffmpeg -ss $ST -to $EN -i "$FN" -vf  ${VF} -c:v libx265  -crf $CRF -preset $PRESET  00Tmp-05.mp4
    echot "ffmpeg -ss $ST -to $EN -i "$FN" -vf  ${VF} -c:v libx265  -crf $CRF -preset $PRESET  00Tmp-05.mp4";;

    14) ST=$P;;
    15) EN=$P
      echot "Cut $cnt of $FN start at $ST and end at $EN"
    ffmpeg -ss $ST -to $EN -i "$FN" -vf  ${VF} -c:v libx265  -crf $CRF -preset $PRESET  00Tmp-06.mp4
    echot "ffmpeg -ss $ST -to $EN -i "$FN" -vf  ${VF} -c:v libx265  -crf $CRF -preset $PRESET  Tmp-06.mp4";;

 esac
 cnt=$((cnt + 1))
done
echot "Now join the cuts"

ls 00Tmp*.mp4 | perl -ne 'print "file $_"' | ffmpeg -protocol_whitelist "file,pipe" -safe 0 -y -f concat -i - -codec copy PROC/$FN-$PRESET-$CRF.mp4
echot "Now delete the temp files"
mv $FN PROC
#rm Tmp*.mp4

Works just fine

antithesis85 12-22-2020 08:20 PM

1) Detect the crop values however you prefer to.
2) Dynamically construct AviSynth script that utilizes Crop() and splicing.
3) Encode the singular, output-ready script with FFmpeg.

No extraneous encodes and after-the-fact concatting.

GPGAgent 12-23-2020 03:10 AM

Quote:

Originally Posted by antithesis85 (Post 6198791)
1) Detect the crop values however you prefer to.
2) Dynamically construct AviSynth script that utilizes Crop() and splicing.
3) Encode the singular, output-ready script with FFmpeg.

No extraneous encodes and after-the-fact concatting.

Cheers, could you expand your comments please, not entirely sure what you mean

And those links are empty!

GPGAgent 12-23-2020 03:17 AM

Quote:

Originally Posted by teckk (Post 6198547)
Code:

And you cannot use copy when re-encoding
No you can't, but you can crop without reencoding. If you have a .mp4 file that is x264 for example. You can make that a transport stream, crop it, and put it back into a .mp4 container without doing any reencoding. You seem to already know that. Good deal.

The input is an mts file and I want to re-encode it to mp4 so I'm not copying.


I could just re-encoe the entie video, then rop and copy the resulting mp4 file, it may be quicker, but I don't think there will be much in it, worth trying tho,

ondoho 12-23-2020 03:55 AM

Quote:

Originally Posted by GPGAgent (Post 6198868)
Cheers, could you expand your comments please, not entirely sure what you mean

And those links are empty!

The links aren't empty, I just had a look.
You are asking a lot of video editing questions, AVSynth might be very helpful to you.

teckk 12-23-2020 05:45 AM

You did not answer post #4. I think that you have not started at the start. The first thing to do it find out what audio/video is in that transport stream. Then you will know what your options are with ffmpeg, and how to reencode it.


All times are GMT -5. The time now is 05:08 AM.