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)))입니다.

NET의 보다 기능적인 스타일보다 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"
}

관련 정보