1

I can use the following to retrieve the audio and video codec and the video frame height:

ffprobe -v quiet -show_entries stream=index,codec_name,height -of csv input.mp4

But the output is on two lines and includes text that I don't need like so:

stream,0,h264,720
stream,1,mp3

The only output I want is to be in the form of:

mp3,h264,720

I've tried using -show_entries twice in the same command line, but it ignores the first call every time. I've also tried using

ffprobe -v quiet -select_streams v -show_entries stream=codec_name,height, -select_streams a -show_entries stream=codec_name

but that doesn't do anything.

How can I get the simplified output as specified above?

gregm
  • 157
  • 6
  • 20
  • Conforming only to your example, `ffprobe -v quiet -show_entries stream=codec_name,height -of csv input.mp4 | powershell "$i=$input|select;[array]::reverse($i);$i -join ',' -replace '( |stream,)'"` would work. But what will it do to your logic if your video file contains the audio as stream 0 and the video as stream 1? Or if stream 0 includes the video, stream 1 includes DTS 5.1 audio in English, stream 2 has AC3 2.0 audio in French, and stream 3 has subtitles in mjpeg format as a video stream? How will you programmatically determine the data you need in the order you need? – rojo Jul 13 '17 at 18:15
  • There are only 3 things I'm looking for: 1) Is the frame height 720 or greater? If yes, proceed with the next two checks. 2) is it h264? if not, re-encode to h264. 2) Is the audio aac? If not, then also re-encode the audio.. – gregm Jul 13 '17 at 18:21
  • Ack! I meant h265..... – gregm Jul 13 '17 at 18:39
  • JSON is an idea which would give more freedom, but I don't know much about it. I notice then when I output to the JSON format I get a section in the streams for disposition. How do I prevent that from showing? I just need to do `ffprobe -show_streams -show_entries stream=height,codec_name -of json -v quiet -i input.mp4` to get the info that I showed before. – gregm Jul 13 '17 at 18:49
  • Seems to me that you just objectify your JSON data, then parse. `while (!height) { height = streams[i++].height || 0 }` or similar, depending on language. – rojo Jul 13 '17 at 18:53

2 Answers2

0
set "codec=" & set "sound="
for /f "tokens=*" %%i in ('ffprobe ... ') do (
  for /f "tokens=3,4 delims=," %%a in (%%i) do (
   if not defined codec (
      set "codec=%%a"
      set "hres=%%b"
    ) else (
      if not defined sound set "sound=%%a"
    )
  )
)
echo %sound%,%codec%,%hres%

if there are blank lines before ffprobe output, you should add the skip=n keyword to for loop.

elzooilogico
  • 1,659
  • 2
  • 17
  • 18
  • Is there any way to get this to run strictly from ffprobe or is it impossible to get the output on a single line without parsing it as shown in the answer? – gregm Jul 13 '17 at 17:29
  • @gregm, I don't know nothing about `ffprobe`, sorry. what I know is that any output may be grabbed with a `for` loop, all we have to do is parse this output to get the desired results. anyway, this is a `batch processing` site, don't forget it, some solutions may seem not easy, but, once you know the constrains your task have, you may create a general tool to work with. – elzooilogico Jul 13 '17 at 17:51
0

After our conversation in the comments, I think something like this is what you're looking for. It's a Batch + JScript hybrid script. I'm using JScript to parse and objectify the JSON output by ffprobe. Salt to taste, and remove echo from line 31 when you're ready for the script to act.

@if (@CodeSection == @Batch) @then
@echo off & setlocal & goto run

:usage
echo Usage: %~nx0 infile outfile
echo This script re-encodes videos to x265 + AAC encoding.
exit /b

:run
if "%~2"=="" goto usage
if not exist "%~1" goto usage

set ffprobe=ffprobe -v quiet -show_entries "stream=codec_name,height" -of json "%~1"

for /f "delims=" %%I in ('%ffprobe% ^| cscript /nologo /e:JScript "%~f0"') do set "%%~I"

if %height% lss 720 (
    echo Video is ^< 720p.  Not worth it.
    exit /b
)

set "pre=-hide_banner -fflags +genpts+discardcorrupt+fastseek -analyzeduration 100M"
set "pre=%pre% -probesize 50M -hwaccel dxva2 -y -threads 3 -v error -stats"
set "global="
set "video=-c:v libx265 -crf 22 -preset fast"
set "audio=-c:a libfdk_aac -flags +qscale -global_quality 4 -afterburner 1"

if defined hevc if defined aac (
    echo Already in x265 + AAC format.
    exit /b
)

if defined aac (
    echo Already has AAC audio.  Re-encoding video only.
    set "audio=-c:a copy"
) else if defined hevc (
    echo Already has x265 video.  Re-encoding audio only.
    set "video=-c:v copy"
)

echo ffmpeg %pre% -i "%~1" %global% %video% %audio% "%~2"

goto :EOF
@end // end Batch / begin JScript

var stdin = WSH.CreateObject('Scripting.FileSystemObject').GetStandardStream(0),
    htmlfile = WSH.CreateObject('htmlfile'),
    JSON;

htmlfile.write('<meta http-equiv="x-ua-compatible" content="IE=9" />');
htmlfile.close(JSON = htmlfile.parentWindow.JSON);

var obj = JSON.parse(stdin.ReadAll());

for (var i = obj.streams.length; i--;) {
    if (obj.streams[i].height) WSH.Echo('height=' + obj.streams[i].height);
    if (/hevc/i.test(obj.streams[i].codec_name)) WSH.Echo('hevc=true');
    if (/aac/i.test(obj.streams[i].codec_name)) WSH.Echo('aac=true');
}
rojo
  • 24,000
  • 5
  • 55
  • 101
  • Wow, that definitely looks like it will work. I certainly wasn't expecting anyone to do all that coding. I'll be back home next Tuesday and will try it out. Thanks for the time you put into this! – gregm Jul 14 '17 at 22:15