Como posso estruturar filtros jq para retornar informações de codec de áudio e vídeo do ffprobe?

3

No interesse de padronizar minha biblioteca de vídeos, estou tentando encontrar uma maneira de criar rapidamente uma lista de arquivos que precisam ser convertidos. Depois de olhar para this pergunta e sua resposta (e muito googling) Eu acho que tenho o básico descoberto, mas estou tendo problemas para elaborar na seção jq. Para referência, o comando jq que estou começando é o seguinte:

jq -c '.format.filename as $path | 
    .streams[]? | 
    select(.codec_type=="video" and .codec_name!="h264") | 
    .codec_name as $vcodec | 
    {video: $vcodec, path: $path}'

e, para simplificar, digamos que isso é o que está sendo alimentado para jq:

{
    "streams": [
        {
            "index": 0,
            "codec_name": "hevc",
            "codec_type": "video"
        },
        {
            "index": 1,
            "codec_name": "aac",
            "codec_type": "audio"
        }
    ],
    "format": {
        "filename": "Video.mkv"
    }
}

, que produz a seguinte saída:

{"video":"hevc","path":"./Video.mkv"}

Isso é ótimo, mas eu quero ir um passo além - eu também gostaria de incluir o codec usado para qualquer fluxo de áudio. Então, dada a mesma entrada, eu gostaria da seguinte saída:

{"video":"hevc","audio":"aac","path":"./Video.mkv"}

Como faço isso?

    
por Ziggy114 04.07.2017 / 10:14

2 respostas

2

Para selecionar os tipos de codecs de áudio e vídeo e excluir h264 video:

$ jq '.format.filename as $path |
    [.streams[]? | select(.codec_type=="audio" 
                          or (.codec_type=="video" 
                              and .codec_name!="h264")) | 
     {(.codec_type): .codec_name, $path}] | 
    group_by(.path) | map(add) | .[]' input.json
$ jq --version      
jq-1.5-1-a5b5cbe  

Se um comando shell se tornar complexo e precisar de mais do que algumas linhas; Eu mudo para o Python mais detalhado para gerenciar a complexidade:

result = dict(path=data['format']['filename'])
for stream in data['streams']:
    if (stream['codec_type'] == 'audio'
        or (stream['codec_type'] == 'video'
            and stream['codec_name'] != 'h264')):
        result[stream['codec_type']] = stream['codec_name'] # last value wins

data é a entrada ( data = json.loads(json_text) ) e result é a saída desejada ( print(json.dumps(result)) ).

Deve ser relativamente simples adaptar o código acima para o seu caso particular se você estiver mais familiarizado com uma programação imperativa em Python do que com um estilo mais funcional em jq .

    
por jfs 04.07.2017 / 17:30
1

Aqui está outra abordagem.

$ jq -M '
  def getpath: {path: .format.filename} ;
  def getcodecs: [
        .streams[]?
      | {(.codec_type):.codec_name}
      | if . == {"video":"h264"} then empty else . end
    ] | add
  ;
  getpath + getcodecs
  ' input.json

Saída

{
  "path": "Video.mkv",
  "video": "hevc",
  "audio": "aac"
}
    
por jq170727 17.09.2017 / 08:02