2026년 9월 2일

모든 클립이 1프레임씩 짧게 도착했습니다

클립 마흔 개에 인/아웃을 표시하고 타임라인으로 보내면, 편집본은 멀쩡해 보입니다. 몇 주 뒤 길이를 확인하던 누군가가 그 전부가 표시했던 값보다 1프레임씩 짧다고 알려줍니다.

1프레임은 눈으로 보기엔 아무것도 아니지만 납품 스펙 앞에서는 전부입니다. 그리고 이건 그대로 출고되기 쉬운데, 사라지는 지점이 아무도 두 번은 읽지 않는 API 안의 단어 하나이기 때문입니다.

"아웃"의 의미는 두 가지입니다

아웃점을 표시할 때, 사용자가 뜻하는 건 둘 중 하나이고, 둘 다 합당합니다:

프레임 아홉 개로 이루어진 띠, 마지막 하나가 강조되어 있고, 그 위로 30fps에서 3.0초 인·8.0초 아웃으로 표시한 범위가 151인지 150인지 묻는 질문이 있습니다.
같은 표시 두 개를 두 가지 방식으로 센 것입니다. 의견이 갈리는 지점은 오직 하나 — 강조된 프레임이 범위 안에 있는가입니다.

둘 다 틀리지 않았습니다. 문제는 파이프라인의 한 부분은 한쪽을, 다음 부분은 다른 쪽을 전제할 때 시작됩니다. 차이가 정확히 1프레임이고, 1프레임은 눈에 보이지 않기 때문입니다.

그 프레임은 실제로 어디로 가는가

Resolve의 스크립팅 API는 클립을 타임라인에 붙일 때 시작 프레임과 끝 프레임을 받습니다. 끝 프레임은 제외(exclusive)입니다: 결과로 얻는 길이는 endFrame - startFrame입니다.

그러니 아웃점을 포함(inclusive)으로 — 표시하는 사람에게 인터페이스가 보여준 그대로 — 들고 있다가 그 숫자를 API에 그대로 넘기면, 모든 클립이 1프레임 짧게 도착합니다. 첫 번째 클립만이 아닙니다. 까다로운 클립만도 아닙니다. 전부가, 조용히, 영원히 그렇습니다.

고치는 건 한 줄입니다: outPoint + 1을 넘기면 됩니다. 어려운 건 그래야 한다는 걸 아는 쪽입니다.

여기 알아 둘 만한 두 번째 함정이 있습니다. 범위가 무너져서 끝 프레임이 시작 프레임과 같아지면, append 호출은 false를 반환하고 클립은 그냥 도착하지 않습니다. 길이가 0인 범위는 떠나기 전에 1프레임으로 고정(clamp)해 둬야 합니다.

테스트를 통과하고도 살아남는 이유

범위는 소재 관리 앱을 한 개의 문이 아니라 여러 문을 통해 빠져나가고, 그 문들은 서로 합의된 게 없습니다. 타임라인 API, EDL, 미디어 내보내기, ALE — 제가 다뤄 본 시스템들에서는 이게 서로 다른 네 번의 변환이고, 전부 같은 규칙을 따르지도 않습니다. EDL과 ALE는 둘 다 끝을 제외(exclusive)로 다룹니다. 길이를 out - in으로 계산하는 내보내기도 제외입니다. 실제로 표시하는 사람이 마주하는 인터페이스만 포함(inclusive)이었습니다.

변환할 기회가 네 번이라는 뜻이고, 그중 한 곳이 두 번 변환하거나 한 곳이 아예 변환하지 않기만 해도 프레임이 밀립니다. 이걸 버텨내게 해 주는 규칙은, 내부적으로는 규칙 하나만 유지하고 각 출구에서 딱 한 번만 변환하는 것입니다 — 중간에서는 절대 하지 않습니다.

자신의 값을 확인하는 방법

이건 눈짐작으로 되는 일이 아닙니다. 실제로 뭔가를 잘라 보고 나온 결과를 세어 봐야 합니다. 계산하기 쉬운 범위를 표시하고 — 30fps 소재에서 3.0초부터 8.0초까지 — 보낸 뒤, 타임라인의 길이를 읽으세요. 포함이면 151프레임, 제외면 150프레임이 나옵니다.

세기 전에 타임라인 프레임 레이트를 클립에 맞추세요. 이 부분 때문에 오후 반나절을 날렸습니다. 30fps 소재를 24fps 타임라인에 올리면 그 151프레임이 120프레임이 되어 버립니다 — 여분의 프레임이 다른 여러 프레임과 함께 반올림으로 사라지고, 검사는 조용히 검사이기를 멈춥니다. 인점은 표시한 자리에 그대로 있어서 아무것도 잘못된 것처럼 보이지 않습니다.

피하고 싶은 게 두 가지 더 있습니다. 초 단위로 계산하지 마세요: 원래 121프레임이어야 할 값이 5.041666…으로 나올 수 있고, 다시 프레임으로 변환할 때 120으로 잘려 나갑니다. 정수 프레임 단위로 작업하세요. 그리고 클립의 소스 끝 프레임을 반환하는 API 호출로 검증하지 마세요 — 제 테스트에서는 그 기준점이 같은 타임라인 위 항목들 사이에서도 일관되지 않아서, 단 1프레임을 두고 벌어지는 논쟁을 해결해 줄 수 없었습니다. 대신 오프셋과 길이를 읽으세요.

Divecut이 하는 일

Divecut은 아웃점을 포함(inclusive)으로 유지합니다. 표시하는 사람이 뜻하는 게 그거니까요. 그리고 각 출구에서 딱 한 번만 변환합니다. Resolve로 넘길 때는 endFrame = outPoint + 1이 되고, 무너진 범위도 도착하도록 최소 1프레임을 보장합니다.

코드를 믿는 대신 위에서 설명한 방식으로 직접 확인했습니다: 30fps 소재에서 3.0초부터 8.0초까지가 맞춰진 타임라인에서 151프레임으로 도착합니다. 이 측정값이 바로 이 글이 존재하는 이유입니다 — 소재를 자르기도 전에 두 경로를 나란히 읽다가 불일치를 발견했고, 그 개수가 수정이 맞았음을 확인해 줬습니다.

클립은 손대지 않은 Log 그대로 도착하고, 변환은 화면에 구워지는 대신 타임라인 정보로 적용됩니다. 그건 또 다른 글의 몫입니다.

Divecut은 macOS와 iPad용 푸티지 브라우저입니다. Log 클립을 촬영할 때 의도한 색으로 보여주고, 평범한 말로 검색하게 해 주며, 고른 클립을 Log 그대로 — 범위까지 포함해서 — DaVinci Resolve로 넘깁니다. 모든 기능 보기.