Estou tentando usar ffmpeg -f concat
. Funciona quando uso um arquivo temporário. Para organização, seria melhor usar uma lista canalizada. Vi exemplos disso em postagens antigas da web. Não funciona mais ou estou esquecendo de algo óbvio? Aqui está um script que ilustra o problema - se você executá-lo, test.sh x
ele funciona criando um arquivo temporário. Se você executá-lo test.sh
, o ffmpeg falha. Conforme observado no comentário do script, tentei com -safe 0
e -protocol_whiteflag "file,pipe,fd"
.
#!/bin/zsh
o=test.mp4
tmp=test.tmp
if [[ "$1" == "x" ]] ; then
echo Temp file $tmp...
ls GX01000?.mp4 | perl -ne 'print "file $_"' > $tmp
ffmpeg -hide_banner -y -f concat -i $tmp -c copy $o
else
echo Pipe
ls GX01000?.mp4 | perl -ne 'print "file $_"' | \
ffmpeg -hide_banner -y -f concat -i - -c copy $o
# this command line with -safe 0 and -protocol_whitelist doesn't work either
# ffmpeg -hide_banner -y -safe 0 -protocol_whitelist "file,pipe,fd" -f concat -i - -c copy $o
fi
Aqui está a saída do caso de falha:
% ./test.sh
Pipe
[fd @ 0x6000015f0620] Protocol 'fd' not on whitelist 'crypto,data'!
[concat @ 0x12e7055f0] Impossible to open 'fd:GX010005.mp4'
[in#0 @ 0x6000002f0100] Error opening input: Invalid argument
Error opening input file -.
Error opening input files: Invalid argument
Obrigado!
Isso parece funcionar:
É baseado na resposta de @terdon. A diferença crítica é que os nomes de arquivo na lista de arquivos agora são caminhos absolutos, graças à
$PWD
expressão in the glob. Ela também adiciona aspas simples ao redor dos nomes, que são necessárias se o caminho completo contiver espaços.Aparentemente
ffmpeg
usa o local do arquivo passado como argumento para-i
como diretório para quaisquer caminhos relativos na lista. Quando você usou um arquivo temporário, esse arquivo estava no mesmo local que os arquivos de entrada, então funcionou. Quando chamado com uma substituição de processo,ffmpeg
viu o nome do arquivo como algo como/dev/fd/12
, e assumiu que todos os nomes de arquivo relativos se referiam a arquivos em/dev/fd
.Esse comportamento
ffmpeg
é, hum, não convencional. Não tenho ideia se está documentado em algum lugar.Não é um pipe propriamente dito, mas como seu objetivo é limpeza, considere o redirecionamento de arquivos subshell:
<(...)
invoca a substituição de processo, que trata a saída de um subcomando como um descritor de arquivo que o ffmpeg pode ler diretamente, sem nenhuma lógica interna especial para ativar o-
símbolo.Edição: Atualizado o exemplo original de substituição de subprocesso com o truque do caminho absoluto de Gairfowl.
Podemos usar um pipe nomeado .
Exemplo:
mkfifo list.txt
- cria um pipe nomeado chamado "list.txt".echo
comando grava a lista de arquivos no pipe nomeado (usando o caminho completo).echo
comando termina com&
a execução em segundo plano - necessário porque escrever em um pipe nomeado é uma "operação de bloqueio".ffmpeg -y -f concat -safe 0 -i list.txt -c copy output.mp4
- lê a lista do pipe nomeado.No final, podemos excluir o pipe nomeado:
rm list.txt
.Testei o exemplo com FFmpeg 7.1 no Ubuntu 24.04
Atualização:
Caso alguém tropece no problema...
De acordo com a resposta aceita, usar o caminho completo do arquivo resolve o problema.
Usar o caminho completo está funcionando no terminal do Windows:
(echo file /Tmp/input1.mp4 && echo file /Tmp/input2.mp4) | ffmpeg -y -f concat -safe 0 -protocol_whitelist file,pipe -i pipe: -c copy output.mp4
No terminal Linux ainda há um problema (pelo menos com o FFmpeg 7.1):
Executando:
echo -e "file /home/rotem/Tmp/input1.mp4\nfile /home/rotem/Tmp/input2.mp4" | ffmpeg -y -f concat -safe 0 -protocol_whitelist file,pipe -i pipe: -c copy output.mp4
Dá um erro:
Impossible to open 'pipe:/home/rotem/Tmp/input1.mp4'
Parece um bug no FFmpeg...
Eu realmente duvido que usar
-i -
teria funcionado aqui. A-i
opção e expects um arquivo , não um fluxo de dados, então precisa receber algo que possa ser tratado como um caminho para um arquivo:Entretanto, se o seu shell for
bash
ou qualquer outro que suporte substituição de processos , você pode fornecer a saída do comando como um arquivo:Enquanto estiver nisso, evite analisar a saída de
ls
pois ela é frágil e provavelmente quebrará (provavelmente não neste caso em que você tem um glob tão simples, mas é melhor se acostumar a evitá-la). Você também deve citar suas variáveis (menos essenciais para zsh, ainda é uma boa ideia). Aqui está uma versão mais robusta do comando: