16 KiB
16 KiB
Android Vulkan AV1 Player 설계 문서
프로젝트: VavCore Android Vulkan Surface AV1 Player 날짜: 2025-09-29 상태: 🚧 설계 단계 플랫폼: Android (API Level 29+, Vulkan 1.0+)
🎯 프로젝트 개요
Android에서 Vulkan Surface를 사용하여 직접 렌더링하는 고성능 AV1 비디오 플레이어를 구현합니다. VavCore JNI 라이브러리와 Android MediaCodec 하드웨어 가속을 활용하여 최적의 성능을 달성합니다.
핵심 목표
- Vulkan Direct Rendering: CPU 메모리 복사 없이 GPU Surface 직접 렌더링
- 하드웨어 가속: MediaCodec + Vulkan 파이프라인으로 최대 성능 달성
- 실시간 성능: 4K AV1 비디오 60fps 재생 목표
- 사용자 경험: 직관적인 비디오 컨트롤 UI
🏗️ 전체 아키텍처
시스템 구성도
┌─────────────────────────────────────────────────────────────┐
│ Android Application Layer │
├─────────────────────────────────────────────────────────────┤
│ Java/Kotlin UI │ VulkanVideoView (Custom View) │
│ - Load Video Button │ - Vulkan Surface │
│ - Play/Pause/Stop │ - YUV → RGB Conversion │
│ - Progress Bar │ - AspectFit Rendering │
│ - Performance Stats │ - Touch Controls │
├─────────────────────────────────────────────────────────────┤
│ JNI Bridge Layer │
│ - VavCore JNI Wrapper │ - Vulkan JNI Native │
│ - Video Control APIs │ - Surface Management │
│ - Performance Metrics │ - Texture Binding │
├─────────────────────────────────────────────────────────────┤
│ Native C++ Layer │
│ VavCore Library │ Vulkan Renderer │
│ - MediaCodec Decoder │ - VkSurface Creation │
│ - dav1d Fallback │ - YUV Shader Pipeline │
│ - Frame Management │ - Command Buffer Management │
├─────────────────────────────────────────────────────────────┤
│ Hardware Layer │
│ Android MediaCodec │ Vulkan GPU Driver │
│ - AV1 HW Decoding │ - GPU YUV Processing │
│ - Surface Output │ - Synchronized Rendering │
└─────────────────────────────────────────────────────────────┘
📱 Android 앱 구조
프로젝트 디렉토리 구조
vav2/platforms/android/applications/vav2player/
├── app/
│ ├── src/main/
│ │ ├── java/com/vavcore/player/
│ │ │ ├── MainActivity.java # 메인 액티비티
│ │ │ ├── VulkanVideoView.java # 커스텀 Vulkan 뷰
│ │ │ ├── VideoController.java # 비디오 컨트롤 로직
│ │ │ └── PerformanceMonitor.java # 성능 모니터링
│ │ ├── cpp/
│ │ │ ├── vulkan_renderer.cpp # Vulkan 렌더링 엔진
│ │ │ ├── vulkan_jni.cpp # Vulkan JNI 바인딩
│ │ │ ├── yuv_shader.cpp # YUV → RGB 쉐이더
│ │ │ └── surface_manager.cpp # Surface 관리
│ │ ├── res/
│ │ │ ├── layout/
│ │ │ │ ├── activity_main.xml # 메인 UI 레이아웃
│ │ │ │ └── video_controls.xml # 비디오 컨트롤 UI
│ │ │ ├── values/
│ │ │ │ ├── strings.xml # 문자열 리소스
│ │ │ │ └── colors.xml # 색상 테마
│ │ │ └── drawable/ # 아이콘 리소스
│ │ └── AndroidManifest.xml # 앱 매니페스트
│ ├── build.gradle # 앱 빌드 설정
│ └── CMakeLists.txt # 네이티브 빌드 설정
├── vavcore/ # VavCore JNI 모듈 (기존)
└── build.gradle # 프로젝트 빌드 설정
🎮 UI 설계
메인 화면 레이아웃
┌─────────────────────────────────────────────────────────────┐
│ App Title Bar │
├─────────────────────────────────────────────────────────────┤
│ │
│ │
│ VulkanVideoView │
│ (Vulkan Surface) │
│ │
│ │
├─────────────────────────────────────────────────────────────┤
│ [Load Video] [Play] [Pause] [Stop] Progress: 45% │
├─────────────────────────────────────────────────────────────┤
│ Decoder: MediaCodec | FPS: 60 | Resolution: 3840x2160 │
│ Frame Time: 12ms | GPU Memory: 245MB | Dropped: 0 │
└─────────────────────────────────────────────────────────────┘
UI 컴포넌트 사양
VulkanVideoView (커스텀 뷰)
- 기능: Vulkan Surface 렌더링 및 비디오 표시
- 특징:
- Touch 이벤트 처리 (탭해서 Play/Pause)
- AspectFit 자동 조정
- 성능 오버레이 표시 옵션
- 크기: Match parent (전체 화면 비율 유지)
비디오 컨트롤 버튼
- Load Video: 파일 선택 다이얼로그 → AV1 파일 로드
- Play: 비디오 재생 시작
- Pause: 재생 일시정지 (Resume 가능)
- Stop: 재생 중지 및 처음으로 되돌리기
진행률 표시
- Progress Bar: 현재 재생 위치 (SeekBar로 탐색 가능)
- 시간 표시: "02:34 / 05:42" 형식
성능 모니터링 패널
- 디코더 정보: 현재 사용 중인 디코더 (MediaCodec/dav1d)
- 실시간 FPS: 현재 렌더링 프레임레이트
- 해상도: 비디오 원본 해상도
- 프레임 타임: 디코딩 + 렌더링 시간
- GPU 메모리: 현재 GPU 메모리 사용량
- 드롭된 프레임: 성능 부족으로 건너뛴 프레임 수
🔧 Vulkan 렌더링 엔진
Vulkan 파이프라인 설계
1. Vulkan 초기화 시퀀스
// 1. Vulkan Instance 생성
VkInstance instance;
VkApplicationInfo appInfo = {};
appInfo.pApplicationName = "VavCore AV1 Player";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "VavCore Vulkan Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
// 2. Android Surface 생성
VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo = {};
surfaceCreateInfo.window = androidWindow; // ANativeWindow*
// 3. Physical Device 및 Queue Family 선택
VkPhysicalDevice physicalDevice;
uint32_t graphicsQueueFamilyIndex;
uint32_t presentQueueFamilyIndex;
// 4. Logical Device 생성
VkDevice device;
VkQueue graphicsQueue;
VkQueue presentQueue;
// 5. Swapchain 설정
VkSwapchainKHR swapchain;
VkFormat swapchainImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
VkExtent2D swapchainExtent;
2. YUV → RGB 변환 쉐이더
Vertex Shader (yuv_vertex.vert):
#version 450
layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec2 inTexCoord;
layout(location = 0) out vec2 fragTexCoord;
layout(push_constant) uniform PushConstants {
mat4 transform;
} pc;
void main() {
gl_Position = pc.transform * vec4(inPosition, 0.0, 1.0);
fragTexCoord = inTexCoord;
}
Fragment Shader (yuv_fragment.frag):
#version 450
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor;
layout(binding = 0) uniform sampler2D yTexture;
layout(binding = 1) uniform sampler2D uTexture;
layout(binding = 2) uniform sampler2D vTexture;
// BT.709 YUV to RGB conversion matrix
const mat3 yuvToRgb = mat3(
1.0000, 1.0000, 1.0000,
0.0000, -0.1873, 1.8556,
1.5748, -0.4681, 0.0000
);
void main() {
float y = texture(yTexture, fragTexCoord).r;
float u = texture(uTexture, fragTexCoord).r - 0.5;
float v = texture(vTexture, fragTexCoord).r - 0.5;
vec3 yuv = vec3(y, u, v);
vec3 rgb = yuvToRgb * yuv;
outColor = vec4(rgb, 1.0);
}
3. 렌더링 파이프라인
class VulkanVideoRenderer {
public:
struct VideoFrame {
VkImage yImage, uImage, vImage;
VkDeviceMemory yMemory, uMemory, vMemory;
VkImageView yImageView, uImageView, vImageView;
uint32_t width, height;
};
// 프레임 렌더링 메인 함수
void RenderFrame(const VideoFrame& frame) {
// 1. Command Buffer 시작
BeginCommandBuffer();
// 2. Render Pass 시작
BeginRenderPass();
// 3. YUV 텍스처 바인딩
BindYUVTextures(frame);
// 4. 변환 행렬 업데이트 (AspectFit)
UpdateTransformMatrix(frame.width, frame.height);
// 5. 그리기 명령
DrawFullscreenQuad();
// 6. Render Pass 종료
EndRenderPass();
// 7. Command Buffer 제출
SubmitCommandBuffer();
// 8. Present
PresentFrame();
}
private:
void UpdateTransformMatrix(uint32_t videoWidth, uint32_t videoHeight);
void BindYUVTextures(const VideoFrame& frame);
void DrawFullscreenQuad();
};
🔗 JNI 통합 레이어
VavCore JNI 확장
vulkan_jni.cpp
// Vulkan Surface 생성 및 관리
extern "C" JNIEXPORT jlong JNICALL
Java_com_vavcore_player_VulkanVideoView_nativeCreateVulkanRenderer(
JNIEnv* env, jobject thiz, jobject surface) {
ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
VulkanVideoRenderer* renderer = new VulkanVideoRenderer();
if (renderer->Initialize(window)) {
return reinterpret_cast<jlong>(renderer);
}
delete renderer;
return 0;
}
// 프레임 렌더링 (VavCore에서 디코딩된 프레임 받아서 Vulkan 렌더링)
extern "C" JNIEXPORT void JNICALL
Java_com_vavcore_player_VulkanVideoView_nativeRenderFrame(
JNIEnv* env, jobject thiz, jlong rendererPtr, jlong framePtr) {
VulkanVideoRenderer* renderer = reinterpret_cast<VulkanVideoRenderer*>(rendererPtr);
VavCoreVideoFrame* frame = reinterpret_cast<VavCoreVideoFrame*>(framePtr);
// VavCore 프레임을 Vulkan 텍스처로 변환
VulkanVideoRenderer::VideoFrame vulkanFrame;
ConvertVavCoreFrameToVulkan(frame, vulkanFrame);
// Vulkan 렌더링
renderer->RenderFrame(vulkanFrame);
}
// 성능 메트릭 수집
extern "C" JNIEXPORT jobject JNICALL
Java_com_vavcore_player_VulkanVideoView_nativeGetPerformanceMetrics(
JNIEnv* env, jobject thiz, jlong rendererPtr) {
VulkanVideoRenderer* renderer = reinterpret_cast<VulkanVideoRenderer*>(rendererPtr);
auto metrics = renderer->GetPerformanceMetrics();
// Java PerformanceMetrics 객체 생성 및 반환
return CreateJavaPerformanceMetrics(env, metrics);
}
📊 성능 최적화 전략
1. Zero-Copy 파이프라인
MediaCodec → Surface → Vulkan Texture → GPU Rendering
↑ ↑ ↑ ↑
HW Decode Direct Bind GPU Memory Zero Copy
2. 메모리 최적화
- Texture Pooling: 프레임 텍스처 재사용
- Staging Buffer: GPU 메모리 전송 최적화
- Memory Mapping: Persistent 메모리 매핑 사용
3. 렌더링 최적화
- Double Buffering: Swapchain 이미지 2개 사용
- Async Rendering: 디코딩과 렌더링 파이프라인 분리
- GPU Synchronization: VkSemaphore로 동기화
4. Android 특화 최적화
- ANativeWindow 직접 사용: Java Surface 오버헤드 제거
- Vulkan 1.0 호환성: 최대 디바이스 지원
- Battery Optimization: 불필요한 GPU 연산 최소화
🛠️ 개발 단계별 계획
Phase 1: Vulkan 기반 구조 구축 (1-2일)
- 설계 문서 작성
- Android 프로젝트 구조 생성
- Vulkan 초기화 및 Surface 생성
- 기본 렌더링 파이프라인 구현
Phase 2: YUV 렌더링 시스템 (2-3일)
- YUV → RGB 쉐이더 구현
- VavCore JNI 연동
- 텍스처 관리 시스템
- AspectFit 렌더링 로직
Phase 3: UI 및 컨트롤 (1-2일)
- Java/Kotlin UI 구현
- 비디오 컨트롤 버튼 기능
- 파일 로더 및 진행률 표시
- 터치 인터랙션
Phase 4: 성능 최적화 (1-2일)
- 성능 모니터링 시스템
- 메모리 및 GPU 최적화
- MediaCodec 벤치마킹
- 배터리 사용량 최적화
Phase 5: 테스트 및 검증 (1일)
- 다양한 AV1 파일 테스트
- 성능 벤치마크 수행
- 메모리 누수 검사
- 사용자 테스트
📋 기술 요구사항
Android 요구사항
- API Level: 29+ (Android 10+)
- Vulkan 지원: Vulkan 1.0 이상
- NDK 버전: r25+
- Build Tools: CMake 3.22+, Gradle 8.0+
하드웨어 요구사항
- GPU: Vulkan 지원 GPU (Adreno 640+, Mali-G76+)
- 메모리: 4GB+ RAM 권장
- 저장공간: 100MB+ 앱 크기
성능 목표
- 4K AV1: 30fps 안정적 재생
- 1080p AV1: 60fps 재생
- 메모리 사용량: 500MB 이하
- 배터리: 1시간 재생 시 20% 이하 소모
🔍 리스크 및 대응방안
기술적 리스크
-
Vulkan 호환성: 일부 구형 디바이스 미지원
- 대응: OpenGL ES 3.0 fallback 구현
-
MediaCodec 안정성: 디바이스별 구현 차이
- 대응: dav1d 소프트웨어 디코더로 fallback
-
메모리 사용량: 4K 비디오의 높은 메모리 요구
- 대응: 동적 해상도 조정 및 메모리 풀링
플랫폼 리스크
-
Android 버전 호환성: Vulkan API 변경
- 대응: Vulkan 1.0 baseline 사용
-
OEM 커스터마이징: 제조사별 드라이버 이슈
- 대응: 광범위한 디바이스 테스트
📚 참고 문서 및 리소스
VavCore 관련
Vulkan 참고자료
Android MediaCodec
문서 작성일: 2025-09-29 작성자: Claude Code 버전: 1.0 상태: ✅ 설계 완료 → 구현 준비
이 설계 문서를 기반으로 Android Vulkan AV1 Player 개발을 시작합니다.