x264

psycho 2011. 6. 21. 23:15

 이전까지의 MPEG 시리즈와는 다르게, MPEG-4 Part 10(H.264)에는 lossless mode라는 것이 존재한다.

이는 "정보의 용량에 상관없이 손실을 없앤다"는 것으로, "낮은 대역폭에서 화질 개선"이라는 본연의 목표(?)와는 반대되는 것이다.

실제로 "High 4:4:4 Predictive Profile"이라는 거창한(?) 이름으로 정의되어 있으며, 공개 소프트웨어로 널리 사용되고 있는 x264에서 이를 지원하고 있다(필자는 x264 이외의 다른 것을 써본 적이 없기 때문에 다른 인코더에 대해서는 알지 못한다).


 필자는 실험을 좋아한다. 경험하기 이전에 알 수 있는 일은 경험을 해야만 알 수 있는 일에 비해 "없다"라고 표현해도 좋을 정도로 적기 때문이다. 내가 원하는 대로 조건을 바꿔가며 결과를 관측하고 해석하는 일련의 과정인 "실험". 그런 이름을 가진 "경험"을 통해 무언가를 알아가는 기쁨(...?).


 잠시 주제와 엇나가는 이야기를 했다고 생각한다면, 글쎄, 어떻게 하면 좋을까... 물론 대학수학능력시험 문제에서 '위 글에서 주제와 상관없는 문장은?' 따위의 문제가 나온다면 반드시 정답이 될 법하긴 하지만, 필자는 "전혀 상관없는 문장"이라고는 생각하지 않는다. 그 이유는 그 "실험" 도중에 보았던 현상에 대해서 나열할 것이기 때문이며, 애초에 왜 그런 "실험"을 하게 되었는지에 대해 어떤 이야기도 없다면 부자연스럽다고 생각하기 때문이다. 비록 이번에 쓸 것은 우연히 발견하게 되었다고는 하지만...


 혹시 AVISynth라는 프로그램에 대해서 아는가? 적어도 영상처리나 인코딩에 관심이 있다면 "전혀 모르지는(들어본 적도 없다...라든가) 않을 것이다"라고 생각하지만, 그래도 혹시 모르는 사람을 위해서 간단하게 말해두자면, "영상 후처리용 프로그램" 정도가 되겠다. 특징이라든가 사용법이라든가...하는 것들은 이미 다른 사람들이 쉽게 설명해놓은 것들도 있고 하므로 미안하지만 다른 곳에서 찾아보기 바란다. 본 글을 이해하기 위한 최소한의 지식을 이야기한다면, 이것은 영상을 불러오는 것부터 시작해서 해야 하는 작업들을 일종의 프로그래밍 언어의 형식으로 서술하여 사용한다. 텍스트 파일의 형태로 저장되지만, 영상을 다루는 프로그램에서는 (특별히 AVISynth를 지원하거나 동영상을 취급하는 형태로 파일에 접근하는 경우) 지시된 대로 처리된 영상을 불러올 수 있다.


 어찌되었건, 처음에 필자가 행했던 실험의 과정은 다음과 같다.


실험 1 :


1. AVISynth를 사용하여 모든 처리를 끝낸 영상을 x264의 lossless option을 사용하여 인코딩한다.

   (단, Multi-thread는 사용하지 않는다)

2. 과정 1에서 출력된 결과물을 그대로 돌려주도록 다른 AVISynth 스크립트를 작성한다.

   (영상을 불러오는 이외의 어떤 처리도 하지 않는다 - 엄밀히 말하면, DirectShowSource의 버그인지 Haali Media Splitter의

   버그인지 ffmpeg의 버그인지는 모르겠지만 정확하게 같아지기 위해서는 마지막 한 프레임을 잘라내야 한다.)

3. 과정 2의 스크립트를 사용하여 한 번 더 x264를 이용하여 lossless 인코딩을 한다.

   (입력 파일 지정 이외의 다른 옵션은 과정 1과 동일하게 한다)

4. 괴정 1의 결과물과 과정 3의 결과물을 파일 비교 프로그램으로 비교한다.


 이 때, 과정 4에서 관찰할 수 있는 결과는 당연히 "같아야 한다"일 것이다. 컴퓨터의 특징 중 하나에 "정확성"이라는 것이 있는데, 이는 "같은 입력이 주어질 경우 정확히 같은 결과를 산출한다"쯤으로 해석할 수 있다. 같은 알고리즘을 가지고 같은 입력값을 주었을 때 서로 다른 출력값이 나온다면, 그것은 연산장치에 뭔가 문제가 있다고밖에는 생각할 수 없다.1


 이쯤 이야기했으면 왜 이런 이야기를 했는지 짐작할 수 있을 것이다. 과정 1과 3에서의 출력물이 서로 달랐다는 것이다. 참고로 필자는 본 실험에서 mkv 컨테이너 포맷을 사용했으며, 이 녀석은 생성시의 Timestamp를 파일 내에 저장하기 때문에 특별히 조작하지 않는 한 두 파일이 완전히 같을 수는 없다. 문제는 달라서는 안 되는 "영상 데이터 부분"이 달랐다는 것에 있다. 그것도 한두 군데도 아닌 아주 많은 부분에서 말이다.

(※실험정신이 강한 독자들을 위한 주 : 실험 1의 경우, 영상에 따라 두 결과물이 같을 수도 있다. 충분한 크기를 가진 다양한 영상으로 실험을 해보기 바란다)


 일반적으로 압축 알고리즘에서, 압축된 데이터의 오류는 설령 그것이 단 1비트의 오차일지라도 엄청난 파괴력을 갖게 된다. 오류가 발생한 부분의 데이터에만 영향을 미치면 양호한 축에 속한다. 최악의 경우, 이는 오류가 발생한 부분 이후에 해석되는 모든 데이터에 영향을 미치게 된다. 물론 앞에서도 말한 특징에 의하여 여기서 해독된 데이터가 원래의 데이터와 같을 가능성은 없다.






 이 사실들이 말하는 바가 무엇인지는 다들 알 것이라 믿는다. 필자는 이런 머리아픈 글을 여기까지 읽고 있는 사람들의 사고능력을 의심하고 싶지 않다. 하지만, 필자는 아래에서 현재 독자가 하고 있는 생각을 뿌리부터 뒤집어엎을 것이다.






 여기서 "과학적 실험"에 대한 개념이 있는 사람이라면 다음과 같은 의문이 들 것이다.

 "스크립트 파일이 달라서 출력 결과물이 다른 것은 아닐까?"

 좋은 질문이다. 물론 필자도 똑같은 생각을 했으므로 실험을 해봤다. 과정은 다음과 같다.


실험 2 :


1. 실험 1의 과정 1에서 사용한 AVISynth 스크립트를 VirtualDub으로 연 다음, Direct stream copy 모드를 사용하여 AVI 파일로 저장한다(이렇게 하면 압축되지 않은 상태로 저장되게 된다).

2. 실험 1의 과정 3에서 사용한 AVISynth 스크립트를 VirtualDub으로 연 다음, 마찬가지 방법을 사용하여 AVI 파일로 저장한다.

3. 과정 1의 결과물과 과정 2의 결과물을 파일 비교 프로그램으로 비교한다.


 놀라운 것은, 이 실험의 결과가 "두 파일이 정확히 일치한다"는 것이었다. 이로써 적어도 "스크립트 자체가 달라서 결과가 달라진 것이다"라는 가설을 부정할 수 있는 충분한 근거를 확보하였다. 그렇지만, 중요한 의문은 아직 풀리지 않았다. 어찌된 일인지 x264 인코더는 똑같은 입력에 대해 서로 다른 출력을 내놓았다. 그리고, 이 실험에서 영상 코덱으로 사용한 ffmpeg는 서로 다른 입력에 대해 동일한 결과를 출력한 꼴이 되었다(물론 이런 특성은 앞의 x264의 경우와는 달리 불가능한 것은 아니다. 이런 특성을 갖는 대표적인 것으로 Hash function이 있다. - Hash function을 맹신하는 독자들을 위해 사족을 붙이자면, 충돌 현상은 최소화할 수 있을 뿐 없애는 것은 이론적으로 불가능하다. 만약 그것이 가능하다면, 그 알고리즘은 Hash function이 아닌 신개념 압축 알고리즘으로 우리들에게 알려져 있을 것이다 - 하지만, 이 경우는 비록 원래 입력과 출력이 다른 손실 압축용이라고는 하나 압축 알고리즘이라는 것을 기억하자).



 이쪽 방면으로 깊이 공부해본 적도 없고 그럴 능력도 안 되는 필자로서는 도저히 이해가 안 되는 현상이다. 필자가 앞서 제기한 대로 연산장치에 문제가 있는 것일까? 혹시 이 글에서 뭔가 논리적으로 잘못된 점이라든가 기타 이런 현상이 발생한 원인을 아는 사람이 있다면 제보 바란다.




(※사족 - 다른 말로 추가내용)

 위 실험과 같은 변환과정을 반복하면 그 결과물은 어떤 것과 같을까? 실험을 해본 결과, 3회 이상 반복시 결과물은 2회째의 결과물과 같았다.


각주 1

여기서 프로그래밍을 해본 사람이라면 "그러면 난수 발생 함수는 어떻게 된 것이냐"라고 반문할 수도 있겠지만, 소프트웨어적으로 구현된 난수 발생기는 엄밀하게 말하면 "의사(pseudo) 난수 발생기"이며, "의사(擬似)"라는 단어의 뜻 그대로 "난수"와 비슷할 뿐 진정한 "난수"는 아니다. 이런 난수 발생기는 seed라고 불리는 일종의 초기값을 받으며, 같은..

  1. 여기서 프로그래밍을 해본 사람이라면 "그러면 난수 발생 함수는 어떻게 된 것이냐"라고 반문할 수도 있겠지만, 소프트웨어적으로 구현된 난수 발생기는 엄밀하게 말하면 "의사(pseudo) 난수 발생기"이며, "의사(擬似)"라는 단어의 뜻 그대로 "난수"와 비슷할 뿐 진정한 "난수"는 아니다. 이런 난수 발생기는 seed라고 불리는 일종의 초기값을 받으며, 같은 초기값에 대해서 언제나 정확히 같은 수열을 반환한다. 보통은 seed값으로 같은 값이 될 수 없는 "현재 시각"을 제공하여 이런 문제를 피하고 있다. [본문으로]