ffmpeg output parse in batch script

2019-05-24 08:28发布

I am totally unfamiliar with scripts in Windows, but are forced to use such a script. I would like someone to help me with the following problem. I want to process the output from ffmpeg command to save information about access an webcam to be used later. More precisely command is following:

ffmpeg -stats -hide_banner -list_devices true -f dshow -i dummy

and output is like this:

[dshow @ 02cec400] DirectShow video devices (some may be both video and audio devices)
[dshow @ 02cec400]  "Microsoft LifeCam Studio"
[dshow @ 02cec400]     Alternative name "@device_pnp_\\?\usb#vid_045e&pid_0772&mi_00#6&2a15e69b&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
[dshow @ 02cec400] DirectShow audio devices
[dshow @ 02cec400]  "Desktop Microphone (3- Studio -"
[dshow @ 02cec400]     Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\Desktop Microphone (3- Studio -"
[dshow @ 02cec400]  "Line In (High Definition Audio "
[dshow @ 02cec400]     Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\Line In (High Definition Audio "
[dshow @ 02cec400]  "Microphone (High Definition Aud"
[dshow @ 02cec400]     Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\Microphone (High Definition Aud"

Typically, the first two occurence for ”Alternative name” from DirectShow correspond to video and audio, so for simplicity I want these two information saved in two variables. In this example is:

@device_pnp_\\?\usb#vid_045e&pid_0772&mi_00#6&2a15e69b&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global

and

@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\Desktop Microphone (3- Studio -

Can someone more experienced to help me with this task? Thanks in advance!

2条回答
我命由我不由天
2楼-- · 2019-05-24 08:57

You might try this (untestet!)

@echo off&setlocal disabledelayedexpansion
set "Alt1="
set "Alt2="
For /f tokens^=1^,2delims^=^" %%a in ('ffmpeg -stats -hide_banner -list_devices true -f dshow -i dummy 2^>^&1 ^| findstr /c:"Alternative name"') do (
   if not defined Alt1 (
      set "Alt1=%%~b"
   ) else (
      if not defined Alt2 (
         set "Alt2=%%~b" 
      )
   )
)
echo Alternative name 1: "%Alt1%"
echo Alternative name 2: "%Alt2%"
查看更多
▲ chillily
3楼-- · 2019-05-24 09:07

This batch code assigns first device string to variable DeviceVideo and the second device string to variable DeviceAudio.

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "DeviceCount=0"

for /F "tokens=4,5*" %%A in ('ffmpeg.exe -stats -hide_banner -list_devices true -f dshow -i dummy 2^>^&1') do (
    if "%%A %%B" == "Alternative name" (
        set /A DeviceCount+=1
        if "!DeviceCount!" == "1" (
            set "DeviceVideo=%%~C"
        ) else (
            set "DeviceAudio=%%~C"
            goto DevicesOutput
        )
    )
)

:DevicesOutput
set Device
endlocal

ffmpeg outputs text messages to handle STDERR instead of STDOUT which is definitely not typical for console applications. Command FOR captures and processes just text printed to STDOUT.

For that reason it is necessary to redirect everything output by ffmpeg to handle STDERR to handle STDOUT using 2>&1 as Microsoft explains in TechNet article Using command redirection operators. It is necessary to escape with ^ the operators > and & because this redirection should be applied on execution of ffmpeg and not on execution of FOR.

Command FOR processes next the output lines of ffmpeg with skipping blank lines and also lines starting with a semicolon (default eol).

Each line is split up to strings using spaces/tabs as separators (default delims). It is specified with tokens=4,5* that only the strings 4, 5 and rest of the line after fifth spaces/tabs separated string are of interest and should be assigned to the loop variables A, B and C.

For example the line

[dshow @ 02cec400]     Alternative name "@device_pnp_\\?\usb#vid_045e&pid_0772&mi_00#6&2a15e69b&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"

is split up to the strings

  1. [dshow ... ignored as token 1 is not specified.
  2. @ ... ignored as token 2 is not specified.
  3. 02cec400] ... ignored as token 3 is not specified.
  4. Alternative ... token 4 assigned to loop variable A.
  5. name ... token 5 assigned to loop variable B.
  6. "@device_pnp_\\?\usb#vid_045e&pid_0772&mi_00#6&2a15e69b&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global" ... token 6 specified with * matching rest of the line (with spaces and tabs) assigned to loop variable C.

Inside the loop a case-sensitive string comparison is made to check if loop variable A and B, with a single space between, enclosed in double quotes is equal the string "Alternative name". The double quotes are not removed by IF before comparing the two strings.

On equal strings an environment variable is incremented by one using a simple arithmetic expression because a new device name is found in output.

The command interpreter of Windows replaces all environment variable references with syntax %VariableName% by the current value of each referenced environment variable within a command block defined with ( ... ) already on finding such a block. If %DeviceCount% would be used in the command block, each loop run would be done with value 0 as defined in the line above the FOR loop. Therefore delayed expansion is used by using syntax !DeviceCount! and enable delayed expansion explicitly at top of the batch script because delayed expansion is not enabled by default.

Note: The command setlocal pushes also the current states of command extensions and delayed expansions as well as current directory and a pointer to current environment variables table on stack and creates a copy of the entire environment variables table for usage up to (matching) endlocal or to exit of batch file processing.

The device string without the surrounding double quotes because of %%~C instead of just %%C is assigned to either variable DeviceVideo or variable DeviceAudio depending on value of the environment variable DeviceCount.

As only the first 2 device strings are of interest, the loop is exited already after assigning the second device string to DeviceAudio.

All variables starting with the substring Device are output alphabetically sorted on next processed line which results for the example in the output:

DeviceAudio=@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\Desktop Microphone (3- Studio -
DeviceCount=2
DeviceVideo=@device_pnp_\\?\usb#vid_045e&pid_0772&mi_00#6&2a15e69b&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global

Finally with command endlocal the current environment variables table with DeviceAudio, DeviceCount and DeviceVideo is removed from memory, states of command extensions (enabled as by default enabled) and delayed expansion (disabled as by default disabled), and the current directory (not changed at all) are restored, and the initial environment variables table is made active again.

For even better understanding the used commands, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • set /?
  • setlocal /?
查看更多
登录 后发表回答