extrair certas informações da saída

6

Estou tentando extrair certas informações da saída do ffmpeg.

Exemplo de saída do ffmpeg:

configuration:  --enable-memalign-hack --enable-mp3lame --enable-gpl --disable-vhook --disable-ffplay --disable-ffserver --enable-a52 --enable-xvid --enable-faac --enable-faad --enable-amr_nb --enable-amr_wb --enable-pthreads --enable-x264 
libavutil version: 49.0.0
libavcodec version: 51.9.0
libavformat version: 50.4.0
built on Apr 15 2006 04:58:19, gcc: 4.0.1 (Apple Computer, Inc. build 5250)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'file.mov':
Duration: 00:01:32.0, start: 0.000000, bitrate: 63489 kb/s
Stream #0.0(eng): Audio: pcm_s16le, 48000 Hz, stereo, 1536 kb/s
Stream #0.1(eng), 29.97 fps(r): Video: Apple ProRes 422, 1280x720
Must supply at least one output file

Eu quero recuperar uma string com apenas Duration, taxa de quadros, codec e tamanho, por exemplo:

[00:01:32_29.97_Apple ProRes 422_1280x720]

Eu tentei começar com isso (de outra dica):

ffmpeg -i file.mov 2>&1 | sed -n 's/Duration: \(.*\), start//gp'

para obter a Duração, mas apenas "removeu" o Duration e , start , ou seja:

00:01:32.0: 0.000000, bitrate: 63489 kb/s

PS: também gostaria de remover o Apple de Apple ProRes 422 : -)

Obrigado!

Atualização: consegui extrair o codec com

sed -n "s/.*\Video: \(.*\),.*//p"

mas não sei como (a) obter o tamanho e a taxa de quadros e (b) combinar as pesquisas em uma linha ...

    
por Ze'ev 30.01.2012 / 00:03

4 respostas

3

awk : é como mágica, mas melhor.

#!/usr/bin/awk -f
/Duration/ {sub(/,/, "", $2); fields["dur"] = $2}
/fps/ { fields["fps"] = $3 }
/Video/ { 
        sub(/.*Video:/, "", $0);
        sub(/\W*Apple\W*/, "", $0);
        split($0, arr, ", ")
        fields["codec"] = arr[1]; 
        fields["res"] = arr[2]; 
}
END {
        printf "[%s_%s_%s_%s]\n", 
                fields["dur"], 
                fields["fps"], 
                fields["codec"],  
                fields["res"]
}
    
por 30.01.2012 / 02:27
1

Para extrair parte de uma linha no sed, combine a linha inteira e use backreferences para imprimir os bits que deseja manter. (Se o seu sed não tiver o operador \+ , use foo* em vez de fo\+ .)

$ … | sed -n -e 's/^.*Duration: *\([^,]*\).*$//p' \
             -e 's/^.* \([0-9.]\+\) fps(r).* Video: \([^,]\+\).*, *\([0-9]\+x[0-9]\+\).*$//'
00:01:32.0
29.97 Apple ProRes 422 1280x720

Observe que, quando há mais de uma maneira de decidir qual texto entra em qual grupo, os grupos anteriores terão o maior tempo possível. Por exemplo, no início da segunda expressão, ^.* \([0-9.]\+\) fps corresponde a um número após um espaço; se a expressão tivesse sido ^.*\([0-9.]\+\) fps , somente um dígito teria sido correspondido dentro do grupo, os dígitos anteriores teriam sido absorvidos pelo .* . Por outro lado, no final da segunda expressão, \([0-9]\+\).*$ coloca todos os dígitos dentro do grupo, e o .* só começa quando [0-9]\+ não pode corresponder por mais tempo, ou seja, após o primeiro não dígito.

Embora seja possível, sed não é bom em combinar várias linhas ou pós-processamento. Quando suas necessidades crescem além de substituições simples de texto, passe para awk .

    
por 30.01.2012 / 22:39
0

Você pode adicionar várias expressões no mesmo comando sed - se você adicionar algo para extrair "Apple" da linha de fluxo de vídeo, ele ainda imprimirá as duas correspondências, com a substituição.

O único problema é que ele será impresso em duas linhas diferentes, mas você sempre pode |xargs echo ou algo mais elegante.

    
por 30.01.2012 / 00:10
0

Você pode usar a opção sed with -e para combinar várias condições como esta:

sed -e <expression1> -e <expression2> ...
    
por 30.01.2012 / 02:17