0

Thanks to the help of the user mklement0 I got this script to automatically convert all files in the folder "video_old" and move them into "video_new", all while keeping the original filename. Original Post.

Now I want to remove the black bars in the container. I know that there is "cropdetect" but AFAIK you have to manually parse the the value into the script. What parameter should I add to bellow's ffmpeg execution?

Get-ChildItem .\video_old -Filter *.mkv | ForEach-Object {
  .\ffmpeg.exe -i $_.FullName -c:v libx265 -crf 18 ".\video_new\$($_.Name)"
}

Parameters used to remove the bars

ffmpeg -ss 90 -i input.mkv -vframes 10 -vf cropdetect -f null -
...
[Parsed_cropdetect_0 @ 0x220cdc0] x1:0 x2:1279 y1:0 y2:719 w:1280 h:720 x:0 y:0 pts:215 t:0.215000 crop=1280:720:0:0
[Parsed_cropdetect_0 @ 0x220cdc0] x1:0 x2:1279 y1:0 y2:719 w:1280 h:720 x:0 y:0 pts:257 t:0.257000 crop=1280:720:0:0
[Parsed_cropdetect_0 @ 0x220cdc0] x1:0 x2:1279 y1:0 y2:719 w:1280 h:720 x:0 y:0 pts:299 t:0.299000 crop=1280:720:0:0

In this example, we can apply the filter like this:

ffmpeg -i input.mkv -vf crop=1280:720:0:0 -c:a copy output.mkv

OriginalPost

Screenshot

Example screenshot from one of the files

timlwsk
  • 121
  • 3
  • 14
  • exactly what do you mean with black bars, can you add a screenshot? and what value needs to be inserted into the script (this script does not accept any named parameters)? – Roque Sosa Apr 07 '20 at 17:14
  • @RoqueSosa [Imgur](https://imgur.com/a/CdaZ2SR). No the script doesn't accept any named parameters because I don't know what to enter :C – timlwsk Apr 07 '20 at 17:30
  • I can help you with the modification to the script, but can you edit the question and add an example of them parameter used to remove the black bars from 1 video? – Roque Sosa Apr 07 '20 at 23:38
  • @RoqueSosa Done as you wish – timlwsk Apr 08 '20 at 22:52
  • @timlwsk Perhaps not particularly useful for you as it is for Linux, but the solution in [ffmpeg get value from cropdetect](https://stackoverflow.com/a/17266356/) is worth looking at. I don't know PowerShell at all so I can't suggest alternative tools to emulate `awk`, etc. – llogan Apr 08 '20 at 23:16
  • @llogan thanks for the help, I didnt know awk either, but looking it up and the response other post you linked it seems to be somthing similar to what I tried to do, just take the crop value out and run the second command. – Roque Sosa Apr 09 '20 at 15:03

2 Answers2

4

Now that I understand, try this:

Get-ChildItem .\video_old -Filter *.mkv | ForEach-Object {
    $exportPath=".\video_new\$($_.Name)"
    #Export
    .\ffmpeg.exe -i $_.FullName -c:v libx265 -crf 18 $exportPath
    Write-Host "Exported file on $exportPath."
    #Know where to cut
    $results = .\ffmpeg.exe -ss 90 -i $exportPath -vframes 10 -vf cropdetect -f null - 2>&1
    #Cut
    if(($results | ? {$_ -match 'crop=\d{1,4}:\d[0-9]{1,4}:\d:\d'})){
        Write-Host "The regular expression was matched, value $($Matches[0])."
        .\ffmpeg.exe -i $exportPath -vf ($Matches[0]) -c:a copy ($exportPath.Replace($_.BaseName,"$($_.BaseName)_CUT"))
    }else{
        Write-Host "The regular expression was NOT matched. The line was '$($resultsParsed[0])'"
        $results | Out-File .\resultsFromCropDetect.txt
    }
}

I don't really have a way to test it, but basically I'm running the first command that tells me where to cut, with regex I pull only that part and then do the actual cutting exporting to a new file named "OriginalName_CUT.mkv".

Let me know how it goes happy to make modifications.

EDIT

After a long amounts of try, I asked for the output of ffmpeg cropdetect and debugged locally, simplified the process to find the match of cropdetect.

Roque Sosa
  • 573
  • 4
  • 21
  • Sadly, it fails right where it should cut. ```Es ist nicht möglich, einen Index auf ein NULL-Array anzuwenden. In D:\FFMPEG BatchProcessing\convert.ps1:9 Zeichen:8 + if($results[0] -match 'crop=\d{1,4}:\d[0-9]{1,4}:\d:\d'){ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : NullArray``` **Translation says:** _not possible to use an index at a NULL array_ – timlwsk Apr 10 '20 at 22:52
  • 1
    ok, that error was thrown because, $results did not get filled, I'm guessing the `.\ffmpeg -ss 90 -i $exportPath -vframes 10 -vf cropdetect -f null -` didnt return anything. I'll modify it to just write to console the vars to debug, also Ich spreche ein bisschen Deutsch. – Roque Sosa Apr 10 '20 at 23:17
  • Kinda unsure if you already tried to fix it or not (sorry). Is the version up above the fixed already? – timlwsk Apr 11 '20 at 13:34
  • yeah, try it again please, I added small text output so I can debug from here hahaha – Roque Sosa Apr 11 '20 at 17:20
  • Oh, my bad! It now returns "Crop Detect gave 0 line(s) of output." [full console output](https://pastebin.com/5bSnQftz). – timlwsk Apr 11 '20 at 17:34
  • ok, I modified it again, for some reason the crop detect output wasn't stored correctly in $resutls var. try again. – Roque Sosa Apr 11 '20 at 18:52
  • Now the conversion doesn't work in the first place: it results in: ```[NULL @ 0000028fddc7b700] Unable to find a suitable output format for ''.\video_new\Die Tribute von Panem - Catching Fire (2013).mkv'' '.\video_new\Die Tribute von Panem - Catching Fire (2013).mkv': Invalid argument``` – timlwsk Apr 11 '20 at 18:59
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/211449/discussion-between-roque-sosa-and-timlwsk). – Roque Sosa Apr 11 '20 at 19:44
1

Modifying the previous answer.. there's no need to encode twice... doing so introduces unnecessary generational loss. Also, the regex match needs to be able to detect more than one digit in the last section of the cropdetect output to handle things like this "crop=1920:880:0:40"... without the modification you may get a weird offset and incorrect crop. I have ffmpeg in my system's PATH, so I replaced ".\ffmpeg.exe" with "ffmpeg". I changed ".\video_old" to ".\ " to detect files in the directory that the script is run in and export to a known folder I have on my network "X:\HEVC_Output". This workflow just makes more sense for me. Another note: The encoder settings I have in there are a bit overkill for most cpus. Something like -c:v libx265 -crf 18 -c:a copy should be sufficient for most. You may also get wonky crop results if its dark in parts of the scene at 90 seconds into the file, so you can mess around with that number and see if you get a more accurate result. You can also mess around with the limit on the cropdetect Example: cropdetect=16:2:0 ...16 is the limit argument in this case, 2 is the round argument (result is divisible by this value, if not, it rounds to nearest integer that is divisible by the value), and 0 being the reset argument (used for looping scenarios). The defaults are 24:16:0. Higher limit values will result in over-cropping, lower limit values can lead to under-cropping, but its another dial you could tinker with if needed.

Get-ChildItem .\ -Filter *.mkv | ForEach-Object {
    $exportPath="X:\HEVC_Output\$($_.Name)"
    #Know where to cut
    $results = ffmpeg -ss 90 -i $($_.Name) -vframes 10 -vf cropdetect -f null - 2>&1
    #Cut
    if(($results | ? {$_ -match 'crop=\d{1,4}:\d[0-9]{1,4}:\d:\d[0-9]{0,4}'})){
        Write-Host "The regular expression was matched, value $($Matches[0])."
        ffmpeg -i $($_.Name) -vf ($Matches[0]) -c:v libx265 -crf 22 -preset medium -tune ssim -profile:v main10 -level:v 4 -x265-params "bframes=8:scenecut-bias=0.05:me=star:subme=5:refine-mv=1:limit-refs=1:rskip=0:max-merge=5:rc-lookahead=80:lookahead-slices=5:min-keyint=23:max-luma=1023:psy-rd=2:strong-intra-smoothing=0:b-intra=1:hist-threshold=0.03" -c:a copy -c:s copy $exportPath
    }else{
        Write-Host "The regular expression was NOT matched. The line was '$($resultsParsed[0])'"
        $results | Out-File .\resultsFromCropDetect.txt
    }
}

Another variation using the crop detect limit and round settings from the example, also allowing user to select the input directory. Searches the dir and subdirs recursively for *.mkv and *.mp4.

Add-Type -AssemblyName System.Windows.Forms
$dialog = [System.Windows.Forms.FolderBrowserDialog]::new()
$dialog.Description = 'Select a folder containing videos you want to convert'
$dialog.RootFolder = [System.Environment+specialfolder]::Desktop
$dialog.ShowNewFolderButton = $true
$dialog.ShowDialog()
$importPath = $dialog.SelectedPath
    Write-Host "Import path chosen $importPath."
    Start-Sleep -s 5

Get-ChildItem $importPath -Recurse -Include *.mkv, *.mp4 | ForEach-Object {
    $exportPath="X:\HEVC_Output\$($_.Name)"
    Write-Host "Exporting file to $exportPath."
    #Know where to cut
    $results = ffmpeg -ss 90 -i $_.FullName -vframes 10 -vf cropdetect=16:2:0 -f null - 2>&1
    #Cut
    if(($results | ? {$_ -match 'crop=\d{1,4}:\d[0-9]{1,4}:\d:\d[0-9]{0,4}'})){
        Write-Host "The regular expression was matched, value $($Matches[0])."
        Start-Sleep -s 5
        ffmpeg -i $_.FullName -vf ($Matches[0]) -c:v libx265 -crf 22 -preset medium -tune ssim -profile:v main10 -level:v 4 -x265-params "bframes=8:scenecut-bias=0.05:me=star:subme=5:refine-mv=1:limit-refs=1:rskip=0:max-merge=5:rc-lookahead=80:lookahead-slices=5:min-keyint=23:max-luma=1023:psy-rd=2:strong-intra-smoothing=0:b-intra=1:hist-threshold=0.03" -c:a copy -c:s copy $exportPath
    }else{
        Write-Host "The regular expression was NOT matched. The line was '$($resultsParsed[0])'"
        $results | Out-File .\resultsFromCropDetect.txt
    }
}
Gille
  • 26
  • 2