Board logo

标题: [文本处理] 如何实现嵌套和对提取的字符串赋予变量后在变量中替换提取多个字符串赋予多个变量? [打印本页]

作者: xp3000    时间: 2018-10-6 14:50     标题: 如何实现嵌套和对提取的字符串赋予变量后在变量中替换提取多个字符串赋予多个变量?

本帖最后由 xp3000 于 2018-10-6 15:16 编辑

第三方工具Mediainfo、grep和sed,
ffmpeg暂时可以不用,最后的切割命令才用到。

http://mediaarea.net/zh-CN/MediaInfo/Download/Windows
关于视频声音延迟的切割方法,上面链接是地址,CLI是命令行版查看工具,

视频1和3特点都无声音,删除了所有关键帧导致无法播放,
视频2特点:
片头:00:00:45.240
片尾:00:01:30.090
同时声音-5秒23毫秒才能同步,播放时候由于头部没有关键帧,是先播放0毫秒的声音和5秒25毫秒的视频,造成声音不同步,
专门用延迟的视频合并了个视频,合并视频特点,无声音视频1+头部5秒23毫秒视频没有关键帧的视频+无声音视频2,

CMD窗口输入
  1. mediainfo.exe 合并视频.mp4
复制代码
屏幕显示以下内容
  1. General
  2. Complete name                            : C:\合并视频.mp4
  3. Format                                   : MPEG-4
  4. Codec ID                                 : M4V  (isom/avc1/iso6/M4A /M4V /mp42)
  5. File size                                : 998 MiB
  6. Duration                                 : 2 h 58 min 10 s
  7. Overall bit rate mode                    : Variable
  8. Overall bit rate                         : 343 kb/s
  9. Encoded date                             : UTC 2018-05-18 09:01:13
  10. Tagged date                              : UTC 2018-05-18 09:01:13
  11. Video
  12. ID                                       : 1
  13. Format                                   : AVC
  14. Format/Info                              : Advanced Video Codec
  15. Format profile                           : High@L4
  16. Format settings                          : CABAC / 4 Ref Frames
  17. Format settings, CABAC                   : Yes
  18. Format settings, ReFrames                : 4 frames
  19. Codec ID                                 : V_MPEG4/ISO/AVC
  20. Duration                                 : 2 h 58 min 5 s
  21. Width                                    : 1 280 pixels
  22. Height                                   : 720 pixels
  23. Display aspect ratio                     : 16:9
  24. Frame rate mode                          : Constant
  25. Frame rate                               : 25.000 FPS
  26. Color space                              : YUV
  27. Chroma subsampling                       : 4:2:0
  28. Bit depth                                : 8 bits
  29. Scan type                                : Progressive
  30. Default                                  : Yes
  31. Forced                                   : No
  32. Color range                              : Limited
  33. Color primaries                          : BT.709
  34. Transfer characteristics                 : BT.709
  35. Matrix coefficients                      : BT.709
  36. Audio
  37. ID                                       : 2
  38. Format                                   : AAC LC
  39. Format/Info                              : Advanced Audio Codec Low Complexity
  40. Codec ID                                 : A_AAC-2
  41. Duration                                 : 1 h 58 min 10 s
  42. Channel(s)                               : 2 channels
  43. Channel layout                           : L R
  44. Sampling rate                            : 44.1 kHz
  45. Frame rate                               : 43.066 FPS (1024 SPF)
  46. Compression mode                         : Lossy
  47. Delay relative to video                  : -1 h 9 min 5 s 23 ms
  48. Default                                  : Yes
  49. Forced                                   : No
复制代码
想用命令提取Delay relative to video                  : 后面的-1 h 9 min 5 s 23 ms

当然,在不同的视频是不一样的,有的是没有延迟的,没有显示,
有的视频头部数据无法识别,造成先播放了视频不该出现的部分,显示-5 s或-1 h 9 ms等等,
只要将片头加上有“-”号后面的时间,一次切除就能提取正确能播放部分,
(这里需要将-替换+,也就是片头+视频延迟的“-”时间刚好是正确不会造成延迟的视频部分。)
如果时间前面没有“-”号,则替换成为“+”,赋予变量用于后面计算出毫秒。

这里想到了grep用正则提取出延迟时间,和sed替换内容了,
但是如何提取的同时赋予变量,又对变量进行替换后提取内容为新的变量,这里不会,
目前只会单独的分次处理,这样就对视频进行了二次切割,

发现这个问题如果解决了,就可以解决很多问题,
比如有人提的,读取文件和文件内容,查找指定范围内的指定子表达式进行替换后,提取另外的有规律的字符串,赋予变量后对文件进行操作或用于命令。

不好意思,刚刚在代码中间设置了颜色,代码不能有颜色

作者: WHY    时间: 2018-10-7 23:36

长篇大论,看不懂楼主到底希望得到什么结果。
如果只是希望获取Delay relative to video后面的字符串并赋值给变量,可以这样:
  1. @echo off
  2. for /f "tokens=2 delims=:" %%i in ('MediaInfo 1.avi ^| find /i "Delay relative to video"') do set "s=%%i"
复制代码
如果希望把结果进一步转换成毫秒,可以这样:
  1. @echo off & setlocal enabledelayedexpansion
  2. for /f "tokens=2 delims=:" %%i in ('MediaInfo 1.avi ^| find /i "Delay relative to video"') do (
  3.     set "s=%%i+0"
  4.     set "s=!s:h=*3600*1000+!"
  5.     set "s=!s:min=*60*1000+!"
  6.     set "s=!s:ms=!"
  7.     set "s=!s:s=*1000+!"
  8.     if "!s:-=!" NEQ "!s!" set "s=!s:-=-1*(!)"
  9.     set /a "t=!s!"
  10.     echo;!t!
  11. )
  12. pause
复制代码

作者: xp3000    时间: 2018-10-8 09:36

目的,视频切割提取58 min 986 ms部分


重点解决grep用正则将屏幕内容提取赋予变量,
用sed再将变量内容非数字开头的部分(有或无-号)替换字符串(替换两次),
和sed批量替换以及在变量中加减乘除。

俗话说没学会走路不能学跑,更不能学飞。
这样做可以把整个过程解释非常清楚,对其他人学习也有帮助。

播放视频时候过程是,片头→正常播放视频→片尾,
因为无关键帧作为参考,不会对视频进行播放,也不会黑屏等待,
直接漏掉1 min 5 s 74 ms后播放正常部分,
但是声音却是从视频无法播放的部分开始播放的,这样声音就不同步了,

声音延迟了1 min 5 s 74 ms,在MediaInfo显示:
Delay relative to video                  : -1 min 5 s 74 ms


也就是需要把“片头00:00:45.240+延迟时间1 min 5 s 74 ms”才是正确的起始分割点,
需要把片头+延迟+片尾切割删除,把中间正常播放部分提取出来,这个是ffmpeg单独做不到的,


下面才是正题:

考虑到grep非常灵活,用下面命令能-1 min 5 s 74 ms,
grep.exe -oP "(?<=Delay relative to video                  : )-?.+"

我想将“-1 min 5 s 74 ms”赋予变量,再将这个变量提取出“-”和“1 min 5 s 74 ms”两个部分,

分别赋予两个变量,第一个变量如果碰到“-”用sed替换成为“+”,如果没有“-”则添加一个“-”,

可能用到sed先头部添加“-”,然后在此基础上“--”替换“+”,因为另一个如果没符号,自然就是“-”用于后面计算正确了,

这个因为也是动态的,所以用于后面的计算也用变量。

第二个变量用sed批量将 h替换为字符*3600+,将 min替换为字符*60+,将 s替换为字符+, ms替换为字符/1000,

因为已经替换成了运算符号,所以直接用set 对第二个变量实施计算,并且在后面添加*1000变成毫秒,

此部分延迟时间转换毫秒后,赋予延迟时间变量,
当片头也完成转换毫秒后,赋予片头时间变量,
用片头时间变量+变量延迟时间,然后赋予新变量,
这个相除获得起始切割点,结构为xx:xx:xx.xxx,

当片尾、总时长也完成转换毫秒后,赋予变量,
然后用变量相减,相除,获得片尾分割点,结构为xx:xx:xx.xxx,

最后才用ffmpeg进行分割。
作者: WHY    时间: 2018-10-8 10:21

本帖最后由 WHY 于 2018-10-8 10:23 编辑

回复 3# xp3000


    你这个需求用 grep + sed 完全就是多余的, 既方便不了半分,也不见得效率会提高。系统自带的 find 完全可以胜任。
2楼已经告诉你怎样获取延迟毫秒数,把这个结果与片头的毫秒数相加,就是总的延迟毫秒数,再转回 hh:mm:ss.ms 的形式即可。

PS: 不要把你的解题思路告诉别人,你的解题思路不一定正确。
作者: xp3000    时间: 2018-10-8 12:50

谢谢了,一会去试试,不知道这个什么意思,
if "!s:-=!" NEQ "!s!" set "s=!s:-=-1*(!)"
作者: WHY    时间: 2018-10-8 16:33

回复 5# xp3000


   
C:\Users\WHY>set "s= -1 h 20 s"

C:\Users\WHY>set "s=%s:-=-1*(%)"

C:\Users\WHY>echo %s%
-1*(1 h 20 s)

作者: WHY    时间: 2018-10-8 16:38

一个示例
  1. @echo off & setlocal enabledelayedexpansion
  2. set "s1=00:00:45.240"
  3. rem 片头毫秒数
  4. for /f "tokens=1-4delims=:." %%a in ("%s1%") do (
  5.     set /a "t1=(1%%a %% 100 *3600 + 1%%b %% 100 * 60 + 1%%c %% 100) * 1000 + 1%%d %% 1000"
  6. )
  7. rem 片头毫秒数 + 延迟毫秒数 = 总延迟毫秒数
  8. for /f "tokens=2 delims=:" %%i in ('MediaInfo 1.avi ^| find /i "Delay relative to video"') do (
  9.     set "s=%%i+0"
  10.     set "s=!s:h=*3600*1000+!"
  11.     set "s=!s:min=*60*1000+!"
  12.     set "s=!s:ms=!"
  13.     set "s=!s:s=*1000+!"
  14.     if "!s:-=!" NEQ "!s!" set "s=!s:-=-1*(!)"
  15.     set /a "t1 -= !s!"
  16. )
  17. rem 总延迟毫秒数转回 hh:mm:ss.ms 格式
  18. set /a  ms=t1%%1000+1000, t1/=1000, hh=t1/3600+100, mm=t1%%3600/60+100, ss=t1%%60+100
  19. set "t=!hh:~1!:!mm:~1!:!ss:~1!.!ms:~1!"
  20. echo;!t!
  21. pause
复制代码

作者: xp3000    时间: 2018-10-8 17:05

谢谢,明白了




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2