FFmpeg를 사용하여 지정된 타임 스탬프 전에 가장 가까운 키 프레임의 타임 스탬프를 얻는 방법은 무엇입니까?


18

나는 빠르고 정확한 FFmpeg seeking 명령을 원합니다. 나는 이것을 발견 했다 .

해결책은 -ss입력 (빠른 탐색)과 출력 (정확한 탐색)을 모두 적용하는 것 입니다. 그러나 : 입력 탐색이 정확하지 않으면 탐색 위치가 정확한지 어떻게 확인할 수 있습니까?


예를 들어 00:03:00을 찾으려면 명령은 다음과 같습니다.

ffmpeg -ss 00:02:30 -i <INPUT> ... -ss 00:00:30 <OUTPUT>

첫 번째 -ss다른 곳으로 노력할 것,하지 00:02:3000:02:31. 그리고 추구 초를 적용한 후, 최종 결과는 것 00:03:01- 하지 우리가 원하는 것을. 그 맞습니까?

첫 번째는 어디를 -ss찾는가? 가장 가까운 키 프레임을 찾고 00:02:30있습니까?

그렇다면, 여기에 제 생각이 있습니다. 내가 틀렸다면 바로 잡으십시오. 첫 번째 탐색 후 결과의 타임 스탬프 (이 예에서는)를 얻은 00:02:31다음 적절한 시간에 두 번째 탐색을 적용합니다 (이 경우) 00:00:29.

질문 : 첫 탐색 결과의 타임 스탬프는 어떻게 얻습니까?

답변:


18

제목의 질문에 문자 그대로 대답하려면 다음을 사용하여 I- 프레임 목록을 얻을 수 있습니다.

ffprobe -select_streams v -show_frames <INPUT> 

를 추가하여이를 필요한 출력으로 제한 할 수 있습니다 -show_entries frame=pkt_pts_time,pict_type.

특정 타임 스탬프에 가장 가까운 (다음에 오는) 프레임을 보려면 먼저 키 프레임의 모든 타임 스탬프를 찾아야합니다 (예 :) awk.

먼저 찾고자하는 시간을 정의하십시오 (예 : 150 초에 해당하는 2 : 30m).

ffprobe -select_streams v -show_frames -show_entries frame=pkt_pts_time,pict_type -v quiet in.mp4 | 
awk -F= ' 
  /pict_type=/ { if (index($2, "I")) { i=1; } else { i=0; } } 
  /pkt_pts_time/ { if (i && ($2 >= 150)) print $2; }  
' | head -n 1

예를 들어,이 반환 150.400000됩니다.


-ssbefore 를 사용할 때 -iFFmpeg는 탐색 지점 이전 의 키 프레임을 찾은 다음 탐색 지점에 도달 할 때까지 모든 다음 프레임에 음의 PTS 값을 할당합니다. 플레이어는 PTS가 음수 인 프레임을 디코딩하지만 표시하지 않아야하며 비디오가 정확하게 시작되어야합니다.

일부 플레이어는이를 제대로 존중하지 않고 검은 색 비디오 또는 쓰레기를 표시합니다. 이 경우, 위 스크립트는 탐색 지점 이후 에 키 프레임의 PTS를 찾고이를 사용하여 키 프레임에서 탐색을 시작할 수 있습니다. 그러나 이것은 정확하지 않습니다.

추구하는 동안 매우 정확하고 많은 플레이어와의 호환성을 유지하려면 비디오를 무손실 인트라 전용 형식으로 변환하여 언제라도 잘라낸 다음 다시 인코딩해야합니다. 그러나 이것은 빠르지 않을 것입니다.


1
고마워, 나는 비디오 편집기를 만들고 있지 않지만 0.5 초 미만의 간격을 유지 해야하는 정확한 비디오 검색을 원합니다.
jackode

1
에서 PTS로 저글링 할 수 있습니다 ffprobe. 그렇지 않은 경우 시각적 손실이없고 프레임 내 전용 인 ProRes 422, DNxHD와 같은 중간 형식이 사용됩니다. 또는 HuffYUV와 같은 것을 사용하십시오. 그러나 물론 "빠른"측면을 다시 잃게됩니다.
slhck

어떤 버전 ffprobe의 것은 내 말 때문에, 명령에 사용했던Unrecognized option 'select_streams'
jackode

2
가까이에 select_streams옵션이 2012 년 10 월추가되었습니다 . :) 당신은 그것없이 할 수 있지만 오디오 프레임에 대한 정보를 얻을 수 있습니다.
slhck

2
이 ffmpeg 행을 추가하여 awk에 의해 버려지는 많은 것들 대신 필요한 2 개의 필드 만 출력하도록 할 수 있습니다. -show_entries frame = pkt_pts_time, pict_type
Jannes

7

이 질문은 몇 년 전이지만, 최신 버전의 ffprobe는 프레임건너 뛸 수 있습니다. -skip_frame nokey키 프레임 (I- 프레임)에서만 정보를보고하도록 전달할 수 있습니다 . 이렇게하면 많은 시간을 절약 할 수 있습니다! 2GB 1080p MP4 파일에서는 건너 뛰기 프레임없이 4 분이 걸렸습니다. 건너 뛰기 매개 변수를 추가하면 20 초 밖에 걸리지 않습니다.

명령:

ffprobe -select_streams v -skip_frame nokey -show_frames -show_entries frame = pkt_pts_time, pict_type D : \ test.mp4

결과 :

[FRAME]
pkt_pts_time=0.000000
pict_type=I
[/FRAME]
[FRAME]
pkt_pts_time=3.753750
pict_type=I
[/FRAME]
[FRAME]
pkt_pts_time=7.507500
pict_type=I
[/FRAME]
[FRAME]
pkt_pts_time=11.261250
pict_type=I
[/FRAME]
[FRAME]
pkt_pts_time=15.015000
pict_type=I
[/FRAME]

따라서 결과에는 키 프레임에 관한 정보 만 포함됩니다.


1

slhck의 답변바탕 으로 bash 함수가 있습니다.이 함수는 N초 전에 발생하는 가장 가까운 키 프레임을 반환합니다 .

또한 -read_intervalsffprobe가 25 초 전에 키 프레임 검색 만 시작하도록하기 위해 사용 합니다 N. 타임 스탬프가 발견되면이 트릭과 awk가 종료되면 속도가 크게 빨라집니다.

function ffnearest() {
  STIME=$2; export STIME;
  ffprobe -read_intervals $[$STIME-25]% -select_streams v -show_frames -show_entries frame=pkt_pts_time,pict_type -v quiet "$1" |
  awk -F= '
    /pict_type=/ { if (index($2, "I")) { i=1; } else { i=0; } }
    /pkt_pts_time/ { if (i && ($2 <= ENVIRON["STIME"])) print $2; }
    /pkt_pts_time/ { if (i && ($2 > ENVIRON["STIME"])) exit 0; }
  ' | tail -n 1
}

사용법 예 :

➜ ffnearest input.mkv 30
23.941000

비디오 파일을 다시 인코딩하지 않고 다듬을 때 사용합니다. 다시 인코딩하지 않고 새 키 프레임을 추가 할 수 없으므로 ffnearest잘라 내기 전에 키 프레임을 찾는 데 사용 합니다. 예를 들면 다음과 같습니다.

ffmpeg  -i input.mkv -ss 00:00:$(echo "$(ffnearest input.mkv 30) - 0.5" | bc)  -c copy -y output.mkv;

이 예의 -ss경우 처음 60 초보다 더 멀리 탐색하려는 경우 매개 변수에 전달 된 형식을 변경해야 할 수도 있습니다 .

(성가 시게,는 FFmpeg을 말하고 키 프레임의 타임 스탬프는 FFmpeg 출력에서 해당 키 프레임을 제외 할 것으로 보인다 정확히에에 추구하지만, 키 프레임의 실제 타임 스탬프에서 0.5 초를 뺀 것은 트릭을 수행합니다. 당신이 사용할 필요가 떠들썩한 파티를 위해 bc소수와 식을 평가하기 위해 하지만 zsh에서는 -ss 00:00:$[$(ffnearest input.mkv 28)-0.5]작동합니다.)


이것은 프레임 후 다음 프레임 시간을 제공합니다.
Ehsan Chavoshi

0

I 프레임의 정보를 얻으려면 다음을 사용할 수 있습니다

ffprobe -i input.mp4 -v quiet -select_streams v -show_entries frame=pkt_pts_time,pict_type|grep -B 1 'pict_type=I'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.