Como você converte um diretório inteiro com o ffmpeg?

191

Como você converte um diretório / pasta inteiro com o ffmpeg via linha de comando ou com um script em lote?

Eugene
fonte

Respostas:

175

A resposta anterior criará apenas 1 arquivo de saída chamado out.mov. Para criar um arquivo de saída separado para cada filme antigo, tente isso.

for i in *.avi;
  do name=`echo "$i" | cut -d'.' -f1`
  echo "$name"
  ffmpeg -i "$i" "${name}.mov"
done
Isaac
fonte
24
Se você é como eu e tem muitos espaços (e alguns outros caracteres problemáticos) em seus nomes de arquivo, sugiro adicionar aspas duplas: ffmpeg -i "$ i" "$ name.mov";
Pif
7
Estou recebendo o erroi was unexpected at this time.
Keavon 17/05
5
do name=`echo "${i%.*}"`;funcionará em nomes de arquivos com pontos (e espaços) neles.
Nepoxx
8
Uau, essa resposta é incrivelmente complicada. Veja uma das respostas de uma linha.
Foobarbecue
2
isso é suportado .batno Windows?
Jazuly
294

Para Linux e macOS, isso pode ser feito em uma linha, usando a expansão de parâmetros para alterar a extensão do nome do arquivo de saída:

for i in *.avi; do ffmpeg -i "$i" "${i%.*}.mp4"; done
llogan
fonte
2
Isso é perfeito, obrigado! Aqui está o comando completo que acabou funcionando muito bem para mim: para i em * .avi; faça ffmpeg -i "$ i" -c: a aac -b: 128k -c: v libx264 -crf 20 "$ {i% .avi} .mp4"; feito #
Phil Kulak
1
@Junaid 1) Certifique-se de usar um nome diferente para o arquivo de saída do que a entrada ou para outro diretório, porque ffmpegnão é possível inserir e enviar para o mesmo arquivo. 2) Não tenho certeza se os comandos do Bash funcionam nativamente no Windows 10. Talvez eu deva acrescentar à resposta que ele é direcionado a sistemas que podem usar nativamente o Bash, como Linux e macOS. O lxs forneceu uma resposta do Windows para esta pergunta.
llogan
4
Resposta incrível. Também funciona com nomes de arquivos com espaços!
wisbucky
1
Essa deve ser a resposta principal. É certo que a explicação de por que {$ i%. *} Não é simples, mas se você puder deixar isso de lado e apenas "usá-lo", poderá modificar rapidamente para se adequar. Por exemplo, converti centenas de arquivos .mp4 (com nomes de arquivos com espaços e caracteres especiais) em um formato menor usando: para i em .mp4; do ffmpeg -i "$ i" -s 512x288 -c: uma cópia "$ {i%. } .m4v"; feito #
Tony M
1
Para dar um passo adiante, você pode usar a substituição do parâmetro Bash se desejar substituir a cadeia "x265" por "x264" se estiver transcodificando do H.265 para o H.264, que é um caso de uso comum. for f in *.mkv; do ffmpeg -i "$f" -map 0 -movflags faststart -c:v libx264 -c:a copy -c:s copy "${f/x265/x264}"; done
Travis Runyard 6/12/19
70

E no Windows:

FOR /F "tokens=*" %G IN ('dir /b *.flac') DO ffmpeg -i "%G" -acodec mp3 "%~nG.mp3"
lxs
fonte
19
se você executar este comando em um arquivo de lote (.bat), você precisa dobrar os sinais% => %%
hB0
Alguma idéia de como executar este comando, mas copiar para um novo arquivo que inclua os metadados do arquivo original?
Barryman9000
@ Barryman9000 isso foi há muito tempo, mas eu acho que há uma opção de arquivo de saída que você poderia passar
LX
@lxs obrigado pelo acompanhamento. Acabei fazendo isso com o Powershell alterando o nome do novo arquivo para ser a data do arquivo original criado stackoverflow.com/a/35671099/197472
Barryman9000 #
Utilizou-o para remover metadados. Mas está me dando erro de acesso negado. Então mudei o nome do arquivo de saída com um espaço extra para torná-lo novo. FOR /F "tokens=*" %G IN ('dir /b *.mp3') DO ffmpeg -i "%G" -map_metadata -1 -c:v copy -c:a copy "%~nG .mp3"
Junaid
28

Um script bash de uma linha seria fácil de fazer - substitua *.avipelo seu tipo de arquivo:

for i in *.avi; do ffmpeg -i "$i" -qscale 0 "$(basename "$i" .avi)".mov  ; done
gema
fonte
O codificador padrão para .mov é libx264 (se disponível), mas esse codificador ignora -qscale. Remova-o e use as configurações padrão ou use -crf(o padrão é -crf 23).
Llogan
1
Se houver algum espaço no nome do arquivo, o comando falhará porque o basenamesubshell backticked não está entre aspas. É exatamente por isso que o bash possui expansão de shell: for i in * .avi; do ffmpeg -i "$ i" - qscale 0 "$ (nome da base" $ i ".avi)". mov; feito
Calimo
graças @Calimo concordo totalmente - Eu atualizei a minha resposta
gema de
22

Para converter com subdiretórios, use eg

find . -exec ffmpeg -i {} {}.mp3 \;
user2707001
fonte
Eu usei isso, combinado com esta resposta para converter VTT em SRT, com grande efeito. find -name "*.vtt" -exec ffmpeg -i {} {}.srt \;
grooveplex
Eu este comando, com ligeiro modif para converter todos os mp4 para mp3:find *.mp4 -exec ffmpeg -i {} {}.mp3 \;
swdev 15/06
1
Ou, se você deseja converter vários tipos de arquivo:find . -name *.ogg -or -name *.wma -exec ffmpeg -i {} {}.mp3 \;
bonh 26/09
Converter todos os arquivos WMA para MP3 e depois excluí-los:find . -name *.wma -exec ffmpeg -i {} {}.mp3 \; -exec rm {} \;
Panagiotis
20

Para Windows:

Aqui estou convertendo todos os arquivos (.mp4) para arquivos (.mp3).
Basta abrir o cmd, ir para a pasta desejada e digite o comando

Atalho: (opcional)
1. Vá para a pasta em que seus arquivos (.mp4) estão presentes
2. Pressione Shift e clique esquerdo e escolha "Abrir janela do PowerShell aqui"
ou "Abrir janela do prompt de comando aqui"
3. Digite "cmd" [NOTA : Ignore esta etapa se ela abrir diretamente o cmd em vez do PowerShell]
4. Execute o comando

for %i in (*.mp4) do ffmpeg -i "%i" "%~ni.mp3"

Se você deseja colocar isso em um arquivo em lotes no Windows 10, use %% i.

shubhamr238
fonte
18

Para quem deseja converter em lote qualquer coisa com o ffmpeg, mas gostaria de ter uma interface conveniente do Windows, desenvolvi este front-end:

https://sourceforge.net/projects/ffmpeg-batch

Ele adiciona ao ffmpeg uma interface de moda de janelas, barras de progresso e informações de tempo restante, recursos que sempre perdi ao usar o ffmpeg.

Eibel
fonte
Ok, este é um bom projeto! Estou perseguindo minha cauda por uma hora tentando fazer com que o ffmpeg aceite um caminho relativo de arquivamento no Windows e isso faz com que pareça trapaça. EDIT: eu usei isso para converter .xwm para .flac
semtex41
6

Se você possui o GNU paralelo, pode converter todos os arquivos .avi abaixovid_dir em mp4 em paralelo, usando todos, exceto um dos núcleos da CPU com

find vid_dir -type f -name '*.avi' -not -empty -print0 |
    parallel -0 -j -1 ffmpeg -loglevel fatal -i {} {.}.mp4

Para converter de / para diferentes formatos, altere '*.avi'ou .mp4conforme necessário. O paralelo GNU é listado nos repositórios da maioria das distribuições Linux em um pacote que geralmente é chamado parallel.

sebbit
fonte
você não poderia fazer o mesmo adicionando !ao final de qualquer um dos bash one-liners?
STIB
3

Sei que isso pode ser redundante, mas uso esse script para converter arquivos em lote.

old_extension=$1
new_extension=$2

for i in *."$old_extension";
  do ffmpeg -i "$i" "${i%.*}.$new_extension";
done

São necessários 2 argumentos para torná-lo mais flexível:

  1. a extensão da qual você deseja converter
  2. a nova extensão que você deseja converter

Eu crio um alias para ele, mas você também pode usá-lo manualmente assim:

sh batch_convert.sh mkv mp4

Isso converteria todos os mkvarquivos em mp4arquivos.

Como você pode ver, é um pouco mais versátil. Enquanto ffmpegpuder convertê-lo, você poderá especificar duas extensões.

Alexander Luna
fonte
Isso é o melhor 👍
Andreas Prang
3

Como um código de golfe aqui, mas como quase todas as respostas até agora são bash (com exceção de um cmd único), aqui está um comando de plataforma cruzada do Windows que usa o powershell (porque impressionante):

ls *.avi|%{ ffmpeg -i $_ <ffmpeg options here> $_.name.replace($_.extension, ".mp4")}

Você pode alterar * .avi para o que corresponder à sua gravação de origem.

stib
fonte
3

É claro que agora surgiu o PowerShell, projetado especificamente para tornar extremamente fácil algo exatamente assim .

E, sim, o PowerShell também está disponível em outros sistemas operacionais, além do Windows, mas é pré-instalado no Windows, portanto, isso deve ser útil para todos.

Primeiro, você deseja listar todos os arquivos no diretório atual; portanto, começaremos com:

ls

Você também pode usar ls -Recurse se quiser converter recursivamente todos os arquivos em subdiretórios.

Em seguida, filtraremos esses arquivos apenas para o tipo de arquivo que queremos converter - por exemplo, "avi".

ls | Where { $_.Extension -eq ".avi" }

Depois disso, passaremos essas informações para o FFmpeg através de um ForEach .

Para entrada do FFmpeg, usaremos o FullName- esse é o caminho inteiro para o arquivo. E para a saída do FFmpeg, usaremos o Name- mas substituindo o .avino final por .mp3. Então, será algo parecido com isto:

$_.Name.Replace(".avi", ".mp3")

Então, vamos juntar tudo isso e este é o resultado:

ls | Where { $_.Extension -eq ".avi" } | ForEach { ffmpeg -i $_.FullName $_.Name.Replace(".avi", ".mp3") }

Isso converterá todos os arquivos ".avi" em arquivos ".mp3" através do FFmpeg, substitua as três aspas para decidir qual o tipo de conversão que você deseja e sinta-se à vontade para adicionar outros argumentos ao FFmpeg no ForEach.

Você poderia dar um passo adiante e adicionar Remove-Item no final para excluir automaticamente os arquivos antigos.

Se ffmpegnão estiver no seu caminho, e realmente estiver no diretório em que você está, escreva ./ffmpeglá em vez de apenas ffmpeg.

Espero que isso ajude alguém.

ABPerson
fonte
1
O PowerShell é ótimo, obrigado! Caso alguém tenha problemas para executar isso: coloque este comando em um .ps1arquivo, não em um .batarquivo. Você precisará executar Set-ExecutionPolicy RemoteSignedcomo administrador se nunca executou um script PS antes.
starpause
Bem, geralmente eu pensava em executá-lo diretamente no PowerShell, então não pensei nisso! Boa dica!
ABPerson
2
for i in *.flac;
  do name=`echo "${i%.*}"`;
  echo $name;
  ffmpeg -i "${i}" -ab 320k -map_metadata 0 -id3v2_version 3 "${name}".mp3;
done

Processar flacarquivos em lote em mp3(seguro para nomes de arquivos com espaços) usando [1] [2]

César D. Velandia
fonte
2

janelas:

@echo off
for /r %%d in (*.wav) do (
    ffmpeg -i "%%~nd%%~xd" -codec:a libmp3lame -c:v copy -qscale:a 2 "%

%~nd.2.mp3"
)

essa é a taxa de bits variável da qualidade 2, você pode defini-la como 0 se quiser, mas, a menos que você tenha um sistema de alto-falantes realmente bom, não vale nada a pena

user151496
fonte
1

Se você deseja que uma interface gráfica seja processada em lote com o ffmpegX, tente o Quick Batcher . É gratuito e terá suas últimas configurações do ffmpegX para converter os arquivos que você soltar nele.

Observe que você não pode arrastar e soltar pastas no Quick Batcher. Então, selecione os arquivos e os coloque no Quick Batcher.

Nirav Mehta
fonte
2
O software "Quick Batcher" é APENAS para o MAC OS
#:
1

Somente este funcionou para mim, observe que você precisa criar a pasta "newfiles" manualmente onde o arquivo ffmpeg.exe está localizado.

Converter . arquivos para áudio .wav Código:

for %%a in ("*.*") do ffmpeg.exe -i "%%a" "newfiles\%%~na.wav"
pause

ou seja, se você deseja converter todos os arquivos .mp3 para .wav, mude ("*.*")para ("*.mp3").

O autor deste script é:

https://forum.videohelp.com/threads/356314-How-to-batch-convert-multiplex-any-files-with-ffmpeg

espero que tenha ajudado.

Mehrdad995
fonte
0

Isso criará vídeo mp4 de todos os arquivos jpg do diretório atual.

echo exec("ffmpeg -framerate 1/5 -i photo%d.jpg -r 25 -pix_fmt yuv420p output.mp4");
thesachinparmar
fonte
0

E para Windows, isso não funciona

FOR /F "tokens=*" %G IN ('dir /b *.flac') DO ffmpeg -i "%G" -acodec mp3 "%~nG.mp3"

mesmo se eu dobrar isso %.

Eu até sugeriria:

-acodec ***libmp3lame***

Além disso:

FOR /F "tokens=*" %G IN ('dir /b *.flac') DO ffmpeg -i "%G" -acodec libmp3lame "%~nG.mp3"
Halligallator
fonte
Isso é uma resposta ou uma tentativa de postar uma nova pergunta como resposta? Neste último caso, em vez disso, crie uma pergunta completamente nova, embora possivelmente faça um link aqui para obter mais informações.
tripleee 12/06
0

Isto é o que eu uso para converter em lote avi para 1280x mp4

FOR /F "tokens=*" %%G IN ('dir /b *.avi') DO "D:\Downloads\ffmpeg.exe" -hide_banner -i "%%G" -threads 8 -acodec mp3 -b:a 128k -ac 2 -strict -2 -c:v libx264 -crf 23 -filter:v "scale=1280:-2,unsharp=5:5:1.0:5:5:0.0" -sws_flags lanczos -b:v 1024k -profile:v main -preset medium -tune film -async 1 -vsync 1 "%%~nG.mp4"

Funciona bem como um arquivo cmd, execute-o, o loop encontra todos os arquivos avi nessa pasta.

chama MY (mude para o seu) ffmpeg, passa o nome da entrada, as configurações são para redimensionar com nitidez. Os probs não precisam de CRF e " -b:v 1024k" ...

O arquivo de saída é um arquivo de entrada menos a extensão, com mp4 como novo ext.

Morphy
fonte
0

Estou usando esse linux no linux para converter arquivos (geralmente H265) em algo que eu possa jogar no Kodi sem problemas:

for f in *.mkv; do ffmpeg -i "$f" -c:v libx264 -crf 28 -c:a aac -b:a 128k output.mkv; mv -f output.mkv "$f"; done

Isso se converte em um arquivo temporário e substitui o original para que os nomes permaneçam os mesmos após a conversão.

user1634000
fonte
0

Além disso, se você quiser a mesma conversão em subpastas. aqui está o código recursivo.

for /R "folder_path" %%f in (*.mov,*.mxf,*.mkv,*.webm) do (
    ffmpeg.exe -i "%%~f" "%%~f.mp4"
    )
Hasan Yilmaz
fonte
-1

pequeno script php para fazer isso:

#!/usr/bin/env php
<?php
declare(strict_types = 1);
if ($argc !== 2) {
    fprintf ( STDERR, "usage: %s dir\n", $argv [0] );
    die ( 1 );
}
$dir = rtrim ( $argv [1], DIRECTORY_SEPARATOR );
if (! is_readable ( $dir )) {
    fprintf ( STDERR, "supplied path is not readable! (try running as an administrator?)" );
    die(1);
}
if (! is_dir ( $dir )) {
    fprintf ( STDERR, "supplied path is not a directory!" );
    die(1);
}
$files = glob ( $dir . DIRECTORY_SEPARATOR . '*.avi' );
foreach ( $files as $file ) {
    system ( "ffmpeg -i " . escapeshellarg ( $file ) . ' ' . escapeshellarg ( $file . '.mp4' ) );
}
hanshenrik
fonte
2
Uma resposta de escopo muito limitada, pois o usuário precisa ter o PHP instalado em sua máquina. As respostas da linha de comando e do arquivo em lote são muito mais fáceis e muito menos complexas.
ProfK
2
O @ProfK PHP é uma das linguagens mais populares no SO - segundo, a resposta de Isaac para sh é um pouco confiável, pois pode renomear seus arquivos para algo diferente do original, por exemplo, não preserva novas linhas no nome do arquivo. O script bat do lyx é ainda pior, IGNORA COMPLETAMENTE qualquer arquivo com novas linhas no nome. não sei por que, nem mesmo um erro de sintaxe ou algo assim, mas sim (testado no win10). meu script php não tem problemas, graças a escapeshellarg(), e funciona tanto no windows quanto no linux. Eu concordo que é um caso extremo.
hanshenrik
-1

Outra solução simples que ainda não foi sugerida seria usar xargs:

ls *.avi | xargs -i -n1 ffmpeg -i {} "{}.mp4"

Uma pequena armadilha é a nomeação incômoda dos arquivos de saída (por exemplo input.avi.mp4). Uma possível solução alternativa para isso pode ser:

ls *.avi | xargs -i -n1 bash -c "i={}; ffmpeg -i {} "\${i%.*}.mp4""

telenachos
fonte
O shellcheck.net tem algumas sugestões sobre seus exemplos.
Llogan
mywiki.wooledge.org/ParsingLs, embora você possa simplesmente substituir lspor printf '%s\n'aqui.
tripleee