소리꽃 KeyBloom TIL 32
KeyBloom에서 뽑은 영상이 편집툴에서 한 장 깨지는 걸 이틀에 걸쳐 쫓아 고쳤고, 그 수정을 새 건반과 함께 0.1.8로 냈다.
편집툴에서만 한 장이 깨졌다
파일을 열어 보니 멀쩡했다
추출한 영상을 편집툴에 올렸더니 한 장면이 이상했다. 건반이 통째로 사라지고 물결만 떠 있었다. 두 번 뽑아도 같은 자리였다.
먼저 우리가 그린 그림이 틀렸는지를 봤다. ffmpeg(영상을 읽고 변환하는 명령줄 도구)로 그 자리 앞뒤 프레임을 한 장씩 뽑아 보고, 영상 전체에서 앞뒤와 동떨어진 장면이 있는지도 훑었다. 전부 정상이었다.
앞선 TIL 30에서 느린 이유를 재서 갈랐던 것과 같은 결이다. 이상한 게 보이면 고칠 곳을 짐작하기 전에 “어느 단계까지는 멀쩡한가”를 먼저 확인한다. 파일이 멀쩡하면 그림을 그린 KeyBloom이 아니라 파일을 읽는 쪽을 봐야 한다.
편집툴이 말한 번호는 파일의 번호가 아니었다
편집툴 화면에는 371번 프레임이라고 나와 있었는데, 파일의 371번을 뽑아 보니 멀쩡했다. 편집툴 타임라인 앞쪽에 빈 구간을 두고 영상을 얹어 놔서 번호가 그만큼 밀려 보인 것이었다. 파일로는 239번이었다.
편집툴의 프레임 번호는 타임라인 기준이고 파일 안의 번호와 다를 수 있다. 문제 위치를 넘길 때는 편집툴 번호가 아니라 파일 기준 시각이나 번호로 넘겨야 같은 장면을 본다.
깨진 모양이 원인을 가리켰다
239번은 4초(240번) 바로 앞이다. 영상 압축은 몇 초마다 한 장을 통째로 저장하고(키프레임), 그 사이 프레임은 앞 장면과 달라진 부분만 저장한다. 이 앱은 4초마다 키프레임을 넣는다.
달라진 부분만 담긴 프레임을 기준 없이 풀면 가만히 있던 건반은 빠지고 움직인 물결만 남는다. 편집툴에서 본 모습이 정확히 그랬다. 그러니 그림이 틀린 게 아니라, 편집툴이 키프레임 경계에서 기준을 놓친 것이다.
깨진 모양은 그냥 “깨졌다”가 아니라 단서다. 무엇이 사라지고 무엇이 남았는지를 보면 어느 단계에서 틀렸는지가 드러난다.
한 가지씩만 바꾼 파일로 갈랐다
원인 후보가 여럿이었다. 그래서 딱 한 가지씩만 다른 파일을 만들어 편집툴에서 239번을 하나씩 확인했다.
- A 같은 데이터를 MP4로 다시 포장만 → 깨짐
- B 다른 인코더(영상을 압축하는 프로그램)로 다시 압축 → 정상
- C 멀쩡한 B를 앱과 같은 AMD 하드웨어 인코더로 다시 압축 → 깨짐
- D A의 데이터는 한 바이트도 안 바꾸고 파일 머리 정보만 통일 → 정상
- E AMD 인코더에 B프레임(앞뒤 프레임을 둘 다 참고하는 프레임)을 켬 → 정상
A와 B로 “앱의 인코더가 원인”까지 좁혔고, D 하나가 결정적이었다. 데이터는 그대로인데 머리 정보만 맞췄더니 멀쩡해졌다.
D에서 맞춘 「머리 정보」가 SPS다. SPS(Sequence Parameter Set)는 H.264(지금 가장 널리 쓰이는 영상 압축 방식) 영상 전체에 걸리는 설정 묶음으로, 디코더(압축된 영상을 풀어 그림으로 되돌리는 쪽)가 첫 프레임을 풀기 전에 알아야 하는 값이 들어 있다. 해상도, 프로필(어떤 압축 기법까지 썼는지의 등급), 참고할 수 있는 이전 프레임 개수, 초당 몇 장인지 같은 것들이다. 이게 없으면 프레임 데이터를 받아도 어떻게 풀지 모른다.
SPS는 보통 두 군데에 들어간다. 하나는 MP4 파일 맨 앞 머리 부분이다. 편집툴이나 플레이어는 파일을 열자마자 여기를 읽고 디코더를 준비한다. 다른 하나는 영상 데이터 안, 키프레임 앞이다. 방송처럼 중간부터 받아 보는 경우에도 풀 수 있게 스트림 안에 한 번 더 넣는 것이다. 원래 둘은 같은 내용이어야 한다.
AMD 인코더가 만든 파일은 둘이 달랐다. 영상 안 SPS에는 초당 프레임 수 정보가 있는데, 파일 머리 SPS에는 그게 빠져 있었다. 게다가 머리 쪽은 규격 검사 도구가 값이 맞지 않는다고 걸 정도로 어긋나 있었다. 편집툴은 파일 머리의 설정으로 디코더를 준비했다가 영상 안에서 다른 설정을 만나고, 그 사이 어딘가에서 앞 프레임을 기준으로 잡지 못한다. 편집툴 내부라 정확히 어떤 순서로 꼬이는지는 밖에서 알 수 없다. 다만 머리만 영상 안 SPS와 똑같이 맞춘 D가 멀쩡했으니, 두 SPS가 다르다는 것이 원인이다.
여러 개를 한꺼번에 바꾼 파일은 고쳐져도 무엇 때문인지 모른다. 편집툴처럼 내가 직접 열어 봐야 하는 확인일수록 파일 하나에 바뀐 것 하나만 두는 게 확인 횟수를 줄인다.
둘 다 통했는데 하나만 골랐다
D(머리 정보 정리)와 E(B프레임 켜기)가 둘 다 멀쩡했다. D를 골랐다.
E는 이 PC의 AMD 칩에서는 됐지만, B프레임 지원이 칩마다 달라 다른 사람 PC에서는 실패할 수 있다. D는 어떤 인코더가 만든 파일이든 머리만 정리하니 기기를 가리지 않는다. 화질도 그대로고 추출 끝에 몇 초가 더 걸릴 뿐이다.
내 PC에서 통한 방법이 사용자 PC에서도 통한다는 보장은 없다. 해결책이 여럿이면 “어디서나 같은 결과가 나오는 쪽”을 먼저 본다.
0.1.8을 내며
미뤘던 건반이 같이 나갈 이유가 생겼다
건반에 입체감을 넣은 건 열흘 전인데 출시는 미뤘었다. 건반 모양 하나로 업데이트 알림을 띄우기엔 값어치가 약하다고 봤기 때문이다.
이번 수정이 붙으면서 사정이 달라졌다. 영상 편집툴에서 깨지는 건 KeyBloom으로 영상을 만드는 사람에게 직접 걸리는 문제고, KeyBloom을 사는 사람이 바로 그들이다. 그래서 둘을 묶어 0.1.8로 냈다.
혼자서는 약한 변경도 버리지 않고 기다리게 두면, 사용자에게 필요한 수정이 생겼을 때 같이 태워 보낼 수 있다. 업데이트 한 번의 값어치는 묶음으로 따진다.
고친 것을 너무 자세히 적었다
릴리스 노트 초안의 「고친 것」에는 “앱에서 내보낸 MP4를 일부 편집 프로그램에서 열면 4초 부근의 한 프레임이 깨져 보이던 문제”라고 적혀 있었다. 너무 디테일하다고 했다. “앱에서 내보낸 영상이 일부 편집 프로그램에서 깨져 보이던 문제”로 줄였다.
사용자가 알아야 하는 건 “내가 겪던 그 문제가 고쳐졌나”다. MP4, 4초, 한 프레임은 원인을 쫓은 사람에게나 의미 있는 말이다. 사용자용 노트에는 증상을 사용자가 부르는 말로 한 줄만 쓰고, 원인과 과정은 프로젝트 기록에 남긴다.
사본은 원본을 따라오지 않았다
출시하고 나서 로그스톤 샵이 짚었다. 제품 페이지에서 움직이는 데모 그림의 건반이 옛날 사각형 모양이라는 것이다. 그 데모는 앱 화면을 가져다 쓰는 게 아니라 앱의 그리기 코드를 샵이 옮겨 둔 사본이라, 앱을 바꿔도 따라가지 않는다.
같은 일이 파동 모션을 넣을 때도 있었다(앞선 TIL 31의 「말로 넘긴 사양」 — 샵이 데모를 자기 렌더러로 따로 그린다는 걸 그때 알았다). 그때 “모션을 바꾸면 데모 값도 같이 보낸다”고 정했는데, 규칙을 모션에만 걸어 두는 바람에 건반을 바꾼 이번엔 빠졌다.
사본이 있다는 걸 알면서도 빠뜨리는 건, 규칙을 그때 사건의 모양대로 좁게 적었기 때문이다. 그래서 규칙을 넓혔다. 화면에 그려지는 것(건반이든 파티클이든)을 바꾼 릴리스는 체크리스트에 “샵 데모 코드 전달”까지 넣는다.
요약
- 이상한 게 보이면 “어느 단계까지는 멀쩡한가”부터 확인한다. 파일이 멀쩡하면 만든 쪽이 아니라 읽는 쪽을 본다
- 편집툴의 프레임 번호는 타임라인 기준이라 파일 번호와 다를 수 있다. 위치는 파일 기준으로 넘긴다
- 깨진 모양은 단서다. 무엇이 사라지고 무엇이 남았는지가 어느 단계에서 틀렸는지를 말해 준다
- 비교 파일에는 바뀐 것을 하나만 둔다. 여러 개를 한꺼번에 바꾸면 고쳐져도 이유를 모른다
- 해결책이 여럿이면 내 PC가 아니라 어디서나 같은 결과가 나오는 쪽을 고른다
- 혼자서는 약한 변경도 기다리게 두면 필요한 수정과 함께 보낼 수 있다. 업데이트의 값어치는 묶음으로 따진다
- 사용자용 노트에는 증상만 사용자가 부르는 말로 쓰고, 원인은 프로젝트 기록에 둔다
- 사본은 원본을 따라오지 않는다. 사본 규칙을 사건 모양대로 좁게 적으면 다음 사건에서 또 빠진다