Estou usando o EndeavourOS e se eu reproduzir áudio com o comando ffmpeg -i test.flac -f alsa default
, o terminal mostra esse tipo de saída:
size=N/A time=00:00:21.31 bitrate=N/A speed=1.22x
Gostaria de pegar o parâmetro 'time=' e seu valor lá. Sei que o ffmpeg gera saídas para STDERR, então, sei que redirecionar 2>1, então tento:
ffmpeg -i test.flac -f alsa default 2>&1 | grep time
…e o terminal fica completamente em branco neste ponto (embora a música toque perfeitamente).
Eu também tentei:
ffmpeg -i test.flac -f alsa default 2>test.txt
…e em uma segunda sessão terminal:
tail -f test.txt | grep time
…e ainda em branco, embora se eu apenas seguir o arquivo sem a parte grep, eu vejo a linha de texto relevante com um valor time= cada vez maior.
Sei que será sugerido usar ffplay, mas estou lidando com muito código usando ffmpeg e alternar não é uma opção. Estou realmente mais interessado em saber uma resposta para o porquê de grep simplesmente não funcionar na saída STDERR do ffmpeg, não importa para onde ele seja redirecionado! Quase secundariamente: há uma maneira de extrair o valor de tempo da 'posição atual no fluxo' usando apenas ffmpeg?
À luz dos comentários abaixo:
ffmpeg -v
ffmpeg version n7.1 Copyright (c) 2000-2024 the FFmpeg developers
built with gcc 14.2.1 (GCC) 20240910
E a saída truncada apenas pela reprodução da música, sem redirecionamentos:
TAGDATE : 1623718801
encoder : Lavf61.7.100
Stream #0:0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s
Metadata:
encoder : Lavc61.19.100 pcm_s16le
size=N/A time=00:00:15.36 bitrate=N/A speed=1.34x
E alguns exemplos do que posso e não posso obter dessa saída:
[zelenka Desktop]$ ffmpeg -i test.flac -f alsa default 2>&1 | grep Duration
Duration: 00:21:10.00, start: 0.000000, bitrate: 690 kb/s
^C^C^C
[zelenka Desktop]$ ffmpeg -i test.flac -f alsa default 2>&1 | grep Audio
Stream #0:0: Audio: flac, 44100 Hz, stereo, s16
Stream #0:0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s
^C^C^C
[zelenka Desktop]$ ffmpeg -i test.flac -f alsa default 2>&1 | grep time=
^C^C^C
(E neste ponto eu tenho que Ctrl+ Cinterromper, pois nada aparece na tela). Usar grep nos dados 'estáticos' funciona; usar grep na parte dinâmica da size=N/A time=00:00:15.36 bitrate=N/A speed=1.34x
saída de linha não.
Editado para fornecer uma resposta funcional:
Na sessão 1, agora posso emitir este comando:
ffmpeg -stats_period 1 -i test.flac -f alsa default |& awk -v RS="\r" -v FS='[= ]' 'NR > 1 && /time/ {print $4; fflush("/dev/stdout")}' | tee test.txt
O que diz para o ffmpeg emitir uma contagem de progresso a cada 1 segundo. A saída de progresso é então passada para o awk, buscando pela linha 'out_time=' de progresso. Isso é então liberado e gravado em um arquivo test.txt.
Em um segundo terminal, eu então emito este comando:
tail -f test.txt | cut -c-8
...que produz uma saída como esta:
[zelenka Desktop]$ tail -1 test.txt | grep --line-buffered ":" |cut -c-8
00:00:04
00:00:05
00:00:06
00:00:07
00:00:08
00:00:09
...que eu posso usar!
Se você quiser ver apenas o
time
campo:Se você não quiser ver
time=
parte:Se você ainda quiser redirecionar a saída para outro arquivo, você pode seguir o procedimento de flush da saída no awk, mas lembre-se de que quanto mais coisas você fizer no pipeline, mais lento ele se tornará:
ffmpeg -i test.flac -f alsa default 2>&1 | grep time
não funciona porque grep é orientado a linhas, mas uma nova linha para ele significa\n
(ASCII 0xa, você pode verman ascii
), mas o ffmpeg usa\r
(ASCII 0xd) para ir ao início da linha e limpá-la para que as informações de tempo sejam sempre mostradas na mesma linha. Você pode ver isso com strace:É um separador de registros awk, você pode saber mais sobre ele no manual do GNU awk .
O ffmpeg tem uma opção
-progress
para gravar o progresso da saída em um arquivo (ou qualquer URL ou pipe).Então corra
ffmpeg -i test.flac -progress myfile.txt -f alsa default
e então
grep "time=" myfile.txt | tail -1