¿Cómo puedo estructurar los filtros jq para devolver información del códec de audio y video de ffprobe?

¿Cómo puedo estructurar los filtros jq para devolver información del códec de audio y video de ffprobe?

Con el fin de estandarizar mi biblioteca de videos, estoy tratando de encontrar una manera de crear rápidamente una lista de archivos que deben convertirse. Después de mirarestepregunta y su respuesta (y mucho buscar en Google) Creo que he descubierto los conceptos básicos, pero tengo problemas para desarrollar la sección jq. Como referencia, el comando jq con el que estoy empezando es el siguiente:

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

y, en aras de la simplicidad, digamos que esto es lo que se envía a jq:

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

que produce el siguiente resultado:

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

Esto es genial, pero quiero ir un paso más allá: también me gustaría incluir el códec utilizado para cualquier transmisión de audio. Entonces, dada la misma entrada, me gustaría obtener el siguiente resultado:

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

¿Cómo logro esto?

Respuesta1

Para seleccionar tipos de códecs de audio y video y excluir h264video:

$ 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  

Si un comando de shell se vuelve complejo y ocupa más de unas pocas líneas; Cambio a Python más detallado para gestionar la complejidad:

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

dataes la entrada ( data = json.loads(json_text)) y resultes la salida deseada ( print(json.dumps(result))).

Debería ser relativamente sencillo adaptar el código anterior a su caso particular si está más familiarizado con una programación imperativa en Python que con un estilo más funcional en jq.

Respuesta2

Aquí hay otro enfoque.

$ 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

Producción

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

información relacionada