x264

psycho 2011. 6. 27. 16:26

 x264는 자체적으로 Avisynth 입력을 지원한다. 이것은 확실히 매우 편리한 기능이지만, 가끔 문제가 될 때도 있다.


 DVD 소스 정도까지만 취급한다면 잘 발생하지 않는 일이지만, 블루레이 소스라든가 HDTV 소스 같은 경우에는 신들린 듯(?) 필터질을 하다 보면 Avisynth 자체가 상당한 메모리를 잡아먹게 된다. 문제는, 32비트 운영체제에서 기본적으로 프로세스 하나가 사용할 수 있는 최대 메모리 공간이 2GB밖에 되지 않는다는 것이다(물론 운영체제 커널과 응용프로그램이 모두 지원한다는 전제하에 3GB까지 사용할 수 있기는 하다. 다만, 이렇게 하려면 프로그램 컴파일 시에 특수한 옵션을 주어야 하고, 부팅시에도 특수 옵션을 주거나 하여야 한다).

 64비트 운영체제 하에서 64비트 Avisynth와 64비트 필터들, 64비트 x264를 사용한다면 메모리 관련 문제는 발생하지 않겠지만, 이 또한 문제는 공식적인 64비트 Avisynth가 만들어지지 않았다는 점이며, 이것은 필터들 또한 마찬가지다(참고 : 32비트 Avisynth 설치 프로그램을 이용하여 64비트 Avisynth를 설치하는 방법은 이미 존재하며, 64비트로 포팅된 필터도 꽤 많긴 하지만, 설정하기가 어렵고 안정성이 떨어진다는 단점이 있다).

 사정이 이렇다 보니, Avisynth측에서 사용하는 메모리가 많아지면 많아질수록 x264 인코딩시 적용할 수 있는 옵션에 제한이 생기게 된다. 특히, lookahead 계열의 옵션(더 나은 결과를 위해서 미리 프레임을 디코딩해둔다)이나 reference frame 관련 옵션의 경우에는 심각한 영향을 받게 된다. 그렇다고 Avisynth가 사용할 수 있는 메모리에 제한을 가하자니(SetMemoryMax()로 조절할 수 있다. 자세한 것은 매뉴얼을 읽어볼 것) 툭하면 제대로 디코딩이 되질 않는다(실제로, 무거운 필터들을 여럿 쓰다 보면 사용할 수 있는 메모리를 충분하게 잡아주더라도 Access Violation 오류를 빈번하게 볼 수 있다).


 자, 상황을 대충 설명하자면 이렇다. 32비트 운영체제에서 프로세스 하나가 쓸 수 있는 메모리는 2GB이다. 그런데, x264에서 바로 Avisynth 입력을 받으면, Avisynth가 x264 프로세스의 한 스레드로 동작하게 된다. 그렇게 해서 x264 인코더가 사용할 수 있는 메모리를 감소시키며, 심한 경우 화질에 영향을 줄 수 있는 옵션을 제한하게 된다. 이럴 때는 어떻게 하면 좋은가?


 가장 확실한 방법은 어떻게든 관련된 프로그램들을 전부 64비트로 바꾸는 것이다. 이 때의 문제는, 현재 인터넷에 돌아다니는 Avisynth 필터들은 구버전인 경우가 종종 있으며, 알 수 없는 오류를 내는 경우도 많다. 스스로 컴파일하려고 하더라도, 컴파일 환경 설정에 어려움을 겪는 일이 꽤 많고, 심한 경우에는 32비트만을 염두에 두고 설계한 소스를 가지고 스스로 뜯어고쳐야 되는 경우도 있다.

 이런 경우 쓸 수 있는 방법은 한 가지뿐이라고 할 수 있다. 바로 파이프를 이용하여 프로세스를 나누는 것이다. Avisynth 입력을 디코딩하는 프로세스와 x264 인코더를 분리시켜 동작시킴으로써 x264가 사용할 수 있는 메모리에 영향을 주는 것을 막을 수 있다. 물론, 이 때도 Avisynth 필터가 사용할 수 있는 메모리의 총합은 당연히 2GB를 넘을 수 없다(혹시 아래에 소개된 방법을 응용해서 이것을 피해가는 방법을 개발했다면 필자에게도 알려주기 바란다).


 x264 인코더는 stdin에서의 입력을 지원한다. 이는 파이프를 사용하여 다른 프로그램의 stdout 출력을 입력으로 읽을 수 있다는 말이 된다. avs2yuv라는 프로그램이 이 기능을 사용하기에 가장 적합하다(구글신(?)에 의하면 ffmpeg을 사용하는 방법들이 많이 나오지만, 이 녀석은 버그가 있어서 적합하지 않다. Avisynth 입력을 Direct stream copy(말 그대로 어떤 변형도 가하지 않고 스트림을 그대로 복사한다는 뜻이다)할 시 데이터가 변형되는 버그인데, 필자가 직접 최신 소스를 컴파일해서 돌려본 게 아니라서 ffmpeg의 버그인지 다른 이유가 있는지, 현재는 고쳐진 것인지에 대해서는 확실하지 않다. 이 때 사용한 버전은 http://ffmpeg.zeranoe.com/builds/ 에서 배포하는 2011년 6월 22일자 32-bit static build이다).


 avs2yuv의 사용법은 간단하다. avs2yuv (avs file) - (하이픈은 부연설명을 위한 의도라든가 잘못 쓴 것이 아니다. 정확하게 입력해줄 것)라고 입력하면 avs 입력을 yuv4mpeg라는 형식으로 화면에(!) 출력한다(엄밀하게는 stdout으로 출력한다. 하지만, stdout의 정보 출력 방향은 기본적으로 콘솔 화면으로 되어 있으며, 종종 '화면으로의 출력'과 동등한 의미로 사용된다. 한편, 이는 redirection을 사용하여 파일로 출력하거나 파이프를 사용하여 다른 프로그램의 입력으로 넘겨줄 수 있다). 여기에 | x264 (필요한 옵션) -demuxer y4m - (여기도 마찬가지다. |나 -를 절대 빼먹지 말 것)를 덧붙이면 x264는 파이프를 통해 넘겨진 입력을 해석하여 인코딩을 하게 된다. -demuxer y4m 옵션은 입력을 yuv4mpeg 형태로 간주하여 처리하라는 의미로, x264는 stdin에서 입력을 받아들일 때 기본적으로 raw 형식으로 취급하기 때문에 반드시 지정해줘야 한다.


 딱딱하고 재미없는 설명이 지루하다거나 이해하기가 힘들다는 독자를 위해, 사용법을 한 줄로 정리하면 다음과 같다(|, -와 띄어쓰기를 정확하게 하라. ()안의 부분은 사용자가 원하는 것으로 바꾼다)


 avs2yuv (avs) - | x264 (option) -demuxer y4m -


 이로써 일단 메모리 부족으로 x264가 뻗어버리는 현상은 막을 수 있었다. 이를 이용하여 Avisynth 필터 처리를 몇 단계로 나눠서 할 수 있다면, 단일 필터의 메모리 사용량이 2GB를 넘지 않는 선에서(그래봐야 스왑을 고려 대상에서 제외한다면 운영체제 자체 한계인 4GB를 넘어설 수는 없겠지만...) 메모리 걱정 없이 인코딩을 할 수도 있을 것이다. 그렇지만, 궁극적인 해결방법은 뭐니뭐니해도 64비트로 넘어가는 것이다. Avisynth와 사용되는 필터들이 한시빨리 공식적으로 64비트를 지원했으면 한다.