모바일 영상 파이프라인의 발열 — 메모리 복사, GPU Texture, Zero-Copy, 하드웨어 코덱
카메라 캡처부터 색공간 변환, 인코딩, 디코딩, 렌더링까지 모바일 영상 경로에서 메모리 복사와 CPU·GPU·하드웨어 코덱 사용이 발열에 미치는 영향을 설명합니다. Android SurfaceTexture와 iOS CVPixelBuffer 같은 플랫폼별 버퍼 공유 방식도 비교합니다. 실제 전력 효과는 단말과 코덱 지원에 따라 달라지므로 계측 기준을 함께 제시합니다.
목차(15개 항목)
- 0. 핵심 명제
- 1. 데이터 흐름: 카메라에서 화면까지 무슨 일이 일어나는가
- 2. 복사(Copy)는 왜 발생하는가 — 경계가 만든 비용
3. Zero-Copy: 픽셀 대신 "텍스처 핸들"을 넘긴다
- 4. 모바일 SoC의 공유 시스템 메모리
5. 하드웨어 인코딩 vs 소프트웨어 인코딩 — 전력과 품질의 교환
- 6. 기기 파편화와 코덱 화이트리스트 — 안드로이드의 현실
- 7. "렌더(Render)"라는 단어 정리
- 8. 한 줄 결론
- 관련 글
- 참고 자료
"영상 통화를 좀 하면 폰이 뜨끈해지고 배터리가 훅 닳는데, 코덱 설정 문제인가요?"라는 질문을 자주 받습니다. 코덱만의 문제는 아닙니다. 카메라, 디스플레이, CPU·GPU, 메모리, 모뎀과 인코더가 모두 전력과 발열에 기여하며 우선순위는 기기와 워크로드마다 달라집니다.
이 글은 모바일 영상 파이프라인을 따라가며 메모리 복사가 생기는 경계, 복사 없이 버퍼 핸들을 공유할 수 있는 조건, 하드웨어 코덱의 장단점을 정리합니다. 발열은 카메라·디스플레이·CPU/GPU·메모리·모뎀을 함께 측정해야 합니다.
0. 핵심 명제
모바일 영상의 발열·배터리에 메모리 이동과 인코더 선택이 큰 영향을 줄 수 있다. Zero-Copy는 CPU readback과 불필요한 풀프레임 복사를 줄이는 설계 목표이지, 카메라 입력·GPU 필터 결과·인코더 출력이 항상 동일 버퍼 하나를 쓴다는 뜻은 아니다.
세 줄 요약 카드부터 보겠습니다.
| 레버 | 나쁨 🔴 | 좋음 🟢 |
|---|---|---|
| 프레임 이동 | 불필요한 CPU memcpy/readback | 공유 버퍼와 surface를 사용해 복사 최소화 |
| 인코딩 주체 | 소프트웨어(CPU 풀로드) | 하드웨어 ASIC(MediaCodec/VideoToolbox) |
| 메모리 모델 가정 | "VRAM과 RAM이 따로 있다" (PC식 오해) | Unified Memory(통합 메모리) 전제로 설계 |
1. 데이터 흐름: 카메라에서 화면까지 무슨 일이 일어나는가
먼저 "정상적인" 영상 파이프라인의 단계를 그려 봅니다. 영상 통화 앱 하나에서 프레임 하나가 거쳐야 하는 경로입니다.
여기서 핵심 질문은 각 화살표(│)마다 픽셀 데이터를 복사하느냐, 아니면 "어디에 있는지"만 가리키느냐 입니다.
- 픽셀을 복사한다 = 1080p 프레임이면 약 3MB(YUV420 기준)를 초당 30번 옮긴다 = 초당 ~90MB의 memcpy.
- 가리키기만 한다 = 핸들(포인터/텍스처 ID) 몇 바이트만 전달한다.
이 차이가 발열의 큰 축입니다.
이 글은 [1]~4에 집중하고, [5] 네트워크/전송은 블로그 23·블로그 43에서 다룹니다.
비유: 한 부서에서 다음 부서로 서류를 넘길 때, 매번 전체 문서를 복사기로 복사해서 넘기는 것과, "서류함 3번 칸에 있다"는 쪽지 만 넘기는 것의 차이입니다. 기술적 실체로 환원하면 — 전자는 CPU가 메모리 대역폭을 태우며
memcpy를 도는 것이고, 후자는 GPU 텍스처 핸들(정수 ID) 하나를 전달하는 것입니다.
2. 복사(Copy)는 왜 발생하는가 — 경계가 만든 비용
"그냥 안 복사하면 되잖아?" 싶지만, 복사가 생기는 데는 구조적 이유가 있습니다. 데이터를 가진 쪽과 쓰려는 쪽 사이에 경계(boundary) 가 있기 때문입니다.
| 경계 종류 | 왜 복사가 생기나 |
|---|---|
| 프로세스 경계 | 공유 버퍼 핸들을 IPC로 전달할 수 있지만, API·포맷이 맞지 않으면 복사가 발생 |
| 보안/권한 경계 | 카메라 HAL이 만든 버퍼를 앱이 임의로 못 만진다. 안전한 핸드오프가 없으면 복사로 우회 |
| 포맷 경계 | 센서는 NV12/YUV, 인코더는 다른 정렬(stride/tiling)을 원함. 맞추려면 변환=복사 |
| CPU↔GPU 경계 | CPU 메모리에 있는 데이터를 GPU가 쓰려면 업로드(복사)가 필요 — 단, 통합 메모리에서는 이게 회피 가능 (4번 참조) |
순진하게 짜면 한 프레임이 이렇게 흐릅니다.
1080p·30fps 기준으로 위 경로엔 프레임당 3~4번의 풀프레임 이동이 있습니다. 초당으로 환산하면 수백 MB의 메모리 트래픽이고, 이는 CPU를 고클럭 상태로 붙잡아 둡니다. 발열의 직접 원인 중 하나입니다.
정정 (자주 보는 과장): "모바일 발열의 주범은 메모리 복사다" 는 부분적으로만 맞습니다(PARTLY_TRUE). 발열은 카메라 센서 동작, 디스플레이 백라이트, CPU/GPU 고주파 구동, 네트워크 무선(모뎀) 등 여러 요인의 합 입니다. 메모리 복사는 그중 하나일 뿐입니다. 다만 현대 안드로이드/iOS는 하드웨어 버퍼 공유와 제로카피를 기본 설계로 채택해 불필요한 복사를 최소화하므로, "복사를 피하는 것이 파이프라인 설계의 핵심"이라는 명제는 유효합니다.
3. Zero-Copy: 픽셀 대신 "텍스처 핸들"을 넘긴다
해결책은 단순합니다. 데이터를 옮기지 말고, 데이터를 가리키는 핸들을 공유한다. 모바일에서 이를 가능케 하는 건 OS가 제공하는 공유 버퍼 메커니즘입니다.
통합 메모리와 공유 버퍼 API를 사용하면 많은 복사를 피할 수 있지만, 포맷 변환과 필터 출력에는 별도 쓰기 대상이 필요할 수 있습니다.
3-1. Android: SurfaceTexture + GraphicBuffer + 외부 텍스처
안드로이드의 그래픽 스택은 BufferQueue라는 생산자-소비자 큐 위에 서 있습니다. 카메라가 프레임을 생산하면, 소비자(GPU/디스플레이)가 그 버퍼를 복사 없이 받아 갑니다.
| 구성요소 | 역할 |
|---|---|
GraphicBuffer | 실제 픽셀이 담긴 공유 메모리 버퍼(하드웨어 버퍼) |
BufferQueue | 생산자(카메라)↔소비자(GPU) 사이의 버퍼 핸들 큐 |
SurfaceTexture | 큐에서 받은 버퍼를 OpenGL 텍스처로 노출 |
GL_TEXTURE_EXTERNAL_OES | 일반 GL_TEXTURE_2D가 아닌 외부 텍스처 타깃. YUV/특수 포맷을 GPU가 직접 샘플링 |
EGLImageKHR | 버퍼를 텍스처 내용으로 "연결"하는 핸들. updateTexImage()가 이걸로 갱신 |
SurfaceTexture.updateTexImage()는 BufferQueue에서 새 버퍼를 획득하고 외부 OpenGL ES 텍스처의 내용을 갱신합니다. BufferQueue는 픽셀 내용 대신 버퍼 핸들을 전달할 수 있습니다. 필터 결과는 인코더 입력 Surface 같은 별도 출력 대상으로 렌더링되며, 전체 경로의 복사 유무는 포맷과 드라이버 구성까지 확인해야 합니다.
3-2. iOS: CVPixelBuffer + IOSurface + CVMetalTextureCache
iOS에서는 Metal 호환 CVPixelBuffer를 CVMetalTextureCache로 MTLTexture에 매핑할 수 있습니다. 이 경로는 CPU로 픽셀을 복사하는 일을 피할 수 있지만, 필터 결과는 일반적으로 별도 출력 texture/pixel buffer에 기록합니다.
| 구성요소 | 역할 |
|---|---|
CVPixelBuffer | 픽셀 버퍼 추상화 |
IOSurface | 프로세스/엔진 간 공유 가능한 실제 GPU 접근 가능 버퍼 |
CVMetalTextureCache | IOSurface 백업 버퍼를 Metal 텍스처로 복사 없이 래핑 |
kCVPixelBufferMetalCompatibilityKey | Metal texture 사용을 위한 pixel buffer compatibility 요청 |
CVMetalTextureCacheCreateTextureFromImage성공 여부와 pixel format·plane·Metal compatibility를 확인해야 합니다. IOSurface 여부 하나만으로 전체 pipeline의 zero-copy를 보장하지 않습니다.
3-3. 양 플랫폼 비교
| Android | iOS | |
|---|---|---|
| 공유 버퍼 | GraphicBuffer / HardwareBuffer | IOSurface |
| 카메라 프레임 타입 | SurfaceTexture 텍스처 | CVPixelBuffer |
| GPU 텍스처화 | GL_TEXTURE_EXTERNAL_OES + EGLImageKHR | CVMetalTextureCache |
| 갱신 호출 | updateTexImage() | CVMetalTextureCacheCreateTextureFromImage() |
| 복사 비용 | BufferQueue 구간은 핸들 전달 가능. 전체 경로는 측정 필요 | texture mapping은 CPU 복사를 피할 수 있음. 전체 경로는 측정 필요 |
두 플랫폼 모두 공유 버퍼와 surface를 이용해 CPU 복사를 줄일 수 있습니다.
4. 모바일 SoC의 공유 시스템 메모리
여기서 PC 그래픽 카드의 직관을 그대로 옮기면 틀립니다.
스마트폰 SoC에서는 CPU·GPU·미디어 블록이 시스템 메모리를 공유하는 구성이 일반적입니다. Apple은 자사 silicon을 Unified Memory Architecture로 설명합니다. 세부 캐시·tiling·coherency와 메모리 채널은 SoC별 구현입니다.
공유 물리 메모리는 CPU↔GPU 사이의 residency copy를 줄일 수 있습니다. 다만 API 사용 방식, pixel format, texture layout과 필터 출력 때문에 논리적 복사나 별도 메모리 쓰기가 여전히 발생할 수 있습니다.
메모리 채널 수와 우선순위 정책은 SoC별 구현이므로 일반화하지 않습니다. 앱에서는 지원 API와 실제 메모리 대역폭·전력 프로파일을 기준으로 판단합니다.
5. 하드웨어 인코딩 vs 소프트웨어 인코딩 — 전력과 품질의 교환
H.264/HEVC/AV1 인코딩은 연산량이 큽니다. 소프트웨어와 전용 하드웨어 블록은 처리량, 전력, 품질·기능 지원이 다르며 어느 쪽이 얼마나 유리한지는 코덱·설정·SoC와 thermal 상태에서 측정해야 합니다.
모바일 SoC는 전용 비디오 인코더·디코더를 통합할 수 있지만 지원 코덱·프로파일·해상도·프레임률은 기기마다 다릅니다. Android는 MediaCodecList/MediaCodecInfo, Apple은 VideoToolbox session 생성과 encoder specification으로 런타임 capability를 확인해야 합니다.
| 항목 | 소프트웨어 인코딩 🔴 | 하드웨어 인코딩(ASIC) 🟢 |
|---|---|---|
| 연산 주체 | 범용 CPU 코어 | 전용 고정기능 블록 |
| 전력 효율 | 낮음(CPU 고클럭 유지) | 높음(목적 최적화 회로) |
| 발열 | 큼 | 작음 |
| 유연성 | 높음(임의 코덱/옵션) | 낮음(지원 코덱·프로파일 한정) |
| 화질 튜닝 | 세밀(x264 옵션 등) | 제한적 |
전용 하드웨어는 처리량과 전력에서 이점을 줄 수 있지만 절감 폭은 코덱·해상도·비트레이트·SoC·품질 설정에 따라 달라집니다. 디코딩 연구 수치로 인코딩 전력을 추정하거나 범용 배수를 적용하지 않습니다. 대상 기기에서 전력, thermal throttling, frame drop과 품질을 직접 측정합니다.
소프트웨어 인코더는 튜닝 범위가 넓고, 하드웨어 인코더는 지원 기능이 제한될 수 있습니다. 모바일 실시간 영상에서는 하드웨어 인코더를 우선 검토하되 capability·품질·안정성 검증과 software fallback을 함께 설계합니다.
5-1. 접근 API
| 플랫폼 | API | 하드웨어 확인 방법 |
|---|---|---|
| Android | android.media.MediaCodec | API 29+ MediaCodecInfo.isHardwareAccelerated() |
| iOS | VideoToolbox 프레임워크 | VTCompressionSession 생성 시 kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder 요청 및 사용 encoder 확인 |
Android에서는 MediaCodecInfo의 getSupportedPerformancePoints()로 특정 해상도·프레임레이트 조합을 하드웨어가 감당하는지 조회할 수 있습니다. iOS의 VideoToolbox는 헤더 파일과 WWDC 세션 문서가 주된 레퍼런스입니다.
6. 기기 파편화와 코덱 화이트리스트 — 안드로이드의 현실
Android 하드웨어 코덱은 기기마다 capability와 구현 품질이 다를 수 있습니다. 고정된 과거 화이트리스트를 복사하기보다 런타임 capability 조회, 실패 telemetry와 명시적 fallback을 사용합니다.
MediaCodecInfo의 codec type·profile/level·hardware acceleration과 performance point를 확인하고, session 생성 실패나 출력 이상을 관측해 codec별 fallback 조건을 유지합니다.
시사점: 모바일 영상 앱을 직접 만든다면 "하드웨어 코덱 = 항상 켠다"가 아니라 "기기별로 신뢰할 수 있을 때만 켠다" 가 현실적인 정책입니다. 신뢰 안 되는 기기는 소프트웨어 폴백(전력 손해를 감수)하거나 해상도를 낮춥니다.
7. "렌더(Render)"라는 단어 정리
마지막으로 자주 혼동되는 용어 하나를 짚습니다. 영상 파이프라인에서 "렌더"는 두 가지 다른 작업을 동시에 가리킬 수 있습니다.
| 맥락 | "렌더"의 의미 |
|---|---|
| 미리보기/표시 | GPU가 텍스처를 화면(디스플레이)에 그리는 것 |
| 필터 처리 | GPU가 셰이더로 텍스처를 다른 텍스처로 변환(오프스크린 렌더)하는 것 |
두 작업은 같은 입력 texture를 읽을 수 있지만 필터 결과는 별도 render target에 기록됩니다. 인코더 입력 Surface에 직접 렌더하면 CPU readback을 피할 수 있습니다.
8. 한 줄 결론
모바일 영상의 발열·배터리는 카메라·디스플레이·CPU/GPU·메모리 이동·인코더·모뎀의 합이다. 공유 버퍼와 surface로 CPU readback을 줄이고 하드웨어 인코더를 우선 검토하되, 기기별 capability와 품질을 측정해 fallback을 설계한다.
관련 글
- /frank/blog/23 — 오디오 파이프라인 (Opus/RTP/Jitter Buffer): 영상의 자매편
- /frank/blog/27 — 프레임 I/P/B, GOP, PLI/FIR: 인코더가 뭘 만드는지
- /frank/blog/28 — H.264 Profile·인코더·비트레이트: 코덱 설정의 기초
- /frank/blog/30 — x264 옵션 ref/tune/keyint: 소프트웨어 인코딩의 튜닝 자유도
- /frank/blog/43 — Agora 자체 코덱 vs Web SDK, SD-RTN: 플랫폼이 파편화를 흡수하는 방식
참고 자료
- Android — HardwareBuffer: https://developer.android.com/reference/android/hardware/HardwareBuffer
- Android — SurfaceTexture 아키텍처: https://source.android.com/docs/core/graphics/arch-st
- Android — MediaCodec: https://developer.android.com/reference/android/media/MediaCodec
- Android — Media codecs 가이드: https://developer.android.com/guide/topics/media/media-codecs
- Apple — CVMetalTextureCache: https://developer.apple.com/documentation/corevideo/cvmetaltexturecache
- Apple — Metal compatibility key: https://developer.apple.com/documentation/corevideo/kcvpixelbuffermetalcompatibilitykey
- Apple — VideoToolbox: https://developer.apple.com/documentation/videotoolbox
- Android — BufferQueue and gralloc: https://source.android.com/docs/core/graphics/arch-bq-gralloc
- Apple — Explore the image processing pipeline (WWDC21): https://developer.apple.com/videos/play/wwdc2021/10153/
- Apple — hardware encoder specification: https://developer.apple.com/documentation/videotoolbox/kvtvideoencoderspecification_enablehardwareacceleratedvideoencoder