명품몰 상품 영상 변환 결과가 이상한데 어느 단계에서 그렇게 됐는지 알 수 없었다. 처리가 ffmpeg 명령 하나로 되어 있어서 안이 한 덩어리로 보였다.
Table of contents
Open Table of contents
증상 — 한 덩어리로 보이던 처리
명령 하나에 -vf scale 크기 변환과 -r 프레임 조정과 -c:v libx264 영상 인코딩과 -c:a aac 음성 인코딩이 전부 들어 있었다. 결과가 이상해도 어느 부분 때문인지 가를 근거가 없었다.
그래서 먼저 그 명령이 무엇들로 이루어져 있는지를 여섯 단계로 나눠 적었다. 전부 따로 실행한 것은 아니고 무엇이 무엇인지를 알아 두는 것이 목적이었다.
측정 — 입력과 출력을 재서 본 차이
각 단계의 결과를 재는 방법을 붙였는데 ffprobe 로 입력과 출력의 width 와 nb_frames 와 duration 을 뽑아 비교했다. 길이가 같고 해상도가 바뀐 것은 기대대로였다.
그런데 출력의 nb_frames 가 예상보다 둘 적었다. 한 번은 미세하지만 반복되면 누적되는 종류의 차이였다.
조치 — 단계를 나눠 돌린 뒤
두 가지 방법이 있었다. 명령 하나를 그대로 두고 옵션을 바꿔 가며 결과만 비교하는 것과, 크기만 바꾸고 프레임만 바꾸는 식으로 단계를 갈라 중간 결과를 남기는 것이다. 뒤쪽을 골랐다. 이유는 옵션을 바꿔 결과만 보면 어느 옵션이 움직였는지 여전히 안 갈려서다. 대신 중간 파일로 디스크가 몇 배 드는 것을 감수했다. -r 프레임 조정 단계에서 빠진다는 것이 그렇게 드러났다.
입력이 정확한 정수 프레임률이 아니라 29.97 처럼 소수점이 붙은 r_frame_rate 였다. 30 으로 맞추는 과정에서 프레임이 딱 떨어지지 않고 있었다.
원인 — 입력이 한 가지가 아니었다
표본 폴더의 파일들을 r_frame_rate 와 해상도로 묶어 세어 보니 네 종류가 섞여 있었다. 나는 그중 한 가지만 보고 처리를 만든 상태였다.
각각 시험해 보니 셋에서 문제가 나왔다. 입력이 한 가지인 줄 알고 만들면 다른 입력이 들어올 때 깨지고 그 깨짐은 특정 파일에서만 나므로 원인을 찾기 어렵다.
확인 목록과 실패 보관
처리 뒤에 볼 것을 목록으로 뒀는데 duration 과 nb_frames 와 음성 스트림 존재와 음성 영상 길이 일치와 재생 가능 여부였다. 마지막이 중요했는데 파일이 만들어져도 재생이 안 되는 경우가 있었다.
실패한 입력은 stderr 로그와 ffprobe 정보를 함께 남겼다. 로그만 남기면 그 입력을 다시 만들 수 없어서 같은 조건으로 재현할 수 없기 때문이다.
단계별 처리 시간도 재서 libx264 인코딩이 대부분을 차지한다는 것을 확인했다. -preset 몇 가지를 놓고 시간과 파일 크기를 나란히 재니 저장 비용과 처리 시간 사이에서 고르는 판단이 빨라졌다.
정리
- 여러 단계를 거치는 처리는 어느 단계인지부터 갈라야 한다
ffmpeg한 명령에 뭉쳐 있어도 무엇이 무엇인지를 알아 둔다ffprobe로 입력과 출력을 재서 비교하면 미세한 차이가 드러난다- 문제를 좁힐 때는 단계를 나눠 돌리고 중간 결과를 남긴다
- 입력이 여러 종류인지
r_frame_rate로 확인한다 - 하나만 보고 만들면 다른 입력에서 깨진다
- 파일이 만들어져도 재생이 안 될 수 있으므로 확인 목록을 둔다
- 실패한 입력과 로그를 같이 남겨야 재현할 수 있다