我对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中“Alternative name”的前两个出现对应于视频和音频,因此为简单起见,我希望将这两个信息保存在两个变量中。 在这个例子中是:
@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 -
更有经验的人可以帮我完成这项任务吗? 提前致谢!
答案 0 :(得分:2)
你可以试试这个(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%"
答案 1 :(得分:1)
此批处理代码将第一个设备字符串分配给变量DeviceVideo
,将第二个设备字符串分配给变量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
输出文字信息以处理 STDERR 而非 STDOUT ,这对于控制台应用程序来说绝对不常见。命令 FOR 仅捕获并处理打印到 STDOUT 的文本。
出于这个原因,有必要将ffmpeg
输出的所有内容重定向到处理 STDERR 以使用2>&1
来处理 STDOUT ,正如Microsoft在TechNet中所解释的那样文章Using command redirection operators。有必要使用^
运算符>
和&
进行转义,因为此重定向应该应用于执行ffmpeg
而不是执行 FOR
命令 FOR 处理ffmpeg
的输出行,然后跳过空白行以及以分号开头的行(默认为eol
)。
使用空格/制表符作为分隔符将每行分割为字符串(默认为delims
)。使用tokens=4,5*
指定只有字符串4,5和第五个空格/制表符分隔字符串后的其余部分是感兴趣的,应该分配给循环变量A
,B
和C
。
例如
行[dshow @ 02cec400] Alternative name "@device_pnp_\\?\usb#vid_045e&pid_0772&mi_00#6&2a15e69b&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
分为字符串
[dshow
...因为未指定令牌1而被忽略。@
...因为未指定令牌2而被忽略。02cec400]
...因为未指定令牌3而被忽略。Alternative
...令牌4分配给循环变量A
。name
...令牌5分配给循环变量B
。"@device_pnp_\\?\usb#vid_045e&pid_0772&mi_00#6&2a15e69b&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
...令牌6指定*
匹配线的其余部分(空格和制表符)分配给循环变量C
。在循环内部进行区分大小写的字符串比较,以检查用双引号括起来的循环变量A
和B
之间是否有单个空格等于字符串"Alternative name"
。在比较两个字符串之前,双引号不会被 IF 删除。
在相等的字符串上,使用简单的算术表达式将环境变量加1,因为在输出中找到了新的设备名称。
Windows的命令解释程序将语法%VariableName%
的所有环境变量引用替换为已使用(
... )
定义的命令块中每个引用的环境变量的当前值找到这样一个街区。如果在命令块中使用%DeviceCount%
,则每个循环运行将使用 FOR 循环上方的行中定义的值0完成。因此,使用语法!DeviceCount!
可以使用延迟扩展,并在批处理脚本的顶部显式启用延迟扩展,因为默认情况下未启用延迟扩展。
注意:命令 setlocal 还会推送命令扩展和延迟扩展的当前状态以及当前目录和指向堆栈上当前环境变量表的指针并创建用于最多(匹配) endlocal 或退出批处理文件处理的整个环境变量表的副本。
根据环境变量的值,由于%%~C
而不是%%C
而没有周围双引号的设备字符串被分配给变量DeviceVideo
或变量DeviceAudio
DeviceCount
。
由于只关注前2个设备字符串,因此在将第二个设备字符串分配给DeviceAudio
后,循环已经退出。
以子字符串Device
开头的所有变量按字母顺序排序,在下一个处理过的行上输出,这将导致输出中的示例:
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
最后,使用命令 endlocal ,从内存中删除当前环境变量表DeviceAudio
,DeviceCount
和DeviceVideo
,命令扩展名的状态(由默认启用)和延迟扩展(默认情况下禁用禁用),并恢复当前目录(根本没有更改),并且初始环境变量表再次处于活动状态。
为了更好地理解使用过的命令,打开一个命令提示符窗口,在那里执行以下命令,并完全阅读为每个命令显示的所有帮助页面。
echo /?
endlocal /?
for /?
goto /?
if /?
set /?
setlocal /?