批处理脚本中的FFmpeg输出解析

3

我对Windows中的脚本完全不熟悉,但被迫使用这样的脚本。我希望有人能帮我解决以下问题。我想处理来自ffmpeg命令的输出,以保存有关访问摄像头的信息,以便以后使用。

更确切地说,命令如下:

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

输出结果如下:
[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"

通常,DirectShow中“替代名称”的前两次出现对应于视频和音频,为了简化起见,我想将这两个信息保存在两个变量中。 在此示例中为:
@device_pnp_\\?\usb#vid_045e&pid_0772&mi_00#6&2a15e69b&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global

并且

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

有没有更有经验的人能帮助我完成这个任务? 提前感谢!

2个回答

4
这段批处理代码将第一个设备字符串分配给变量DeviceVideo,将第二个设备字符串分配给变量DeviceAudio
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "DeviceVideo="

for /F "tokens=4,5*" %%I in ('ffmpeg.exe -stats -hide_banner -list_devices true -f dshow -i dummy 2^>^&1') do (
    if "%%I %%J" == "Alternative name" (
        if not defined DeviceVideo (
            set "DeviceVideo=%%~K"
        ) else (
            set "DeviceAudio=%%~K"
            goto DevicesOutput
        )
    )
)

:DevicesOutput
set Device
endlocal

ffmpeg 输出文本消息以处理 STDERR,而不是像控制台应用程序一样处理 STDOUT,这绝对不是典型的做法。命令 FOR 仅捕获和处理输出到 STDOUT 的文本。

因此,需要使用 2>&1ffmpeg 输出的所有内容重定向到 STDOUT 处理 STDERR,正如 Microsoft 在文章 Using command redirection operators 中所述。必须使用 ^ 转义运算符 >&,因为此重定向应该在使用带有 %ComSpec% /c 启动的单独命令进程执行 ffmpeg 命令时应用,并将命令行作为附加参数添加到 ' 内部,而不是在处理批处理文件的命令进程执行命令 FOR

命令FOR处理ffmpeg的输出行,跳过空行和以分号开头的行(默认的eol)。

每一行都使用空格/制表符作为分隔符进行字符串拆分(默认的delims)。使用tokens=4,5*指定只有第四个、第五个和第五个空格/制表符之后的部分是感兴趣的,并应该分配给循环变量IJK

例如,这行:

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

被拆分成字符串

  1. [dshow ... 因为未指定令牌1而被忽略。
  2. @ ... 因为未指定令牌2而被忽略。
  3. 02cec400] ... 因为未指定令牌3而被忽略。
  4. Alternative ... 令牌4分配给指定循环变量 I
  5. name ... 令牌5分配给循环变量 J,是 ASCII表 中的下一个字符。
  6. "@device_pnp_\\?\usb#vid_045e&pid_0772&mi_00#6&2a15e69b&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global" ... 令牌6是用 * 匹配行剩余部分(包括空格和制表符),赋值给循环变量 K 是 ASCII 表中的下两个字符之一。
在循环中,进行了区分大小写的字符串比较,以检查循环变量IJ,之间有一个空格,用双引号括起来,是否等于字符串"Alternative name"。在比较这两个字符串之前,IF不会删除双引号。
在相等的字符串上找到一个新的设备字符串。在这种情况下,接下来检查顶部明确未定义的环境变量DeviceVideo是否仍未定义,这意味着第一个设备字符串当前由FOR命令处理。
由于使用了%%~K而不是%%K,所以设备字符串被分配给没有周围双引号的环境变量DeviceVideo(第一个设备字符串)或环境变量DeviceAudio(第二个设备字符串)。
由于只有前两个设备字符串是感兴趣的,因此在将第二个设备字符串分配给DeviceAudio后就退出了该循环。
所有以子字符串Device开头的变量按字母顺序排序,在下一行上进行输出,这导致示例输出为:
DeviceAudio=@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\Desktop Microphone (3- Studio -
DeviceVideo=@device_pnp_\\?\usb#vid_045e&pid_0772&mi_00#6&2a15e69b&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global

最后使用命令endlocal,当前环境变量表中的DeviceAudioDeviceVideo被从内存中删除,命令扩展状态(默认启用)和延迟扩展(默认禁用)的状态以及当前目录(未更改)被恢复,并且初始环境变量表重新激活。

为了更好地理解所使用的命令,请打开一个命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • set /?
  • setlocal /?

3

您可以尝试以下内容(未经测试!)

@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 替代名称1: "%Alt1%"
echo 替代名称2: "%Alt2%"

注意:本文涉及IT技术,已尽力在保留原意的同时,使内容通俗易懂。

工作得非常好!非常感谢!关于批处理脚本如何处理注册商标符号,您有什么建议吗?微软网络摄像头在名称中有这个标志,并在命令中给我一个奇怪的符号。我认为这与控制台使用的字体有关。 - vlad2005
@vlad2005 这是一个非常困难的问题,它取决于您的本地设置,请阅读这里。如果可以,请将我的答案标记为已接受。谢谢。 - Endoro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接