다시 인코딩하지 않고 ffmpeg에서 프레임 속도 변경

다시 인코딩하지 않고 ffmpeg에서 프레임 속도 변경

23.976fps(24000/1001)인 mkv(h264) 비디오가 있는데 재인코딩이나 품질 저하 없이 25fps로 변환하고 싶습니다. mkvmerge가 이를 수행할 수 있다는 것을 알고 있지만( --default-duration '0:25fps' 옵션 사용) 가능하면 ffmpeg에서 직접 수행하고 싶습니다. 문서에 따르면 이것이 작동해야 합니다.

ffmpeg -i input.mkv -r 25 -vcodec copy output.mkv

하지만 실행하면 동일한 비디오 fps만 얻습니다. ffmpeg에서 (존재하는 경우) 올바른 방법은 무엇입니까?

답변1

현재 버전의 FFmpeg를 사용하는 방법은 다음과 같습니다. 이는 첫 번째 파일 이후 입력의 PTS 크기를 다시 조정하지 않고 단순히 고정 오프셋을 적용하는 concat demuxer에 의존합니다. 15360(일반적인 FFmpeg 출력) 시간 척도를 갖는 30fps 스트림이 있다고 가정해 보겠습니다 . 이는 프레임 0에 PTS가 있고 0프레임 30에 PTS가 있음을 의미합니다 15360. 23040PTS 값에 영향을 주지 않고 시간 척도를 변경할 수 있다면 이는 45fps 스트림이 됩니다 .

본질적으로 이것이 아래 방법이 수행하는 작업입니다.

1. 소스 속성을 식별합니다.

Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1171 kb/s,
       30 fps, 30 tbr, 15360 tbn (default)

소스 속성, 특히 해상도와 tbn.


2a. (선택 사항) 시간 척도를 편리한 것으로 변경하여 계산을 더 간단하게 만듭니다.

ffmpeg -i in.mp4 -c copy -an -video_track_timescale 30 in-v30.mp4

이것이 우리를 사로잡는다

Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1171 kb/s, \
       30 fps, 30 tbr, 30 tbn (default

이 단계를 수행하면 새 시간 척도는 원래 프레임 속도와 같거나 정수배가 되어야 합니다.

2b. 필요한 시간 척도를 계산하여 대상 프레임 속도의 경우 소스에 있는 x프레임 #의 PTS가 새 값과 동일한 값을 가져야 합니다 . 2a 단계를 수행했다면 이는 매우 쉽고 단순히 새로운 프레임 속도일 뿐입니다. 따라서 대상 fps 의 경우 new 는 이어야 합니다 .xtbn45tbn45


. 더미 비디오를 생성합니다.

ffmpeg -f lavfi -i color=s=1280x720:r=45:d=1 -profile:v main -video_track_timescale 45 0.mp4

최상의 결과를 얻으려면 모든 속성이 해상도, H.264 프로필, 픽셀 형식, 참조 수 등과 동일해야 합니다.


4비디오를 연결하십시오.

먼저 텍스트 파일을 만들어주세요

file '0.mp4'
file 'in-v30.mp4'

그런 다음 연결

ffmpeg -f concat -i list.txt -c copy -video_track_timescale 45 45fps.mp4

출력 파일에는 두 번째 비디오가 45fps로 재생됩니다.

5. 이제 더미 프리롤을 잘라냅니다.

ffmpeg -ss 1.1 -i 45fps.mp4 -c copy -avoid_negative_ts make_zero in45.mp4

그리고 당신이 가진 것은

Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1757 kb/s, \
       45 fps, 45 tbr, 11520 tbn (default)

나는 이것이 복잡하다고 말했다!

답변2

ffmpeg -itsscale 1.0427083 -i input.mp4 -codec copy output.mp4

이는 Handbrake가 PAL DVD 소스에서 생성한 25fps mp4의 속도를 23.974fps로 올바르게 늦춥니다. 원래 쇼는 NTSC입니다. 오디오는 현재 47분의 실행 시간 동안 내내 동기화를 유지합니다. 디코딩/인코딩이 수행되지 않으므로 매우 빠릅니다. 다만, 전체적으로 약 3초 간격으로 오디오 결함(드롭아웃)이 발생합니다. vcodec비디오가 다시 인코딩되지 않는 동안 오디오가 원래 비트 전송률의 절반으로 다시 인코딩되고 여전히 드롭아웃 결함이 있다는 점을 제외하면 코덱을 대체한 것과 동일한 결과입니다 .

ffmpeg -itsscale 1.0427083 -i input.mp4 -vcodec copy -filter:a "atempo=0.959041" output.mp4

이렇게 하면 오디오 드롭아웃이 제거되지만 오디오가 다시 인코딩됩니다. 이는 비디오를 다시 인코딩하는 것보다 훨씬 빠릅니다. 나머지 단점은 기본적으로 원래 오디오 비트 전송률의 절반으로 설정된다는 것입니다. 재인코딩을 위한 오디오 비트 전송률을 설정하는 방법을 알아내야 합니다.

답변3

사용-itsscale입력 비디오에서 효과적인 프레임 속도 변경을 달성합니다. 에서는 잘 작동합니다 -vcodec copy.

답변4

비트스트림 필터를 사용하여 이를 수행할 수 있습니다 setts. 이는 또한 원시 스트림을 파일에 작성한 다음 다시 다중화하는 번거로움을 방지합니다. 이는 디코딩된 비디오 스트림에서 작동하기 때문에 코덱 복사( )와 함께 일반 필터를 사용할 수 없지만 -c:v copy인코딩된 스트림에서 작동하는 비트스트림 필터를 사용할 수 있기 때문에 작동합니다.

예를 들어 프레임 속도를 60fps로 변경하려면 다음을 삽입하세요.

-bsf:v setts=ts=STARTPTS+N/TB_OUT/60

스트림을 디코딩하지 않고 pts모두 설정해야 합니다 . dts가변 프레임 속도 비디오가 있는 경우 대신 이와 같은 것이 필요할 수 있습니다.

-bsf:v setts=ts='if(PREV_OUTPTS+9223372036854775808\,PREV_OUTPTS\,STARTPTS)+PREV_OUTDURATION*2'

이는 각 프레임의 지속 시간이 일정하다고 가정하는 대신 프레임의 지속 시간을 수정합니다. 이상해 보이는 표현식은 첫 번째 프레임 동안 가 (64비트 int의 최소값) 로 설정되어 있으므로 if첫 번째 프레임이 올바르게 오프셋되었는지 확인하기 위한 것이며 이를 0으로 바꿔야 합니다.PREV_OUTPTS-9223372036854775808

B-프레임이 있는 경우 dts보다 작아야 할 수 있으므로 디코딩이 엉망이 될 수 있지만 pts어쨌든 나에게는 잘 작동하는 것 같습니다. 문제가 발생하면 교체 setts=ts를 시도할 수 있습니다 . setts=pts보다https://ffmpeg.org/ffmpeg-bitstream-filters.html#setts자세한 내용은

관련 정보