Json 是否有一种方法可以使用ffmpeg按章节批量拆分文件,然后在windows中使用mkvmerge重新组装?

Json 是否有一种方法可以使用ffmpeg按章节批量拆分文件,然后在windows中使用mkvmerge重新组装?,json,ffmpeg,jq,trim,mkv,xidel,Json,Ffmpeg,Jq,Trim,Mkv,Xidel,因此,我最初制作了一个批处理脚本,它能够相对精确地将视频剪辑成章节,而不必按关键帧运行,但代码看起来很糟糕,我无法让它在所有mp4文件中循环,也无法让mkvmerge在分割文件后追加这些文件。代码如下,但要温柔,这是我第一次尝试 @echo off setlocal enableDelayedExpansion REM CODE BELOW CREATES JSON FILES FOR ALL MP4 FILES WITHIN THE SAME DIRECTORY ffprobe -v qui

因此,我最初制作了一个批处理脚本,它能够相对精确地将视频剪辑成章节,而不必按关键帧运行,但代码看起来很糟糕,我无法让它在所有mp4文件中循环,也无法让mkvmerge在分割文件后追加这些文件。代码如下,但要温柔,这是我第一次尝试

@echo off
setlocal enableDelayedExpansion

REM CODE BELOW CREATES JSON FILES FOR ALL MP4 FILES WITHIN THE SAME DIRECTORY
ffprobe -v quiet -print_format json -show_chapters -loglevel error "01x01.mp4" > "01x01.json"

REM CODE BELOW SETS VARIABLES FROM EACH SPECIFIC JSON
FOR /F "delims=" %%i in ('jq .chapters[2].start ^< 01x01.json') DO SET /A start1=%%i
FOR /F "delims=" %%j in ('jq .chapters[2].end ^< 01x01.json') DO SET /A end1=%%j

FOR /F "delims=" %%k in ('jq .chapters[4].start ^< 01x01.json') DO SET /A start2=%%k
FOR /F "delims=" %%l in ('jq .chapters[4].end ^< 01x01.json') DO SET /A end2=%%l

FOR /F "delims=" %%m in ('jq .chapters[6].start ^< 01x01.json') DO SET /A start3=%%m
FOR /F "delims=" %%n in ('jq .chapters[6].end ^< 01x01.json') DO SET /A end3=%%n

FOR /F "delims=" %%o in ('jq .chapters[8].start ^< 01x01.json') DO SET /A start4=%%o
FOR /F "delims=" %%p in ('jq .chapters[8].end ^< 01x01.json') DO SET /A end4=%%p

REM SETS THE DURATION OF EACH FILE TO USE PRECISION TIMING FOR START AND STOP TIMES
CALL vbs (%end1%-%start1%)/1000
SET duration1=%val%
CALL vbs (%end2%-%start2%)/1000
SET duration2=%val%
CALL vbs (%end3%-%start3%)/1000
SET duration3=%val%
CALL vbs (%end4%-%start4%)/1000
SET duration4=%val%

REM SETS THE START TIME IN SECONDS VS MILLISECONDS
CALL vbs (%start1%)/1000
SET start1=%val%
CALL vbs (%start2%)/1000
SET start2=%val%
CALL vbs (%start3%)/1000
SET start3=%val%
CALL vbs (%start4%)/1000
SET start4=%val%

REM TRIM AND SPLIT ORIGINAL FILE INTO SEPERATE SECTIONS BASED ON CHAPTER MARKERS
ffmpeg -ss %START1% -i 01x01.mp4 -ss 0 -c copy -to %DURATION1% -avoid_negative_ts make_zero 01x01-1.mp4
ffmpeg -ss %START2% -i 01x01.mp4 -ss 0 -c copy -to %DURATION2% -avoid_negative_ts make_zero 01x01-2.mp4
ffmpeg -ss %START3% -i 01x01.mp4 -ss 0 -c copy -to %DURATION3% -avoid_negative_ts make_zero 01x01-3.mp4
ffmpeg -ss %START4% -i 01x01.mp4 -ss 0 -c copy -to %DURATION4% -avoid_negative_ts make_zero 01x01-4.mp4

REM DELETES UNNEEDED JSON AFTER USE
del /s *.json

REM APPEND ALL MP4 FILES INTO COHESIVE MKV
for /d /r %%D in (*) do (
    pushd %%D
    set files=
    for %%F in (*.mp4) do set files=!files! + ^( "%%F" ^)
    if not "!files!"=="" %mkvmerge% -o "01x01-FINAL.mkv" !files:~2!
    popd
)

REM DELETE UNNEEDED MP4 ORIGINALS AND SPLIT FILES
del /s *.mp4
我也试着使用开始时间,所以我不需要做额外的计算,但jq也不喜欢这样

当我把它放在这里的时候,mkvmerge甚至没有试着运行,当它再次成为一个文件的时候,我仍然需要在它的结尾处减少7秒,在它的前面减少12秒

任何帮助都将被感激,我知道这是很多,但我似乎遇到了一个路障或只是在这一点上睡眠剥夺

更新

这真是太棒了,我只需要弄清楚如何使用带有空格的文件,我已经准备好了。我想我可以先运行批处理,然后用下划线替换所有空格。这可能会工作,但我想不改变文件名,如果我可以帮助它

@echo off

for %%i in (*.mp4) do (
FOR /F "delims=" %%A IN ('ffprobe -v quiet -print_format json -show_chapters -loglevel error "%%i" ^| xidel - -se "$json/(chapters)()[id!=0 and tags/title='Video']/concat('ffmpeg -ss ',start div 1000,' -i %%i -to ',((end - start) div 1000),' -c copy -avoid_negative_ts make_zero %%~ni-',position(),'.mp4')"') DO %%A
FOR /F "delims=" %%A IN ('xidel -s --xquery "concat('mkvmerge -o &quot;%%~ni-FINAL.mkv&quot; &quot;',join(file:list(.,false(),'%%~ni-*.mp4'),'&quot; + &quot;'),'&quot;')"') DO %%A
)

如果我理解正确,您希望删除“广告”-章节。
这可能完全可以通过
ffmpeg
实现,但如果没有源视频,我不能确定

无论如何,让我为您提供一个非常优雅的解决方案,帮助您完成拆分过程

首先,您不必将
ffprobe
的输出保存到JSON文件中。您只需通过管道将其连接到xidel即可:

ffprobe -v quiet -print_format json -show_chapters -loglevel error "01x01.mp4" | xidel - -se "$json"
选择标记为“视频”的对象/章节:

(我不确定您为什么不想要第一章。如果想要,请删除
id!=0和

要计算4章的持续时间:

ffprobe [...] | xidel - -se "$json/(chapters)()[id!=0 and tags/title='Video']/round-half-to-even(end_time - start_time,3)"
#or
ffprobe [...] | xidel - -se "$json/(chapters)()[id!=0 and tags/title='Video']/((end - start) div 1000)"
149.97
351.909
817.738
52.127
使用这些值创建
ffmpeg
字符串/命令并
start

ffprobe [...] | xidel - -se "$json/(chapters)()[id!=0 and tags/title='Video']/concat('ffmpeg -ss ',start div 1000,' -i 01x01.mp4 -to ',((end - start) div 1000),' -c copy -avoid_negative_ts make_zero 01x01-',position(),'.mp4')"
ffmpeg -ss 13.994 -i 01x01.mp4 -to 149.97 -c copy -avoid_negative_ts make_zero 01x01-1.mp4
ffmpeg -ss 195.94 -i 01x01.mp4 -to 351.909 -c copy -avoid_negative_ts make_zero 01x01-2.mp4
ffmpeg -ss 595.85 -i 01x01.mp4 -to 817.738 -c copy -avoid_negative_ts make_zero 01x01-3.mp4
ffmpeg -ss 1477.569 -i 01x01.mp4 -to 52.127 -c copy -avoid_negative_ts make_zero 01x01-4.mp4
美化命令/查询:

ffprobe [...] | xidel - -se ^"^
  $json/(chapters)()[id!=0 and tags/title='Video']/concat(^
    'ffmpeg -ss ',^
    start div 1000,^
    ' -i 01x01.mp4 -to ',^
    ((end - start) div 1000),^
    ' -c copy -avoid_negative_ts make_zero 01x01-',^
    position(),^
    '.mp4'^
  )^
"
要执行这些
ffmpeg
命令,只需将整个
ffprobe
/
xidel
命令放入
FOR
-循环中:

FOR /F "delims=" %A IN ('ffprobe [...] ^| xidel - -se "$json/(chapters)()[id!=0 and tags/title='Video']/concat('ffmpeg -ss ',start div 1000,' -i 01x01.mp4 -to ',((end - start) div 1000),' -c copy -avoid_negative_ts make_zero 01x01-',position(),'.mp4')"') DO %A
FOR /F "delims=" %A IN ('xidel -s --xquery "concat('mkvmerge -o &quot;01x01-FINAL.mkv&quot; &quot;',join(file:list(.,false(),'01x01-*.mp4'),'&quot; + &quot;'),'&quot;')"') DO %A
(在批处理脚本中使用
%%a
,如果是
SETLOCAL ENABLEDELAYEDEXPANSION
则转义惊叹标记;
id^!=0

鉴于
cmd
的所有缺点,我将再次使用
xidel
创建
mkvmerge
字符串/命令:

xidel -s -e "file:list(.,false(),'01x01-*.mp4')"
01x01-1.mp4
01x01-2.mp4
01x01-3.mp4
01x01-4.mp4

xidel -s -e "join(file:list(.,false(),'01x01-*.mp4'),' + ')"
01x01-1.mp4 + 01x01-2.mp4 + 01x01-3.mp4 + 01x01-4.mp4

xidel -s -e "concat('\"',join(file:list(.,false(),'01x01-*.mp4'),'\" + \"'),'\"')"
#or
xidel -s --xquery "concat('&quot;',join(file:list(.,false(),'01x01-*.mp4'),'&quot; + &quot;'),'&quot;')"
"01x01-1.mp4" + "01x01-2.mp4" + "01x01-3.mp4" + "01x01-4.mp4"

xidel -s --xquery "concat('mkvmerge -o &quot;01x01-FINAL.mkv&quot; &quot;',join(file:list(.,false(),'01x01-*.mp4'),'&quot; + &quot;'),'&quot;')"
mkvmerge -o "01x01-FINAL.mkv" "01x01-1.mp4" + "01x01-2.mp4" + "01x01-3.mp4" + "01x01-4.mp4"
要再次执行
mkvmerge
命令,只需将整个
xidel
命令放入
FOR
-循环中:

FOR /F "delims=" %A IN ('ffprobe [...] ^| xidel - -se "$json/(chapters)()[id!=0 and tags/title='Video']/concat('ffmpeg -ss ',start div 1000,' -i 01x01.mp4 -to ',((end - start) div 1000),' -c copy -avoid_negative_ts make_zero 01x01-',position(),'.mp4')"') DO %A
FOR /F "delims=" %A IN ('xidel -s --xquery "concat('mkvmerge -o &quot;01x01-FINAL.mkv&quot; &quot;',join(file:list(.,false(),'01x01-*.mp4'),'&quot; + &quot;'),'&quot;')"') DO %A
(为什么
--xquery
?因为
\”
将在
FOR
-循环中导致“转义字符地狱”)


如果您对
-循环仅使用这两个
,这也意味着不再需要
SETLOCAL ENABLEDELAYEDEXPANSION

这只创建了第一章,我不想这样做,但去掉了
id=0和
创建了所有章节。我想这很好。我还使用了mkvmerge,但它也包含了被分离的原始文件。这非常完美,适用于任何没有空格的文件。如果我尝试在文件名中首先使用空格来表示循环中断,但我尝试在一些地方添加了
,但这也会导致第一个for循环中断。我会继续尝试,看看是否可以在文件名中使用空格。再次感谢您的帮助。@Sipherdrakon try
表示%%I in(“*.mp4”)可以吗(
。它仍在将其拆分为两个文件名,但没有什么大不了的。只添加了一个片段,将所有空格改为下划线,它运行得非常完美。
FOR /F "delims=" %A IN ('xidel -s --xquery "concat('mkvmerge -o &quot;01x01-FINAL.mkv&quot; &quot;',join(file:list(.,false(),'01x01-*.mp4'),'&quot; + &quot;'),'&quot;')"') DO %A