Водяной знак не работает для видео с восклицательными знаками

Я сделал скрипт .bat для водяных знаков видео с логотипом, медленно скользящим по видео справа налево. Вот мой код:

set ffmpeg="C:\ffmpeg\ffmpeg.exe"
set ffprobe="C:\ffmpeg\ffprobe.exe"

@echo off
setlocal enableextensions enabledelayedexpansion
for %%A in ("H:\4 - Watermark Process\Before\*.mp4") do (
    echo "________________________________________________________________________________________________________________________"
    echo _ Filename _: %%A
    rem Find videoDuration
    for /F "delims=" %%G in ('ffprobe.exe -v error -show_entries format^=duration -of default^=noprint_wrappers^=1:nokey^=1 "%%A" 2^>^&1') do (
        set /A videoDuration=%%G/1
        echo _ Video Duration _: !videoDuration!
    )

    rem Find videoWidth
    for /F "delims=" %%I in ('ffprobe -v error -show_entries stream^=width -of csv^=p^=0:s^=x "%%A"') do (
        set videoWidth=%%I
        echo _ Video Width _: !videoWidth!
    )

    rem Find videoHeight
    for /F "delims=" %%J in ('ffprobe -v error -show_entries stream^=height -of csv^=s^=x:p^=0 "%%A"') do (
        set videoHeight=%%J
        echo _ Video Height _: !videoHeight!
    )

    rem Scale logo watermark according to video Width and Height
    if !videoHeight! LSS !videoWidth! (
        echo "_ videoHeight LESS THAN videoWidth _"
        set /A scaleWidth = !videoWidth!/10
        ffmpeg -i logo.png -y -v verbose -vf scale=!scaleWidth!:-1 scaled.png
    ) else (
        echo "_ videoHeight GREATER THAN videoWidth _"
        set /A scaleWidth = !videoWidth!/4
        ffmpeg -i logo.png -y -v verbose -vf scale=!scaleWidth!:-1 scaled.png
    )

    rem Place logo watermark based on video Duration
    if !videoDuration! LSS 10 (
        echo "_ videoDuration LESS THAN 10 seconds _"
        echo "________________________________________________________________________________________________________________________"
        ffmpeg -i "%%A" -i scaled.png -filter_complex "overlay=10:main_h-overlay_h" "H:\4 - Watermark Process\After\%%~nA.mp4"
        echo "______________________________________________LESS THAN 10SEC CONVERSION COMPLETE__________________________________________________________________________"
    )
    if !videoDuration! GEQ 10 (
        set /A "videoDurationOneThird=(videoDuration*2)/3"
        echo _ videoDuration One Third _: !videoDurationOneThird!
        echo "________________________________________________________________________________________________________________________"
        ffmpeg -i "%%A" -i scaled.png -filter_complex "[0:v][1:v] overlay='if(gte(t,!videoDurationOneThird!), (main_w-(w+(t-!videoDurationOneThird!)*20)), NAN)':(main_h-overlay_h)/2:enable=between'(t,!videoDurationOneThird!,!videoDuration!)'" "H:\4 - Watermark Process\After\%%~nA.mp4"
    )
)

pause 10

Проблема в том, что я получаю сообщение об ошибке на видео с восклицательными знаками: Нет такого файла или каталога.

Я читал, что включение отложенного расширения удаляет восклицательный знак, но мне это нужно для правильной работы скрипта. Как я могу это исправить?

Неудачное решение, которое я пробовал, приведено ниже:

set ffmpeg="C:\ffmpeg\ffmpeg.exe"
set ffprobe="C:\ffmpeg\ffprobe.exe"

@echo off
setlocal enableextensions disabledelayedexpansion
for %%A in ("H:\4 - Watermark Process\BeforeWide\*.mp4") do (
    set FILE=%%~A
    set NAME=%%~nA
    echo "________________________________________________________________________________________________________________________"
    echo _ Filename _: !FILE!
    setlocal enabledelayedexpansion
    rem Find videoDuration
    for /F "delims=" %%G in ('ffprobe.exe -v error -show_entries format^=duration -of default^=noprint_wrappers^=1:nokey^=1 !FILE! 2^>^&1') do (
        set /A videoDuration=%%G/1
        echo _ Video Duration _: !videoDuration!
    )

    rem Find videoWidth
    for /F "delims=" %%I in ('ffprobe -v error -show_entries stream^=width -of csv^=p^=0:s^=x !FILE!') do (
        set videoWidth=%%I
        echo _ Video Width _: !videoWidth!
    )

    rem Find videoHeight
    for /F "delims=" %%J in ('ffprobe -v error -show_entries stream^=height -of csv^=s^=x:p^=0 !FILE!') do (
        set videoHeight=%%J
        echo _ Video Height _: !videoHeight!
    )

    rem Scale logo watermark according to video Width and Height
    if !videoHeight! LSS !videoWidth! (
        echo "_ videoHeight LESS THAN videoWidth _"
        set /A scaleWidth = !videoWidth!/10
        ffmpeg -i logo.png -y -v verbose -vf scale=!scaleWidth!:-1 scaled.png
    ) else (
        echo "_ videoHeight GREATER THAN videoWidth _"
        set /A scaleWidth = !videoWidth!/4
        ffmpeg -i logo.png -y -v verbose -vf scale=!scaleWidth!:-1 scaled.png
    )

    rem Place logo watermark based on video Duration
    if !videoDuration! LSS 10 (
        echo "_ videoDuration LESS THAN 10 seconds _"
        echo "________________________________________________________________________________________________________________________"
        ffmpeg -i !FILE! -i scaled.png -filter_complex "overlay=10:main_h-overlay_h" "H:\4 - Watermark Process\After\!NAME!.mp4"
        echo "______________________________________________LESS THAN 10SEC CONVERSION COMPLETE__________________________________________________________________________"
    )
    if !videoDuration! GEQ 10 (
        set /A "videoDurationOneThird=(videoDuration*2)/3"
        echo _ videoDuration One Third _: !videoDurationOneThird!
        echo "________________________________________________________________________________________________________________________"
        ffmpeg -i !FILE! -i scaled.png -filter_complex "[0:v][1:v] overlay='if(gte(t,!videoDurationOneThird!), (main_w-(w+(t-!videoDurationOneThird!)*20)), NAN)':(main_h-overlay_h)/2:enable=between'(t,!videoDurationOneThird!,!videoDuration!)'" "H:\4 - Watermark Process\After\!NAME!.mp4"
    )
    endlocal
)

pause 10

person Tevin Mosley    schedule 08.10.2020    source источник
comment
Проблема в том, что вы используете метапеременную for %%A, когда включено отложенное расширение, поэтому любые ! потребляются отложенным расширением; чтобы решить эту проблему, вам нужно отключить отложенное расширение до того, как наступит цикл for %%A in …, а затем в теле цикла сначала установить несколько переменных (например, set "FILE=%%~A" & set "NAME=%%~nA"), затем включить отложенное расширение, а затем использовать эти переменные (поэтому используйте !FILE! вместо %%A и !NAME! вместо %%~nA) и, наконец, поставить endlocal последней командой в теле цикла…   -  person aschipfl    schedule 08.10.2020
comment
Командная строка set /A videoDuration=%%G/1 действительно интересна. В результате SET выводит сообщение об ошибке для обработки STDERR для значения с плавающей запятой, например, 20.43 назначается переменной цикла G, а затем определяется переменная среды videoDuration со значением 20. . Эта командная строка с арифметическим выражением вообще не понадобится при использовании for /F "delims=. " %%G in ....   -  person Mofi    schedule 08.10.2020
comment
aschipfl. Я пробовал ваше решение, но оно дает ошибки. Вы можете проверить мой код? я отредактировал пост   -  person Tevin Mosley    schedule 08.10.2020
comment
Что вы ожидаете от разницы между pause 10 и просто pause? Команда pause не поддерживает аргумент, отличный от /?, что приводит к печати небольшой справки для этой простой команды. timeout может лучше подойти для вашей задачи. Запустите timeout /? для справки по этой команде, доступной по умолчанию, начиная с Windows Vista, которая является внешней командой, т.е. представляет собой исполняемый файл с полным именем файла %SystemRoot%\System32\timeout.exe.   -  person Mofi    schedule 08.10.2020
comment
Вы эффективно использовали if !videoHeight! LSS !videoWidth! (echo "_ videoHeight LESS THAN videoWidth _") else echo "_ videoHeight GREATER THAN videoWidth _" Что произойдет, если они оба одинаковы? Вы не учли этот сценарий, поэтому он будет рассматриваться как GREATER THAN. Если это то, что вы намеревались, измените компаратор/порядок по мере необходимости.   -  person Compo    schedule 08.10.2020
comment
Компо. Да, я хочу, чтобы по умолчанию было больше, чем потому, что водяной знак был бы того же размера.   -  person Tevin Mosley    schedule 08.10.2020
comment
Подсказка: не используйте set /A scaleWidth = !videoWidth!/10, а вместо этого используйте set /A scaleWidth=videoWidth/10, который лучше и всегда работает даже на videoWidth, который вообще не определен. Переменные среды могут быть указаны внутри арифметического выражения только их именами. Нет необходимости в %VariableName% или !VariableName! внутри арифметического выражения, которое является строкой после set /A. Это объясняется выводом команды SET при запуске set /? в окне командной строки.   -  person Mofi    schedule 08.10.2020
comment
Я также предполагаю, что вы разработали это для работы в Windows 10. Я говорю это, потому что вы echoed 120 символы подчеркивания, (ширина символа окна cmd.exe по умолчанию). Однако вы также включили заключающие двойные кавычки, что означает, что те строки, которые в любом случае не нужны, будут переноситься и выглядеть плохо. Поэтому вы должны удалить по крайней мере два из них в каждом экземпляре.   -  person Compo    schedule 08.10.2020
comment
Мофи. Я нашел проблему. Дело в том, что мне нужно включать и отключать отложенное расширение для определенных частей кода в одном и том же цикле. У Aschipfl была правильная идея, но она все еще не работает с его решением.   -  person Tevin Mosley    schedule 08.10.2020
comment
Еще две подсказки: echo _ Filename _: !FILE! во втором коде не работает, так как отложенное расширение не включено для cmd.exe обработки этой командной строки. Вы должны использовать здесь echo _ Filename _: %%~A. Вы знаете, что команда echo выводит также все "? Вы действительно хотите вывести все эти " в начале и конце несколькихecho строк аргументов? Кстати: я рекомендую назвать один видеофайл ;Development & Test !File!.mp4 и посмотреть, сможет ли окончательный пакетный файл правильно обработать этот видеофайл с очень необычным именем.   -  person Mofi    schedule 08.10.2020
comment
Подождите, я вижу определенную синтаксическую ошибку. Во всех внутренних циклах FOR вы должны использовать "!FILE!" вместо только !FILE!, и вам лучше использовать в начале также set "FILE=%%~A" и set "NAME=%%~nA". По причинам см. проблемы в этом длинном ответе и примите во внимание, что для каждой командной строки заключенный в ' командной строки for /F, еще один командный процесс запускается с %ComSpec% /c в фоновом режиме с полностью развернутой и обработанной командной строкой, добавленной в качестве дополнительных аргументов для запуска фоном cmd.   -  person Mofi    schedule 08.10.2020
comment
Мофи. Вот оно! Теперь это работает. Спасибо и Компо!   -  person Tevin Mosley    schedule 08.10.2020


Ответы (1)


Вот непроверенный пример для вас, основанный на предоставленной вами информации:

@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion

Set "Source=H:\4 - Watermark Process"
Set "Before=BeforeWide"
Set "After=After"
Set "Glob=*.mp4"
Set "ffmpeg=C:\ffmpeg\ffmpeg.exe"
Set "ffprobe=C:\ffmpeg\ffprobe.exe"
Set "logo=%CD%\logo.png"
Set "scaled=%CD%\scaled.png"

For %%A In ("%Source%\%Before%\%Glob%") Do (
    Set "FullName=%%A"
    Set "NameOnly=%%~nxA"
    If Not Exist "%Source%\%After%\" MD "%Source%\%After%" || GoTo :EOF  2> NUL
    SetLocal EnableDelayedExpansion
    Echo ________________________________________________________________________________________________________________________
    Echo _ Filename _: !FullName!
    Set /A "videoDuration=videoWidth=videoHeight=0"
    Rem Find videoDuration
    For /F Delims^=^ EOL^= %%G In (
        '^""%ffprobe%" -v error -show_entries format^=duration -of default^=noprint_wrappers^=1:nokey^=1 "!FullName!" 2^>^&1^"'
    ) Do Set /A "videoDuration=%%G / 1" 2> NUL
    Echo _ Video Duration _: !videoDuration!
    Rem Find videoWidth
    For /F Delims^=^ EOL^= %%I In (
        '^""%ffprobe%" -v error -show_entries stream^=width -of csv^=p^=0:s^=x "!FullName!"^"'
    ) Do Set /A "videoWidth=%%I" 2> NUL 
    Echo _ Video Width _: !videoWidth!
    Rem Find videoHeight
    For /F Delims^=^ EOL^= %%J In (
        '^""%ffprobe%" -v error -show_entries stream^=height -of csv^=s^=x:p^=0 "!FullName!"^"'
    ) Do Set /A "videoHeight=%%J" 2> NUL
    Echo _ Video Height _: !videoHeight!
    Rem Scale logo watermark according to video Width and Height
    If !videoHeight! Lss !videoWidth! (
        Echo _ videoHeight LESS THAN videoWidth _
        Set /A "scaleWidth=videoWidth / 10"
    ) Else (
        Echo _ videoHeight GREATER THAN videoWidth _
        Set /A "scaleWidth=videoWidth / 4"
    )
    "%ffmpeg%" -i "%logo%" -y -v verbose -vf scale=!scaleWidth!:-1 "%scaled%"
    Rem Place logo watermark based on video Duration
    If !videoDuration! Lss 10 (
        Echo _ videoDuration LESS THAN 10 seconds _
        Echo ________________________________________________________________________________________________________________________
        "%ffmpeg%" -i "!FullName!" -i "%scaled%" -filter_complex "overlay=10:main_h-overlay_h" "%Source%\%After%\!NameOnly!"
        Echo __________________________________________LESS THAN 10SEC CONVERSION COMPLETE___________________________________________
    )
    If !videoDuration! GEq 10 (
        Set /A "videoDurationOneThird = (videoDuration * 2) / 3"
        Echo _ videoDuration One Third _: !videoDurationOneThird!
        Echo ________________________________________________________________________________________________________________________
        "%ffmpeg%" -i "!FullName!" -i "%scaled%" -filter_complex "[0:v][1:v] overlay='if(gte(t,!videoDurationOneThird!), (main_w-(w+(t-!videoDurationOneThird!)*20)), NAN)':(main_h-overlay_h)/2:enable=between'(t,!videoDurationOneThird!,!videoDuration!)'" "%Source%\%After%\!NameOnly!"
    )
    EndLocal
)
%SystemRoot%\System32\timeout.exe /T 10 /NoBreak 1> NUL

Вам нужно только изменить значения переменных в изолированной группе Set. Обратите внимание, что я использовал %CD% для .png файлов, поскольку вы не указали их местоположение. Однако, поскольку вы также не установили текущий каталог, у вас могут быть эти файлы в том же каталоге, что и работающий скрипт. Если это так, вам действительно следует изменить оба с %CD% на %~dp0.

person Compo    schedule 08.10.2020