ffprobe からビデオおよびオーディオ コーデック情報を返すように jq フィルターを構造化するにはどうすればよいですか?

ffprobe からビデオおよびオーディオ コーデック情報を返すように jq フィルターを構造化するにはどうすればよいですか?

ビデオライブラリを標準化するために、変換する必要があるファイルのリストをすばやく作成する方法を探しています。これ質問とその回答 (および多くのグーグル検索) 基本的なことは理解できたと思いますが、jq セクションの詳細を説明するのに苦労しています。参考までに、私が最初に使用する jq コマンドは次のとおりです。

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

簡単にするために、これが jq に入力されているとします。

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

次のような出力が生成されます。

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

これは素晴らしいですが、もう一歩進んで、オーディオ ストリームに使用されるコーデックも含めたいと思います。同じ入力に対して、次のような出力が求められます。

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

これを実現するにはどうすればいいでしょうか?

答え1

オーディオとビデオの両方のコーデック タイプを選択し、h264ビデオを除外するには:

$ 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  

シェル コマンドが複雑になり、数行以上かかる場合は、複雑さを管理するために、より冗長な Python に切り替えます。

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は入力(data = json.loads(json_text))であり、resultは目的の出力(print(json.dumps(result)))です。

関数型のスタイルよりも、Python の命令型プログラミングに慣れている場合は、上記のコードを特定のケースに適応させることは比較的簡単ですjq

答え2

ここに別のアプローチがあります。

$ 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

出力

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

関連情報