1635 lines
60 KiB
Markdown
1635 lines
60 KiB
Markdown
|
|
# VavCore Android MediaCodec 크로스 플랫폼 Graphics 통합 설계
|
||
|
|
|
||
|
|
## 📋 **문서 정보**
|
||
|
|
- **작성일**: 2025-09-27
|
||
|
|
- **버전**: 3.0.0 (완전한 크로스 플랫폼 Graphics API 통합)
|
||
|
|
- **최신 업데이트**: Enhanced IVideoDecoder 인터페이스 및 VavCoreSurfaceType 시스템
|
||
|
|
- **대상**: VavCore Android MediaCodec AV1 Decoder + 크로스 플랫폼 Graphics
|
||
|
|
- **목적**: Android의 다양한 Graphics API와 MediaCodec의 완전한 크로스 플랫폼 통합
|
||
|
|
|
||
|
|
## 1. 개요 및 최신 변경사항
|
||
|
|
|
||
|
|
본 문서는 VavCore의 완전한 크로스 플랫폼 Graphics API 지원을 포함하여 Android MediaCodec API와의 통합 설계를 제시합니다. **주요 업데이트:**
|
||
|
|
|
||
|
|
### **🆕 v3.0 최신 기능 (2025-09-27) - 현실적인 AV1 하드웨어 지원 반영**
|
||
|
|
- ✅ **완전한 크로스 플랫폼 Surface 시스템**: VavCoreSurfaceType 열거형으로 모든 플랫폼 지원
|
||
|
|
- ✅ **Enhanced IVideoDecoder 인터페이스**: 플랫폼별 Graphics API 설정 메서드 확장
|
||
|
|
- ⚠️ **현실적인 Android AV1 하드웨어 지원**: 2022년 이후 고급 SoC만 실제 지원
|
||
|
|
- ✅ **ANativeWindow 우선 지원**: MediaCodec Surface 디코딩의 가장 안정적인 방식
|
||
|
|
- ⚠️ **제한적인 고급 Graphics API**: OpenGL ES/Vulkan은 고급 SoC + API 29+에서만
|
||
|
|
- ✅ **정확한 하드웨어 감지**: 실제 AV1 지원 SoC 검증 로직 (Snapdragon 8 Gen 1+, Tensor G2+)
|
||
|
|
- ✅ **Graceful Fallback**: 하드웨어 미지원 시 dav1d 소프트웨어 디코더로 안전한 전환
|
||
|
|
|
||
|
|
### **⚠️ 중요: Android AV1 하드웨어 지원 현실**
|
||
|
|
**실제 AV1 하드웨어 디코딩이 가능한 기기:**
|
||
|
|
- **Qualcomm**: Snapdragon 8 Gen 1+ (2022년 이후) - Galaxy S22+, OnePlus 10+
|
||
|
|
- **Google**: Tensor G2+ (Pixel 7+, 2022년 이후)
|
||
|
|
- **MediaTek**: Dimensity 9200+ (2023년 이후) - 일부 고급 기기만
|
||
|
|
- **Samsung**: Exynos 2200 (Galaxy S22 일부) - 제한적이고 불안정
|
||
|
|
|
||
|
|
**🎮 Godot 게임엔진 관점에서의 Surface 우선순위:**
|
||
|
|
1. **Vulkan VkImage** - Godot 4 Forward+/Mobile 렌더러와 직접 통합
|
||
|
|
2. **OpenGL ES 텍스처** - Godot 4 Compatibility 렌더러와 직접 통합
|
||
|
|
3. **ANativeWindow** - 추가 변환 필요, 게임엔진에 덜 적합
|
||
|
|
4. **CPU 메모리** - 호환성은 좋지만 성능 저하
|
||
|
|
|
||
|
|
**대부분의 Android 기기는 여전히 소프트웨어 디코딩 필요**
|
||
|
|
|
||
|
|
## 2. VavCore 크로스 플랫폼 아키텍처 분석
|
||
|
|
|
||
|
|
### 2.1 하드웨어 디코더 팩토리 패턴
|
||
|
|
VavCore는 등록 기반 디코더 팩토리 시스템으로 모든 플랫폼의 하드웨어 가속을 지원합니다:
|
||
|
|
|
||
|
|
**VideoDecoderFactory 디코더 우선순위:**
|
||
|
|
```cpp
|
||
|
|
// AUTO 모드 우선순위: Platform-specific HW → dav1d SW
|
||
|
|
enum class VideoCodecType {
|
||
|
|
AV1, VP9, H264, H265
|
||
|
|
};
|
||
|
|
|
||
|
|
enum class DecoderType {
|
||
|
|
AUTO, // 플랫폼별 최적 디코더 자동 선택
|
||
|
|
// Windows Hardware Decoders
|
||
|
|
NVDEC, // NVIDIA NVDEC (Windows)
|
||
|
|
VPL, // Intel VPL (Windows)
|
||
|
|
AMF, // AMD AMF (Windows)
|
||
|
|
MEDIA_FOUNDATION, // Windows Media Foundation
|
||
|
|
// Android Hardware Decoders
|
||
|
|
MEDIACODEC, // Android MediaCodec
|
||
|
|
// Cross-platform Software
|
||
|
|
DAV1D // dav1d 소프트웨어 (모든 플랫폼)
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.2 Enhanced IVideoDecoder 크로스 플랫폼 인터페이스
|
||
|
|
현재 인터페이스는 모든 플랫폼의 Graphics API를 완전히 지원합니다:
|
||
|
|
|
||
|
|
```cpp
|
||
|
|
class IVideoDecoder {
|
||
|
|
public:
|
||
|
|
// Core 디코딩 인터페이스
|
||
|
|
virtual bool Initialize(const VideoMetadata& metadata) = 0;
|
||
|
|
virtual bool DecodeFrame(const VideoPacket& input_packet, VideoFrame& output_frame) = 0;
|
||
|
|
virtual bool DecodeFrame(const uint8_t* packet_data, size_t packet_size, VideoFrame& output_frame) = 0;
|
||
|
|
|
||
|
|
// 크로스 플랫폼 Surface 디코딩
|
||
|
|
virtual bool SupportsSurfaceType(VavCoreSurfaceType type) const = 0;
|
||
|
|
virtual VavCoreSurfaceType GetOptimalSurfaceType() const = 0;
|
||
|
|
virtual bool DecodeToSurface(const uint8_t* packet_data, size_t packet_size,
|
||
|
|
VavCoreSurfaceType target_type,
|
||
|
|
void* target_surface,
|
||
|
|
VideoFrame& output_frame) = 0;
|
||
|
|
|
||
|
|
// 플랫폼별 Graphics API 설정
|
||
|
|
// Windows
|
||
|
|
virtual bool SetD3DDevice(void* d3d_device, VavCoreSurfaceType type) = 0;
|
||
|
|
|
||
|
|
// Android
|
||
|
|
virtual bool SetAndroidSurface(void* native_window) = 0;
|
||
|
|
virtual bool SetOpenGLESContext(void* egl_context) = 0;
|
||
|
|
virtual bool SetVulkanDevice(void* vk_device, void* vk_instance) = 0;
|
||
|
|
|
||
|
|
// Cross-platform
|
||
|
|
virtual bool SetOpenGLContext(void* gl_context) = 0;
|
||
|
|
virtual bool SetMetalDevice(void* metal_device) = 0;
|
||
|
|
|
||
|
|
// Graphics API 지원 감지
|
||
|
|
virtual bool SupportsHardwareAcceleration() const = 0;
|
||
|
|
virtual bool SupportsZeroCopyDecoding() const = 0;
|
||
|
|
virtual bool RequiresExternalContext() const = 0;
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.3 VavCoreSurfaceType 크로스 플랫폼 시스템
|
||
|
|
현재 VavCore는 모든 주요 플랫폼의 Graphics API를 완전히 지원합니다:
|
||
|
|
|
||
|
|
```cpp
|
||
|
|
typedef enum {
|
||
|
|
VAVCORE_SURFACE_CPU = 0, // 전통적인 CPU 메모리
|
||
|
|
|
||
|
|
// Windows Graphics APIs
|
||
|
|
VAVCORE_SURFACE_D3D11_TEXTURE = 1, // D3D11 texture (Windows)
|
||
|
|
VAVCORE_SURFACE_D3D12_RESOURCE = 2, // D3D12 resource (Windows)
|
||
|
|
VAVCORE_SURFACE_CUDA_DEVICE = 3, // CUDA device pointer (Windows)
|
||
|
|
VAVCORE_SURFACE_AMF_SURFACE = 4, // AMF surface wrapper (Windows)
|
||
|
|
|
||
|
|
// Android Graphics APIs
|
||
|
|
VAVCORE_SURFACE_ANDROID_NATIVE_WINDOW = 5, // Android ANativeWindow
|
||
|
|
VAVCORE_SURFACE_OPENGL_ES_TEXTURE = 6, // OpenGL ES texture (Android/iOS)
|
||
|
|
VAVCORE_SURFACE_VULKAN_IMAGE = 7, // Vulkan VkImage (Android/Windows)
|
||
|
|
VAVCORE_SURFACE_ANDROID_HARDWARE_BUFFER = 8, // AHardwareBuffer (Android)
|
||
|
|
|
||
|
|
// Cross-platform APIs
|
||
|
|
VAVCORE_SURFACE_OPENGL_TEXTURE = 9, // Desktop OpenGL texture
|
||
|
|
VAVCORE_SURFACE_METAL_TEXTURE = 10, // Metal MTLTexture (iOS/macOS)
|
||
|
|
VAVCORE_SURFACE_COREVIDEO_PIXELBUFFER = 11 // CVPixelBuffer (iOS/macOS)
|
||
|
|
} VavCoreSurfaceType;
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.4 하드웨어 디코더 공통 구현 패턴
|
||
|
|
**모든 플랫폼의 하드웨어 디코더 (NVDEC/AMF/VPL/MediaCodec) 공통 패턴:**
|
||
|
|
1. **하드웨어 감지**: GPU/SoC 하드웨어 가용성 자동 확인
|
||
|
|
2. **Graphics API 설정**: 플랫폼별 최적 Graphics API 초기화
|
||
|
|
3. **Surface 기반 디코딩**: Zero-copy를 위한 하드웨어 Surface 직접 렌더링
|
||
|
|
4. **Graceful Fallback**: 하드웨어 실패 시 소프트웨어 디코더로 자동 전환
|
||
|
|
5. **성능 최적화**: GPU-to-GPU 직접 전송으로 메모리 복사 제거
|
||
|
|
6. **리소스 관리**: 플랫폼별 하드웨어 리소스 적절한 해제
|
||
|
|
|
||
|
|
## 3. Android MediaCodec 크로스 플랫폼 통합 설계
|
||
|
|
|
||
|
|
### 3.1 플랫폼별 조건부 컴파일 전략
|
||
|
|
|
||
|
|
```cpp
|
||
|
|
// 플랫폼별 헤더 및 Graphics API 정의
|
||
|
|
#ifdef ANDROID
|
||
|
|
#include <media/NdkMediaCodec.h>
|
||
|
|
#include <media/NdkMediaFormat.h>
|
||
|
|
#include <media/NdkMediaCodecList.h>
|
||
|
|
#include <android/native_window.h>
|
||
|
|
#include <android/hardware_buffer.h>
|
||
|
|
#include <EGL/egl.h>
|
||
|
|
#include <GLES2/gl2.h>
|
||
|
|
#include <vulkan/vulkan.h>
|
||
|
|
#include <android/log.h>
|
||
|
|
#define VAVCORE_PLATFORM_ANDROID
|
||
|
|
|
||
|
|
#elif defined(_WIN32)
|
||
|
|
#include <d3d11.h>
|
||
|
|
#include <d3d12.h>
|
||
|
|
#include <dxgi.h>
|
||
|
|
#include <mfapi.h>
|
||
|
|
#include <mftransform.h>
|
||
|
|
#define VAVCORE_PLATFORM_WINDOWS
|
||
|
|
|
||
|
|
#elif defined(__APPLE__)
|
||
|
|
#include <Metal/Metal.h>
|
||
|
|
#include <CoreVideo/CoreVideo.h>
|
||
|
|
#define VAVCORE_PLATFORM_APPLE
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// VavCoreSurfaceType은 이제 enum으로 통합 관리
|
||
|
|
// 플랫폼별 void* 포인터로 실제 리소스 전달
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.2 AndroidMediaCodecAV1Decoder Enhanced 구현
|
||
|
|
|
||
|
|
#### 3.2.1 Enhanced 클래스 구조 (크로스 플랫폼 호환성)
|
||
|
|
```cpp
|
||
|
|
namespace VavCore {
|
||
|
|
|
||
|
|
class AndroidMediaCodecAV1Decoder : public IVideoDecoder {
|
||
|
|
public:
|
||
|
|
AndroidMediaCodecAV1Decoder();
|
||
|
|
virtual ~AndroidMediaCodecAV1Decoder();
|
||
|
|
|
||
|
|
// IVideoDecoder 기본 인터페이스
|
||
|
|
bool Initialize(const VideoMetadata& metadata) override;
|
||
|
|
void Cleanup() override;
|
||
|
|
bool IsInitialized() const override { return m_initialized; }
|
||
|
|
|
||
|
|
// Core 디코딩 기능
|
||
|
|
bool DecodeFrame(const VideoPacket& input_packet, VideoFrame& output_frame) override;
|
||
|
|
bool DecodeFrame(const uint8_t* packet_data, size_t packet_size, VideoFrame& output_frame) override;
|
||
|
|
|
||
|
|
// 크로스 플랫폼 Surface 디코딩 (Enhanced)
|
||
|
|
bool SupportsSurfaceType(VavCoreSurfaceType type) const override;
|
||
|
|
VavCoreSurfaceType GetOptimalSurfaceType() const override;
|
||
|
|
bool DecodeToSurface(const uint8_t* packet_data, size_t packet_size,
|
||
|
|
VavCoreSurfaceType target_type,
|
||
|
|
void* target_surface,
|
||
|
|
VideoFrame& output_frame) override;
|
||
|
|
|
||
|
|
// 플랫폼별 Graphics API 설정 (Android 특화)
|
||
|
|
bool SetAndroidSurface(void* native_window) override;
|
||
|
|
bool SetOpenGLESContext(void* egl_context) override;
|
||
|
|
bool SetVulkanDevice(void* vk_device, void* vk_instance) override;
|
||
|
|
|
||
|
|
// 다른 플랫폼 API는 지원하지 않음 (기본 구현)
|
||
|
|
bool SetD3DDevice(void* d3d_device, VavCoreSurfaceType type) override { return false; }
|
||
|
|
bool SetOpenGLContext(void* gl_context) override { return false; }
|
||
|
|
bool SetMetalDevice(void* metal_device) override { return false; }
|
||
|
|
|
||
|
|
// Graphics API 지원 감지 (Android 특화)
|
||
|
|
bool SupportsHardwareAcceleration() const override;
|
||
|
|
bool SupportsZeroCopyDecoding() const override;
|
||
|
|
bool RequiresExternalContext() const override;
|
||
|
|
|
||
|
|
// 디코더 상태 관리
|
||
|
|
bool Reset() override;
|
||
|
|
bool Flush() override;
|
||
|
|
|
||
|
|
// 디코더 정보
|
||
|
|
std::string GetCodecName() const override;
|
||
|
|
VideoCodecType GetCodecType() const override { return VideoCodecType::AV1; }
|
||
|
|
std::string GetVersion() const override;
|
||
|
|
|
||
|
|
// 성능 및 통계
|
||
|
|
DecoderStats GetStats() const override;
|
||
|
|
void ResetStats() override;
|
||
|
|
|
||
|
|
// Android 레거시 호환성 (legacy)
|
||
|
|
bool SetSurface(ANativeWindow* surface); // Legacy method
|
||
|
|
bool IsHardwareAccelerated() const; // Legacy method
|
||
|
|
std::string GetSelectedCodecName() const;
|
||
|
|
|
||
|
|
private:
|
||
|
|
// 초기화 및 설정
|
||
|
|
bool InitializeMediaCodec();
|
||
|
|
bool FindAV1Decoder();
|
||
|
|
AMediaCodec* CreateAV1Decoder();
|
||
|
|
bool ConfigureDecoder(const VideoMetadata& metadata);
|
||
|
|
|
||
|
|
// 처리 로직
|
||
|
|
bool ProcessInputBuffer(const uint8_t* data, size_t size);
|
||
|
|
bool ProcessOutputBuffer(VideoFrame& frame);
|
||
|
|
|
||
|
|
// 하드웨어 가속 감지 (Enhanced)
|
||
|
|
bool DetectHardwareCapabilities();
|
||
|
|
std::vector<std::string> GetAvailableCodecs();
|
||
|
|
|
||
|
|
// 로깅 (크로스 플랫폼 호환성)
|
||
|
|
void LogError(const std::string& message);
|
||
|
|
void LogInfo(const std::string& message);
|
||
|
|
void LogWarning(const std::string& message);
|
||
|
|
|
||
|
|
private:
|
||
|
|
// Core MediaCodec 객체
|
||
|
|
bool m_initialized;
|
||
|
|
AMediaCodec* m_codec;
|
||
|
|
AMediaFormat* m_format;
|
||
|
|
ANativeWindow* m_surface;
|
||
|
|
|
||
|
|
// 디코더 성능 정보
|
||
|
|
bool m_hardware_accelerated;
|
||
|
|
std::string m_selected_codec_name;
|
||
|
|
|
||
|
|
// 비디오 속성
|
||
|
|
int32_t m_width;
|
||
|
|
int32_t m_height;
|
||
|
|
|
||
|
|
// 버퍼 관리
|
||
|
|
std::vector<uint8_t> m_input_buffer;
|
||
|
|
int64_t m_timestamp_counter;
|
||
|
|
|
||
|
|
// 성능 추적 (Enhanced)
|
||
|
|
std::chrono::high_resolution_clock::time_point m_decode_start_time;
|
||
|
|
};
|
||
|
|
|
||
|
|
} // namespace VavCore
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3.2.2 Android SoC별 하드웨어 감지 로직 (Enhanced)
|
||
|
|
```cpp
|
||
|
|
bool AndroidMediaCodecAV1Decoder::DetectHardwareCapabilities() {
|
||
|
|
// ⚠️ 현실적인 Android AV1 하드웨어 디코더 식별 (2025년 기준)
|
||
|
|
// 대부분의 SoC는 AV1 하드웨어를 광고하지만 실제로는 2022년 이후에만 안정적
|
||
|
|
const char* hw_codec_prefixes[] = {
|
||
|
|
// Qualcomm Snapdragon (8 Gen 1+ 시리즈만 실제 AV1 지원)
|
||
|
|
"c2.qti.av1.decoder", // Qualcomm Codec 2.0 AV1 전용
|
||
|
|
"c2.qcom.av1.decoder", // Qualcomm 최신 AV1 전용
|
||
|
|
"OMX.qcom.video.decoder.av1", // Qualcomm OMX AV1 (레거시)
|
||
|
|
|
||
|
|
// Google Tensor (G2+ 시리즈만 - Pixel 7+)
|
||
|
|
"c2.android.av1.decoder", // Android Codec 2.0 AV1 (Google 하드웨어)
|
||
|
|
"c2.google.av1.decoder", // Google Tensor 특화 AV1
|
||
|
|
|
||
|
|
// MediaTek Dimensity (9200+ 시리즈만 - 늦은 지원)
|
||
|
|
"c2.mtk.av1.decoder", // MediaTek Codec 2.0 AV1
|
||
|
|
"OMX.MTK.VIDEO.DECODER.AV1", // MediaTek OMX AV1
|
||
|
|
|
||
|
|
// Samsung Exynos (매우 제한적 - 2200 일부만)
|
||
|
|
"c2.exynos.av1.decoder", // Samsung Exynos AV1 (제한적)
|
||
|
|
|
||
|
|
// ⚠️ 주의: 범용 프리픽스는 제외
|
||
|
|
// "OMX.qcom.", "c2.qti.", "c2.android." 등은 H.264/H.265도 포함하므로
|
||
|
|
// AV1 전용 디코더명만 검색하여 정확성 확보
|
||
|
|
|
||
|
|
nullptr
|
||
|
|
};
|
||
|
|
|
||
|
|
auto available_codecs = GetAvailableCodecs();
|
||
|
|
|
||
|
|
// 하드웨어 디코더 우선순위 검색
|
||
|
|
for (const auto& codec : available_codecs) {
|
||
|
|
for (int i = 0; hw_codec_prefixes[i] != nullptr; i++) {
|
||
|
|
if (codec.find(hw_codec_prefixes[i]) == 0) {
|
||
|
|
m_selected_codec_name = codec;
|
||
|
|
m_hardware_accelerated = true;
|
||
|
|
|
||
|
|
LogInfo("Hardware AV1 decoder detected: " + codec);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 소프트웨어 디코더로 graceful fallback
|
||
|
|
LogWarning("No hardware AV1 decoder found, will fallback to software decoder");
|
||
|
|
m_hardware_accelerated = false;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Godot 게임엔진 최적화를 위한 Surface 타입 결정
|
||
|
|
VavCoreSurfaceType AndroidMediaCodecAV1Decoder::GetOptimalSurfaceType() const {
|
||
|
|
if (!m_hardware_accelerated) {
|
||
|
|
return VAVCORE_SURFACE_CPU; // 소프트웨어 디코더는 CPU만 지원
|
||
|
|
}
|
||
|
|
|
||
|
|
// Android API Level 및 SoC별 AV1 하드웨어 지원 확인
|
||
|
|
int api_level = GetAndroidAPILevel();
|
||
|
|
std::string soc_name = GetSoCName();
|
||
|
|
|
||
|
|
// ⚠️ 중요: AV1 하드웨어 디코딩이 실제로 가능한 SoC인지 확인
|
||
|
|
if (!IsAV1HardwareCapableSoC(soc_name, api_level)) {
|
||
|
|
LogWarning("SoC does not support AV1 hardware decoding, falling back to CPU");
|
||
|
|
return VAVCORE_SURFACE_CPU;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 🎮 Godot 게임엔진 관점: 직접적인 Graphics API 통합이 최우선
|
||
|
|
// Godot 4는 Vulkan/OpenGL ES 기반 렌더링 시스템 사용
|
||
|
|
|
||
|
|
// 1. Vulkan 최우선 (Godot 4의 기본 렌더링 백엔드)
|
||
|
|
// - Godot 4 Forward+ 및 Mobile 렌더링 메서드
|
||
|
|
// - Google과 협력하여 Android Vulkan 최적화 완료
|
||
|
|
if (api_level >= 29 && IsHighEndSoC(soc_name)) { // Android 10+ 고급 SoC
|
||
|
|
if (SupportsVulkan11()) {
|
||
|
|
LogInfo("Using Vulkan image for Godot 4 optimal integration");
|
||
|
|
return VAVCORE_SURFACE_VULKAN_IMAGE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. OpenGL ES 텍스처 (Godot 4 Compatibility 렌더러)
|
||
|
|
// - Godot 4 Compatibility 렌더링 메서드 (OpenGL ES 3.0)
|
||
|
|
// - SurfaceTexture → GL_TEXTURE_EXTERNAL_OES → Godot 텍스처
|
||
|
|
// - 더 넓은 기기 호환성
|
||
|
|
if (api_level >= 21) { // Android 5.0+ (OpenGL ES 3.0)
|
||
|
|
if (SupportsOpenGLES()) {
|
||
|
|
LogInfo("Using OpenGL ES texture for Godot 4 Compatibility renderer");
|
||
|
|
return VAVCORE_SURFACE_OPENGL_ES_TEXTURE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 3. ANativeWindow (제한적 사용 - 게임엔진에 덜 적합)
|
||
|
|
// - MediaCodec Surface → ANativeWindow → Godot는 복잡한 통합 필요
|
||
|
|
// - Godot의 텍스처 시스템과 직접 연결되지 않음
|
||
|
|
// - 주로 비디오 플레이어 앱에서 사용하는 방식
|
||
|
|
if (api_level >= 18) { // MediaCodec Surface 지원 시작점
|
||
|
|
LogWarning("Using ANativeWindow - suboptimal for Godot integration");
|
||
|
|
return VAVCORE_SURFACE_ANDROID_NATIVE_WINDOW;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 4. 기본값: CPU (안전한 fallback)
|
||
|
|
LogWarning("No suitable Surface type found, falling back to CPU decoding");
|
||
|
|
return VAVCORE_SURFACE_CPU;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Godot 통합을 위한 추가 메서드들
|
||
|
|
bool AndroidMediaCodecAV1Decoder::IsOptimalForGodot() const {
|
||
|
|
VavCoreSurfaceType optimal = GetOptimalSurfaceType();
|
||
|
|
|
||
|
|
// Godot에 최적인 Surface 타입들
|
||
|
|
return (optimal == VAVCORE_SURFACE_VULKAN_IMAGE ||
|
||
|
|
optimal == VAVCORE_SURFACE_OPENGL_ES_TEXTURE);
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string AndroidMediaCodecAV1Decoder::GetGodotIntegrationInfo() const {
|
||
|
|
VavCoreSurfaceType surface_type = GetOptimalSurfaceType();
|
||
|
|
|
||
|
|
switch (surface_type) {
|
||
|
|
case VAVCORE_SURFACE_VULKAN_IMAGE:
|
||
|
|
return "Vulkan VkImage - Direct integration with Godot 4 Forward+/Mobile renderer";
|
||
|
|
|
||
|
|
case VAVCORE_SURFACE_OPENGL_ES_TEXTURE:
|
||
|
|
return "OpenGL ES GL_TEXTURE_EXTERNAL_OES - Direct integration with Godot 4 Compatibility renderer";
|
||
|
|
|
||
|
|
case VAVCORE_SURFACE_ANDROID_NATIVE_WINDOW:
|
||
|
|
return "ANativeWindow - Requires additional conversion for Godot texture system";
|
||
|
|
|
||
|
|
case VAVCORE_SURFACE_CPU:
|
||
|
|
return "CPU memory - Software decoding, universally compatible but slower";
|
||
|
|
|
||
|
|
default:
|
||
|
|
return "Unknown surface type";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 실제 AV1 하드웨어 지원 SoC 검증 (현실적인 출시 시점 고려)
|
||
|
|
bool AndroidMediaCodecAV1Decoder::IsAV1HardwareCapableSoC(const std::string& soc_name, int api_level) const {
|
||
|
|
// ⚠️ 현실: 대부분의 Android SoC는 2022년 이후에야 실제 AV1 하드웨어 지원
|
||
|
|
|
||
|
|
// Qualcomm Snapdragon (8 Gen 1+ 시리즈만 확실한 지원)
|
||
|
|
if (soc_name.find("sm8450") != std::string::npos || // 8 Gen 1 (2022)
|
||
|
|
soc_name.find("sm8475") != std::string::npos || // 8+ Gen 1 (2022)
|
||
|
|
soc_name.find("sm8550") != std::string::npos || // 8 Gen 2 (2023)
|
||
|
|
soc_name.find("sm8650") != std::string::npos) { // 8 Gen 3 (2024)
|
||
|
|
return api_level >= 31; // Android 12+ 필요
|
||
|
|
}
|
||
|
|
|
||
|
|
// Google Tensor (G2+ 시리즈만 - Pixel 7+)
|
||
|
|
if (soc_name.find("gs201") != std::string::npos || // Tensor G2 (Pixel 7, 2022)
|
||
|
|
soc_name.find("gs301") != std::string::npos) { // Tensor G3 (Pixel 8, 2023)
|
||
|
|
return api_level >= 31; // Android 12+ 필요
|
||
|
|
}
|
||
|
|
|
||
|
|
// MediaTek Dimensity (9200+ 시리즈만 - 늦은 지원)
|
||
|
|
if (soc_name.find("mt6985") != std::string::npos || // Dimensity 9200 (2023)
|
||
|
|
soc_name.find("mt6989") != std::string::npos) { // Dimensity 9300 (2024)
|
||
|
|
return api_level >= 33; // Android 13+ 필요 (MediaTek 늦은 지원)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Samsung Exynos (매우 제한적 지원 - 2200 일부만)
|
||
|
|
if (soc_name.find("s5e9925") != std::string::npos) { // Exynos 2200 (Galaxy S22)
|
||
|
|
// Exynos 2200은 AV1 하드웨어가 있지만 성능 이슈로 제한적 활용
|
||
|
|
LogWarning("Exynos 2200 AV1 hardware support is limited and unstable");
|
||
|
|
return api_level >= 32; // Android 12L+ 필요
|
||
|
|
}
|
||
|
|
|
||
|
|
// 기타 모든 SoC는 AV1 하드웨어 디코딩 미지원으로 간주
|
||
|
|
LogWarning("SoC " + soc_name + " not in confirmed AV1 hardware support list");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool AndroidMediaCodecAV1Decoder::IsHighEndSoC(const std::string& soc_name) const {
|
||
|
|
// Snapdragon 8 series
|
||
|
|
if (soc_name.find("sm84") != std::string::npos || soc_name.find("sm86") != std::string::npos) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
// Google Tensor
|
||
|
|
if (soc_name.find("gs") != std::string::npos) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
// MediaTek Dimensity 9xxx series
|
||
|
|
if (soc_name.find("mt698") != std::string::npos) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3.2.3 크로스 플랫폼 Surface 기반 디코딩 (Enhanced)
|
||
|
|
```cpp
|
||
|
|
bool AndroidMediaCodecAV1Decoder::DecodeToSurface(const uint8_t* packet_data, size_t packet_size,
|
||
|
|
VavCoreSurfaceType target_type,
|
||
|
|
void* target_surface,
|
||
|
|
VideoFrame& output_frame) {
|
||
|
|
if (!m_initialized || !m_hardware_accelerated) {
|
||
|
|
LogError("AndroidMediaCodec decoder not initialized or hardware not available");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Android에서 지원하는 Surface 타입 검증
|
||
|
|
if (!SupportsSurfaceType(target_type)) {
|
||
|
|
LogError("Unsupported surface type for Android MediaCodec: " + std::to_string(target_type));
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Surface 타입별 처리
|
||
|
|
switch (target_type) {
|
||
|
|
case VAVCORE_SURFACE_ANDROID_NATIVE_WINDOW: {
|
||
|
|
auto* native_window = static_cast<ANativeWindow*>(target_surface);
|
||
|
|
if (!SetAndroidSurface(native_window)) {
|
||
|
|
LogError("Failed to set Android native window");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case VAVCORE_SURFACE_OPENGL_ES_TEXTURE: {
|
||
|
|
// OpenGL ES 텍스처로 직접 렌더링
|
||
|
|
// EGL 컨텍스트와 텍스처 ID가 필요
|
||
|
|
if (!m_opengl_es_context) {
|
||
|
|
LogError("OpenGL ES context not set for texture rendering");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case VAVCORE_SURFACE_VULKAN_IMAGE: {
|
||
|
|
// Vulkan 이미지로 직접 렌더링
|
||
|
|
// VkDevice와 VkImage가 필요
|
||
|
|
if (!m_vulkan_device) {
|
||
|
|
LogError("Vulkan device not set for image rendering");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case VAVCORE_SURFACE_ANDROID_HARDWARE_BUFFER: {
|
||
|
|
// AHardwareBuffer로 직접 렌더링
|
||
|
|
auto* hardware_buffer = static_cast<AHardwareBuffer*>(target_surface);
|
||
|
|
if (!SetHardwareBuffer(hardware_buffer)) {
|
||
|
|
LogError("Failed to set Android hardware buffer");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
default:
|
||
|
|
LogError("Surface type not supported by Android MediaCodec");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 입력 버퍼 처리
|
||
|
|
if (!ProcessInputBuffer(packet_data, packet_size)) {
|
||
|
|
LogError("Failed to process input buffer");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Zero-copy: 출력이 하드웨어 Surface로 직접 렌더링됨
|
||
|
|
// CPU 메모리 복사 없이 GPU-to-GPU 직접 전송
|
||
|
|
output_frame.surface_type = target_type;
|
||
|
|
output_frame.surface_data.android_native.native_window = target_surface;
|
||
|
|
output_frame.timestamp_us = m_timestamp_counter++;
|
||
|
|
|
||
|
|
// 성능 통계 업데이트
|
||
|
|
IncrementFramesDecoded();
|
||
|
|
UpdateDecodeTime(CalculateDecodeTime());
|
||
|
|
|
||
|
|
LogInfo("Frame decoded directly to Android surface (zero-copy)");
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Android AV1 하드웨어 현실을 반영한 Surface 타입 지원 감지
|
||
|
|
bool AndroidMediaCodecAV1Decoder::SupportsSurfaceType(VavCoreSurfaceType type) const {
|
||
|
|
int api_level = GetAndroidAPILevel();
|
||
|
|
std::string soc_name = GetSoCName();
|
||
|
|
|
||
|
|
switch (type) {
|
||
|
|
case VAVCORE_SURFACE_CPU:
|
||
|
|
return true; // 모든 Android 기기에서 지원 (소프트웨어 dav1d)
|
||
|
|
|
||
|
|
case VAVCORE_SURFACE_ANDROID_NATIVE_WINDOW:
|
||
|
|
// MediaCodec Surface 디코딩: API 18+에서 지원, AV1은 API 29+ 실용적
|
||
|
|
if (api_level >= 18 && m_hardware_accelerated) {
|
||
|
|
return IsAV1HardwareCapableSoC(soc_name, api_level);
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
|
||
|
|
case VAVCORE_SURFACE_OPENGL_ES_TEXTURE:
|
||
|
|
// OpenGL ES 텍스처: 복잡한 MediaCodec 통합, 고급 SoC에서만 권장
|
||
|
|
if (api_level >= 29 && m_hardware_accelerated && IsHighEndSoC(soc_name)) {
|
||
|
|
return SupportsOpenGLES() && IsAV1HardwareCapableSoC(soc_name, api_level);
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
|
||
|
|
case VAVCORE_SURFACE_VULKAN_IMAGE:
|
||
|
|
// Vulkan: API 24+에서 지원, AV1과 함께는 API 29+ 고급 SoC만
|
||
|
|
if (api_level >= 29 && m_hardware_accelerated && IsHighEndSoC(soc_name)) {
|
||
|
|
return SupportsVulkan11() && IsAV1HardwareCapableSoC(soc_name, api_level);
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
|
||
|
|
case VAVCORE_SURFACE_ANDROID_HARDWARE_BUFFER:
|
||
|
|
// AHardwareBuffer: API 26+에서 지원, AV1과 함께는 API 31+ 권장
|
||
|
|
if (api_level >= 31 && m_hardware_accelerated && IsHighEndSoC(soc_name)) {
|
||
|
|
return SupportsHardwareBuffer() && IsAV1HardwareCapableSoC(soc_name, api_level);
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// Android에서 지원하지 않는 플랫폼별 Surface 타입들
|
||
|
|
case VAVCORE_SURFACE_D3D11_TEXTURE:
|
||
|
|
case VAVCORE_SURFACE_D3D12_RESOURCE:
|
||
|
|
case VAVCORE_SURFACE_CUDA_DEVICE:
|
||
|
|
case VAVCORE_SURFACE_AMF_SURFACE:
|
||
|
|
case VAVCORE_SURFACE_OPENGL_TEXTURE: // Desktop OpenGL (Android는 ES만)
|
||
|
|
case VAVCORE_SURFACE_METAL_TEXTURE:
|
||
|
|
case VAVCORE_SURFACE_COREVIDEO_PIXELBUFFER:
|
||
|
|
return false;
|
||
|
|
|
||
|
|
default:
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Android API 및 Graphics API 지원 검증 메서드들
|
||
|
|
bool AndroidMediaCodecAV1Decoder::SupportsOpenGLES() const {
|
||
|
|
// OpenGL ES는 모든 Android 기기에서 지원하지만,
|
||
|
|
// MediaCodec과의 복잡한 통합은 고급 기기에서만 안정적
|
||
|
|
return GetAndroidAPILevel() >= 21; // Android 5.0+ (OpenGL ES 3.0)
|
||
|
|
}
|
||
|
|
|
||
|
|
bool AndroidMediaCodecAV1Decoder::SupportsVulkan11() const {
|
||
|
|
// Vulkan 1.1은 API 29+에서 모든 64비트 기기에서 보장
|
||
|
|
return GetAndroidAPILevel() >= 29;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool AndroidMediaCodecAV1Decoder::SupportsHardwareBuffer() const {
|
||
|
|
// AHardwareBuffer는 API 26+에서 지원, 완전한 기능은 API 31+
|
||
|
|
return GetAndroidAPILevel() >= 31;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.3 Enhanced VideoDecoderFactory 크로스 플랫폼 통합
|
||
|
|
|
||
|
|
#### 3.3.1 크로스 플랫폼 디코더 등록 및 우선순위
|
||
|
|
```cpp
|
||
|
|
// VideoDecoderFactory에서 플랫폼별 디코더 자동 등록
|
||
|
|
void VideoDecoderFactory::RegisterAV1Decoders() {
|
||
|
|
// Windows 하드웨어 디코더들
|
||
|
|
#ifdef VAVCORE_PLATFORM_WINDOWS
|
||
|
|
RegisterDecoder(VideoCodecType::AV1, DecoderType::NVDEC,
|
||
|
|
[]() -> std::unique_ptr<IVideoDecoder> {
|
||
|
|
return std::make_unique<NVDECAV1Decoder>();
|
||
|
|
}, 400); // 최고 우선순위
|
||
|
|
|
||
|
|
RegisterDecoder(VideoCodecType::AV1, DecoderType::VPL,
|
||
|
|
[]() -> std::unique_ptr<IVideoDecoder> {
|
||
|
|
return std::make_unique<VPLAV1Decoder>();
|
||
|
|
}, 300);
|
||
|
|
|
||
|
|
RegisterDecoder(VideoCodecType::AV1, DecoderType::AMF,
|
||
|
|
[]() -> std::unique_ptr<IVideoDecoder> {
|
||
|
|
return std::make_unique<AMFAV1Decoder>();
|
||
|
|
}, 200);
|
||
|
|
|
||
|
|
RegisterDecoder(VideoCodecType::AV1, DecoderType::MEDIA_FOUNDATION,
|
||
|
|
[]() -> std::unique_ptr<IVideoDecoder> {
|
||
|
|
return std::make_unique<MediaFoundationAV1Decoder>();
|
||
|
|
}, 50);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// Android 하드웨어 디코더
|
||
|
|
#ifdef VAVCORE_PLATFORM_ANDROID
|
||
|
|
RegisterDecoder(VideoCodecType::AV1, DecoderType::MEDIACODEC,
|
||
|
|
[]() -> std::unique_ptr<IVideoDecoder> {
|
||
|
|
return std::make_unique<AndroidMediaCodecAV1Decoder>();
|
||
|
|
}, 400); // Android에서 최고 우선순위
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// 크로스 플랫폼 소프트웨어 디코더 (모든 플랫폼에서 fallback)
|
||
|
|
RegisterDecoder(VideoCodecType::AV1, DecoderType::DAV1D,
|
||
|
|
[]() -> std::unique_ptr<IVideoDecoder> {
|
||
|
|
return std::make_unique<AV1Decoder>();
|
||
|
|
}, 10); // 최하위 우선순위 (안전한 fallback)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Enhanced AUTO 디코더 선택 로직
|
||
|
|
std::unique_ptr<IVideoDecoder> VideoDecoderFactory::CreateDecoder(VideoCodecType codec_type,
|
||
|
|
DecoderType type) {
|
||
|
|
switch (type) {
|
||
|
|
case DecoderType::AUTO: {
|
||
|
|
// 플랫폼별 최적 디코더 자동 선택
|
||
|
|
auto decoders = GetSortedDecoders(codec_type); // 우선순위 순서로 정렬
|
||
|
|
|
||
|
|
for (const auto& decoder_factory : decoders) {
|
||
|
|
auto decoder = decoder_factory.create();
|
||
|
|
|
||
|
|
// 하드웨어 가용성 미리 확인
|
||
|
|
if (decoder->SupportsHardwareAcceleration()) {
|
||
|
|
if (decoder->Initialize(GetDummyMetadata())) {
|
||
|
|
decoder->Cleanup(); // 테스트 후 정리
|
||
|
|
LogInfo("Selected hardware decoder: " + decoder->GetCodecName());
|
||
|
|
return decoder_factory.create(); // 새 인스턴스 생성
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 모든 하드웨어 디코더 실패 시 소프트웨어 fallback
|
||
|
|
LogWarning("All hardware decoders failed, using software decoder");
|
||
|
|
return CreateDecoder(codec_type, DecoderType::DAV1D);
|
||
|
|
}
|
||
|
|
|
||
|
|
case DecoderType::MEDIACODEC:
|
||
|
|
#ifdef VAVCORE_PLATFORM_ANDROID
|
||
|
|
return std::make_unique<AndroidMediaCodecAV1Decoder>();
|
||
|
|
#else
|
||
|
|
LogError("MediaCodec decoder not available on this platform");
|
||
|
|
return nullptr;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
case DecoderType::NVDEC:
|
||
|
|
#ifdef VAVCORE_PLATFORM_WINDOWS
|
||
|
|
return std::make_unique<NVDECAV1Decoder>();
|
||
|
|
#else
|
||
|
|
LogError("NVDEC decoder not available on this platform");
|
||
|
|
return nullptr;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
case DecoderType::DAV1D:
|
||
|
|
return std::make_unique<AV1Decoder>(); // 모든 플랫폼에서 사용 가능
|
||
|
|
|
||
|
|
default:
|
||
|
|
LogError("Unknown decoder type requested");
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.4 Enhanced 크로스 플랫폼 빌드 시스템
|
||
|
|
|
||
|
|
#### 3.4.1 완전한 CMakeLists.txt 구조 (모든 플랫폼 지원)
|
||
|
|
```cmake
|
||
|
|
cmake_minimum_required(VERSION 3.22)
|
||
|
|
project(VavCore)
|
||
|
|
|
||
|
|
# 플랫폼별 소스 파일 및 라이브러리 설정
|
||
|
|
if(ANDROID)
|
||
|
|
# Android 플랫폼
|
||
|
|
set(PLATFORM_SOURCES
|
||
|
|
src/Decoder/AndroidMediaCodecAV1Decoder.cpp
|
||
|
|
src/Platform/AndroidSurface.cpp
|
||
|
|
src/Platform/AndroidGraphicsAPI.cpp
|
||
|
|
)
|
||
|
|
set(PLATFORM_LIBRARIES
|
||
|
|
mediandk # Android MediaCodec NDK
|
||
|
|
android # Android 네이티브 라이브러리
|
||
|
|
log # Android 로깅
|
||
|
|
EGL # OpenGL ES 컨텍스트
|
||
|
|
GLESv2 # OpenGL ES 2.0
|
||
|
|
vulkan # Vulkan API (Android 7.0+)
|
||
|
|
)
|
||
|
|
set(PLATFORM_INCLUDES
|
||
|
|
${ANDROID_NDK}/sources/android/native_app_glue
|
||
|
|
)
|
||
|
|
add_definitions(-DVAVCORE_PLATFORM_ANDROID)
|
||
|
|
|
||
|
|
elseif(WIN32)
|
||
|
|
# Windows 플랫폼
|
||
|
|
set(PLATFORM_SOURCES
|
||
|
|
src/Decoder/NVDECAV1Decoder.cpp
|
||
|
|
src/Decoder/AMFAV1Decoder.cpp
|
||
|
|
src/Decoder/VPLAV1Decoder.cpp
|
||
|
|
src/Decoder/MediaFoundationAV1Decoder.cpp
|
||
|
|
src/Platform/WindowsD3D.cpp
|
||
|
|
src/Platform/WindowsCUDA.cpp
|
||
|
|
)
|
||
|
|
set(PLATFORM_LIBRARIES
|
||
|
|
d3d11
|
||
|
|
d3d12
|
||
|
|
dxgi
|
||
|
|
mfplat
|
||
|
|
mfreadwrite
|
||
|
|
mftransform
|
||
|
|
# CUDA 라이브러리들 (옵션)
|
||
|
|
cuda
|
||
|
|
cudart
|
||
|
|
# AMD AMF 라이브러리들 (옵션)
|
||
|
|
amf
|
||
|
|
# Intel VPL 라이브러리들 (옵션)
|
||
|
|
vpl
|
||
|
|
)
|
||
|
|
add_definitions(-DVAVCORE_PLATFORM_WINDOWS)
|
||
|
|
|
||
|
|
elseif(APPLE)
|
||
|
|
# macOS/iOS 플랫폼
|
||
|
|
set(PLATFORM_SOURCES
|
||
|
|
src/Decoder/VideoToolboxAV1Decoder.cpp # 미래 확장
|
||
|
|
src/Platform/AppleMetal.cpp
|
||
|
|
src/Platform/AppleCoreVideo.cpp
|
||
|
|
)
|
||
|
|
set(PLATFORM_LIBRARIES
|
||
|
|
"-framework Metal"
|
||
|
|
"-framework CoreVideo"
|
||
|
|
"-framework VideoToolbox"
|
||
|
|
"-framework Foundation"
|
||
|
|
)
|
||
|
|
add_definitions(-DVAVCORE_PLATFORM_APPLE)
|
||
|
|
|
||
|
|
else()
|
||
|
|
# Linux 플랫폼 (기본값)
|
||
|
|
set(PLATFORM_SOURCES
|
||
|
|
src/Platform/LinuxOpenGL.cpp
|
||
|
|
src/Platform/LinuxVulkan.cpp
|
||
|
|
)
|
||
|
|
set(PLATFORM_LIBRARIES
|
||
|
|
GL # OpenGL
|
||
|
|
vulkan # Vulkan
|
||
|
|
X11 # X11 윈도우 시스템
|
||
|
|
)
|
||
|
|
add_definitions(-DVAVCORE_PLATFORM_LINUX)
|
||
|
|
endif()
|
||
|
|
|
||
|
|
# 크로스 플랫폼 공통 소스
|
||
|
|
set(COMMON_SOURCES
|
||
|
|
# Core 디코더 인터페이스
|
||
|
|
src/Decoder/IVideoDecoder.cpp
|
||
|
|
src/Decoder/VideoDecoderFactory.cpp
|
||
|
|
src/Decoder/AV1Decoder.cpp # dav1d 소프트웨어 디코더
|
||
|
|
|
||
|
|
# 공통 타입 및 유틸리티
|
||
|
|
src/Common/VideoTypes.cpp
|
||
|
|
src/Common/SurfaceTypes.cpp
|
||
|
|
src/Common/PlatformUtils.cpp
|
||
|
|
|
||
|
|
# 파일 I/O (크로스 플랫폼)
|
||
|
|
src/FileIO/IWebMFileReader.cpp
|
||
|
|
src/FileIO/WebMFileReader.cpp
|
||
|
|
|
||
|
|
# C API 래퍼
|
||
|
|
src/VavCore.cpp
|
||
|
|
)
|
||
|
|
|
||
|
|
# VavCore 정적 라이브러리 생성
|
||
|
|
add_library(VavCore STATIC
|
||
|
|
${COMMON_SOURCES}
|
||
|
|
${PLATFORM_SOURCES}
|
||
|
|
)
|
||
|
|
|
||
|
|
# 헤더 파일 경로 설정
|
||
|
|
target_include_directories(VavCore
|
||
|
|
PUBLIC
|
||
|
|
include/ # Public API 헤더
|
||
|
|
PRIVATE
|
||
|
|
src/ # 내부 구현 헤더
|
||
|
|
${PLATFORM_INCLUDES}
|
||
|
|
)
|
||
|
|
|
||
|
|
# 라이브러리 링크
|
||
|
|
target_link_libraries(VavCore
|
||
|
|
${PLATFORM_LIBRARIES}
|
||
|
|
dav1d # 크로스 플랫폼 소프트웨어 디코더
|
||
|
|
webm # libwebm 파서 라이브러리
|
||
|
|
)
|
||
|
|
|
||
|
|
# 컴파일러 플래그 설정
|
||
|
|
target_compile_features(VavCore PRIVATE cxx_std_17)
|
||
|
|
target_compile_definitions(VavCore PRIVATE
|
||
|
|
VAVCORE_VERSION_MAJOR=3
|
||
|
|
VAVCORE_VERSION_MINOR=0
|
||
|
|
VAVCORE_VERSION_PATCH=0
|
||
|
|
)
|
||
|
|
|
||
|
|
# 플랫폼별 추가 설정
|
||
|
|
if(ANDROID)
|
||
|
|
# Android NDK 설정
|
||
|
|
target_compile_options(VavCore PRIVATE
|
||
|
|
-fPIC
|
||
|
|
-Wall
|
||
|
|
-Wextra
|
||
|
|
-O2
|
||
|
|
)
|
||
|
|
elseif(WIN32)
|
||
|
|
# Windows MSVC 설정
|
||
|
|
target_compile_options(VavCore PRIVATE
|
||
|
|
/W4
|
||
|
|
/O2
|
||
|
|
/DWIN32_LEAN_AND_MEAN
|
||
|
|
)
|
||
|
|
endif()
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3.4.2 Enhanced Android Gradle 통합 (모든 Graphics API 지원)
|
||
|
|
```gradle
|
||
|
|
android {
|
||
|
|
namespace 'com.vavcore'
|
||
|
|
compileSdk 34
|
||
|
|
|
||
|
|
externalNativeBuild {
|
||
|
|
cmake {
|
||
|
|
path "CMakeLists.txt"
|
||
|
|
version "3.22.1"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
defaultConfig {
|
||
|
|
minSdk 21 // Android 5.0+ (OpenGL ES 3.0 지원)
|
||
|
|
targetSdk 34
|
||
|
|
|
||
|
|
ndk {
|
||
|
|
// 현대적인 ARM 아키텍처 지원
|
||
|
|
abiFilters 'arm64-v8a', 'armeabi-v7a'
|
||
|
|
}
|
||
|
|
|
||
|
|
externalNativeBuild {
|
||
|
|
cmake {
|
||
|
|
cppFlags "-std=c++17 -DVAVCORE_PLATFORM_ANDROID -DANDROID_STL=c++_shared"
|
||
|
|
arguments "-DANDROID_ARM_NEON=TRUE",
|
||
|
|
"-DANDROID_TOOLCHAIN=clang",
|
||
|
|
"-DCMAKE_BUILD_TYPE=Release"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
buildTypes {
|
||
|
|
debug {
|
||
|
|
debuggable true
|
||
|
|
externalNativeBuild {
|
||
|
|
cmake {
|
||
|
|
cppFlags "-DVAVCORE_DEBUG -g"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
release {
|
||
|
|
minifyEnabled false
|
||
|
|
externalNativeBuild {
|
||
|
|
cmake {
|
||
|
|
cppFlags "-DNDEBUG -O3"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Vulkan API 지원 설정 (Android 7.0+)
|
||
|
|
defaultConfig {
|
||
|
|
externalNativeBuild {
|
||
|
|
cmake {
|
||
|
|
cppFlags "-DVAVCORE_VULKAN_SUPPORT"
|
||
|
|
arguments "-DVULKAN_ANDROID=1"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
dependencies {
|
||
|
|
// Android Graphics API들은 프레임워크 일부이므로 추가 의존성 불필요
|
||
|
|
// - MediaCodec: Android 프레임워크
|
||
|
|
// - OpenGL ES: Android 프레임워크
|
||
|
|
// - Vulkan: Android 7.0+ 프레임워크
|
||
|
|
// - EGL: Android 프레임워크
|
||
|
|
|
||
|
|
// 필요시 추가할 수 있는 외부 라이브러리들
|
||
|
|
// implementation 'androidx.core:core:1.10.1' // AHardwareBuffer 지원
|
||
|
|
// implementation 'androidx.opengl:opengl:1.0.0' // OpenGL 유틸리티
|
||
|
|
}
|
||
|
|
|
||
|
|
// NDK 빌드 최적화 설정
|
||
|
|
android.packagingOptions {
|
||
|
|
pickFirst '**/libvavcore.so'
|
||
|
|
pickFirst '**/libdav1d.so'
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 4. Enhanced 크로스 플랫폼 코드베이스 통합
|
||
|
|
|
||
|
|
### 4.1 완전한 역호환성과 플랫폼 투명성
|
||
|
|
Enhanced 설계는 기존 코드와 100% 역호환성을 유지하면서 모든 플랫폼을 투명하게 지원합니다:
|
||
|
|
|
||
|
|
```cpp
|
||
|
|
// 기존 코드는 전혀 변경 없이 모든 플랫폼에서 동작
|
||
|
|
auto decoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::AUTO);
|
||
|
|
decoder->Initialize(metadata);
|
||
|
|
decoder->DecodeFrame(packet_data, packet_size, frame);
|
||
|
|
|
||
|
|
// 플랫폼별 자동 최적화:
|
||
|
|
// - Windows: NVDEC → VPL → AMF → dav1d → Media Foundation
|
||
|
|
// - Android: MediaCodec (하드웨어) → dav1d (소프트웨어)
|
||
|
|
// - macOS/iOS: VideoToolbox → dav1d (미래 확장)
|
||
|
|
// - Linux: dav1d
|
||
|
|
|
||
|
|
// Enhanced Surface 기반 디코딩 (플랫폼 투명)
|
||
|
|
if (decoder->SupportsSurfaceType(target_surface_type)) {
|
||
|
|
decoder->DecodeToSurface(packet_data, packet_size, target_surface_type, surface, frame);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.2 크로스 플랫폼 로깅 시스템 (Enhanced)
|
||
|
|
```cpp
|
||
|
|
namespace VavCore {
|
||
|
|
|
||
|
|
class PlatformLogger {
|
||
|
|
public:
|
||
|
|
static void LogError(const std::string& message) {
|
||
|
|
#ifdef VAVCORE_PLATFORM_ANDROID
|
||
|
|
__android_log_print(ANDROID_LOG_ERROR, "VavCore", "%s", message.c_str());
|
||
|
|
#elif defined(VAVCORE_PLATFORM_WINDOWS)
|
||
|
|
OutputDebugStringA(("VavCore Error: " + message + "\n").c_str());
|
||
|
|
#elif defined(VAVCORE_PLATFORM_APPLE)
|
||
|
|
NSLog(@"VavCore Error: %s", message.c_str());
|
||
|
|
#else
|
||
|
|
std::cerr << "VavCore Error: " << message << std::endl;
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
static void LogInfo(const std::string& message) {
|
||
|
|
#ifdef VAVCORE_PLATFORM_ANDROID
|
||
|
|
__android_log_print(ANDROID_LOG_INFO, "VavCore", "%s", message.c_str());
|
||
|
|
#elif defined(VAVCORE_PLATFORM_WINDOWS)
|
||
|
|
OutputDebugStringA(("VavCore Info: " + message + "\n").c_str());
|
||
|
|
#elif defined(VAVCORE_PLATFORM_APPLE)
|
||
|
|
NSLog(@"VavCore Info: %s", message.c_str());
|
||
|
|
#else
|
||
|
|
std::cout << "VavCore Info: " << message << std::endl;
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
} // namespace VavCore
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.3 Enhanced Godot 게임엔진 최적화 통합
|
||
|
|
|
||
|
|
#### 4.3.1 Godot 4 렌더링 아키텍처와 VavCore 통합
|
||
|
|
**Godot 4는 2024년 기준 다음과 같은 렌더링 백엔드를 사용:**
|
||
|
|
- **Vulkan**: Forward+ 및 Mobile 렌더링 메서드 (주력)
|
||
|
|
- **OpenGL ES 3.0**: Compatibility 렌더링 메서드 (호환성)
|
||
|
|
- **Google 협력**: Android Vulkan 최적화 완료
|
||
|
|
|
||
|
|
**VavCore Surface 타입별 Godot 통합 방식:**
|
||
|
|
|
||
|
|
```cpp
|
||
|
|
// Godot 4 Vulkan 렌더러 통합 (최우선)
|
||
|
|
bool IntegrateWithGodotVulkan(VkImage vk_image, VkDevice vk_device) {
|
||
|
|
// 1. MediaCodec → Vulkan VkImage 직접 디코딩
|
||
|
|
auto decoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::AUTO);
|
||
|
|
|
||
|
|
if (decoder->SupportsSurfaceType(VAVCORE_SURFACE_VULKAN_IMAGE)) {
|
||
|
|
// 2. Godot Vulkan 렌더링 디바이스와 직접 연결
|
||
|
|
decoder->SetVulkanDevice(vk_device, vk_instance);
|
||
|
|
|
||
|
|
// 3. Zero-copy: MediaCodec → VkImage → Godot 텍스처
|
||
|
|
VideoFrame output_frame;
|
||
|
|
bool success = decoder->DecodeToSurface(
|
||
|
|
packet_data, packet_size,
|
||
|
|
VAVCORE_SURFACE_VULKAN_IMAGE,
|
||
|
|
vk_image,
|
||
|
|
output_frame
|
||
|
|
);
|
||
|
|
|
||
|
|
// 4. Godot에서 VkImage를 텍스처로 직접 사용
|
||
|
|
// RenderingDevice.texture_create_from_extension() 활용
|
||
|
|
return success;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Godot 4 OpenGL ES Compatibility 렌더러 통합
|
||
|
|
bool IntegrateWithGodotOpenGLES(GLuint texture_id, EGLContext egl_context) {
|
||
|
|
// 1. MediaCodec → SurfaceTexture → GL_TEXTURE_EXTERNAL_OES
|
||
|
|
auto decoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::AUTO);
|
||
|
|
|
||
|
|
if (decoder->SupportsSurfaceType(VAVCORE_SURFACE_OPENGL_ES_TEXTURE)) {
|
||
|
|
// 2. Godot OpenGL ES 컨텍스트와 연결
|
||
|
|
decoder->SetOpenGLESContext(egl_context);
|
||
|
|
|
||
|
|
// 3. SurfaceTexture 생성 (JNI를 통해)
|
||
|
|
SurfaceTexture* surface_texture = CreateSurfaceTexture(texture_id);
|
||
|
|
ANativeWindow* native_window = CreateNativeWindowFromSurfaceTexture(surface_texture);
|
||
|
|
|
||
|
|
// 4. MediaCodec → SurfaceTexture → Godot GL 텍스처
|
||
|
|
VideoFrame output_frame;
|
||
|
|
bool success = decoder->DecodeToSurface(
|
||
|
|
packet_data, packet_size,
|
||
|
|
VAVCORE_SURFACE_OPENGL_ES_TEXTURE,
|
||
|
|
native_window,
|
||
|
|
output_frame
|
||
|
|
);
|
||
|
|
|
||
|
|
// 5. updateTexImage() 호출 후 Godot에서 텍스처 사용
|
||
|
|
return success;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 4.3.2 Godot Android 플러그인 구조
|
||
|
|
```cpp
|
||
|
|
// Godot Android VavCore 플러그인 (JNI 인터페이스)
|
||
|
|
extern "C" {
|
||
|
|
// 디코더 생성 및 초기화
|
||
|
|
JNIEXPORT jlong JNICALL
|
||
|
|
Java_org_godotengine_plugin_vavcore_VavCorePlugin_createDecoder(JNIEnv* env, jclass clazz) {
|
||
|
|
auto decoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::AUTO);
|
||
|
|
return reinterpret_cast<jlong>(decoder.release());
|
||
|
|
}
|
||
|
|
|
||
|
|
// Godot 렌더링 백엔드별 최적화 설정
|
||
|
|
JNIEXPORT jint JNICALL
|
||
|
|
Java_org_godotengine_plugin_vavcore_VavCorePlugin_getOptimalSurfaceType(
|
||
|
|
JNIEnv* env, jclass clazz, jlong decoder_ptr) {
|
||
|
|
|
||
|
|
auto* decoder = reinterpret_cast<AndroidMediaCodecAV1Decoder*>(decoder_ptr);
|
||
|
|
return static_cast<jint>(decoder->GetOptimalSurfaceType());
|
||
|
|
}
|
||
|
|
|
||
|
|
// Vulkan 렌더러 통합 (Godot 4 Forward+/Mobile)
|
||
|
|
JNIEXPORT jboolean JNICALL
|
||
|
|
Java_org_godotengine_plugin_vavcore_VavCorePlugin_setupVulkanIntegration(
|
||
|
|
JNIEnv* env, jclass clazz, jlong decoder_ptr,
|
||
|
|
jlong vk_device, jlong vk_instance) {
|
||
|
|
|
||
|
|
auto* decoder = reinterpret_cast<AndroidMediaCodecAV1Decoder*>(decoder_ptr);
|
||
|
|
|
||
|
|
bool success = decoder->SetVulkanDevice(
|
||
|
|
reinterpret_cast<void*>(vk_device),
|
||
|
|
reinterpret_cast<void*>(vk_instance)
|
||
|
|
);
|
||
|
|
|
||
|
|
return success ? JNI_TRUE : JNI_FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
// OpenGL ES 렌더러 통합 (Godot 4 Compatibility)
|
||
|
|
JNIEXPORT jboolean JNICALL
|
||
|
|
Java_org_godotengine_plugin_vavcore_VavCorePlugin_setupOpenGLESIntegration(
|
||
|
|
JNIEnv* env, jclass clazz, jlong decoder_ptr,
|
||
|
|
jobject surface_texture) {
|
||
|
|
|
||
|
|
auto* decoder = reinterpret_cast<AndroidMediaCodecAV1Decoder*>(decoder_ptr);
|
||
|
|
|
||
|
|
// SurfaceTexture → ANativeWindow 변환
|
||
|
|
ANativeWindow* native_window = ANativeWindow_fromSurface(env, surface_texture);
|
||
|
|
if (!native_window) {
|
||
|
|
return JNI_FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool success = decoder->SetAndroidSurface(native_window);
|
||
|
|
ANativeWindow_release(native_window);
|
||
|
|
|
||
|
|
return success ? JNI_TRUE : JNI_FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 프레임 디코딩 (Godot 텍스처로 직접 출력)
|
||
|
|
JNIEXPORT jboolean JNICALL
|
||
|
|
Java_org_godotengine_plugin_vavcore_VavCorePlugin_decodeFrameToTexture(
|
||
|
|
JNIEnv* env, jclass clazz, jlong decoder_ptr,
|
||
|
|
jbyteArray packet_data, jlong texture_handle) {
|
||
|
|
|
||
|
|
auto* decoder = reinterpret_cast<AndroidMediaCodecAV1Decoder*>(decoder_ptr);
|
||
|
|
|
||
|
|
// JNI 바이트 배열 → 네이티브 포인터
|
||
|
|
jbyte* data = env->GetByteArrayElements(packet_data, nullptr);
|
||
|
|
jsize size = env->GetArrayLength(packet_data);
|
||
|
|
|
||
|
|
VavCoreSurfaceType surface_type = decoder->GetOptimalSurfaceType();
|
||
|
|
void* target_surface = reinterpret_cast<void*>(texture_handle);
|
||
|
|
VideoFrame output_frame;
|
||
|
|
|
||
|
|
bool success = decoder->DecodeToSurface(
|
||
|
|
reinterpret_cast<const uint8_t*>(data),
|
||
|
|
static_cast<size_t>(size),
|
||
|
|
surface_type,
|
||
|
|
target_surface,
|
||
|
|
output_frame
|
||
|
|
);
|
||
|
|
|
||
|
|
env->ReleaseByteArrayElements(packet_data, data, JNI_ABORT);
|
||
|
|
return success ? JNI_TRUE : JNI_FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Godot 통합 상태 정보
|
||
|
|
JNIEXPORT jstring JNICALL
|
||
|
|
Java_org_godotengine_plugin_vavcore_VavCorePlugin_getGodotIntegrationInfo(
|
||
|
|
JNIEnv* env, jclass clazz, jlong decoder_ptr) {
|
||
|
|
|
||
|
|
auto* decoder = reinterpret_cast<AndroidMediaCodecAV1Decoder*>(decoder_ptr);
|
||
|
|
std::string info = decoder->GetGodotIntegrationInfo();
|
||
|
|
|
||
|
|
return env->NewStringUTF(info.c_str());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 4.3.3 Godot GDScript 인터페이스
|
||
|
|
```gdscript
|
||
|
|
# Godot VavCore 플러그인 GDScript 인터페이스
|
||
|
|
class_name VavCoreVideoPlayer
|
||
|
|
extends RefCounted
|
||
|
|
|
||
|
|
# 네이티브 플러그인 참조
|
||
|
|
var _native_decoder: int = 0
|
||
|
|
var _surface_type: int = 0
|
||
|
|
var _texture: Texture2D
|
||
|
|
|
||
|
|
# 초기화
|
||
|
|
func initialize() -> bool:
|
||
|
|
if not Engine.has_singleton("VavCorePlugin"):
|
||
|
|
push_error("VavCore plugin not found")
|
||
|
|
return false
|
||
|
|
|
||
|
|
var plugin = Engine.get_singleton("VavCorePlugin")
|
||
|
|
_native_decoder = plugin.createDecoder()
|
||
|
|
|
||
|
|
if _native_decoder == 0:
|
||
|
|
push_error("Failed to create VavCore decoder")
|
||
|
|
return false
|
||
|
|
|
||
|
|
# Godot 렌더링 백엔드에 맞는 최적 Surface 타입 확인
|
||
|
|
_surface_type = plugin.getOptimalSurfaceType(_native_decoder)
|
||
|
|
|
||
|
|
# 렌더링 백엔드별 초기화
|
||
|
|
match _surface_type:
|
||
|
|
VavCoreSurfaceType.VULKAN_IMAGE:
|
||
|
|
return _setup_vulkan_integration()
|
||
|
|
VavCoreSurfaceType.OPENGL_ES_TEXTURE:
|
||
|
|
return _setup_opengl_integration()
|
||
|
|
_:
|
||
|
|
push_warning("Using CPU decoding - not optimal for Godot")
|
||
|
|
return true
|
||
|
|
|
||
|
|
# Vulkan 통합 설정
|
||
|
|
func _setup_vulkan_integration() -> bool:
|
||
|
|
var rendering_device = RenderingServer.create_local_rendering_device()
|
||
|
|
if not rendering_device:
|
||
|
|
return false
|
||
|
|
|
||
|
|
# Vulkan 디바이스 정보 전달 (실제 구현에서는 RenderingDevice API 사용)
|
||
|
|
var plugin = Engine.get_singleton("VavCorePlugin")
|
||
|
|
return plugin.setupVulkanIntegration(_native_decoder, 0, 0) # VkDevice, VkInstance
|
||
|
|
|
||
|
|
# OpenGL ES 통합 설정
|
||
|
|
func _setup_opengl_integration() -> bool:
|
||
|
|
# SurfaceTexture 생성 및 설정
|
||
|
|
var plugin = Engine.get_singleton("VavCorePlugin")
|
||
|
|
# 실제 구현에서는 Android SurfaceTexture API 사용
|
||
|
|
return plugin.setupOpenGLESIntegration(_native_decoder, null)
|
||
|
|
|
||
|
|
# AV1 비디오 프레임 디코딩
|
||
|
|
func decode_frame(packet_data: PackedByteArray) -> bool:
|
||
|
|
if _native_decoder == 0:
|
||
|
|
return false
|
||
|
|
|
||
|
|
var plugin = Engine.get_singleton("VavCorePlugin")
|
||
|
|
return plugin.decodeFrameToTexture(_native_decoder, packet_data, 0)
|
||
|
|
|
||
|
|
# 통합 정보 확인
|
||
|
|
func get_integration_info() -> String:
|
||
|
|
if _native_decoder == 0:
|
||
|
|
return "Decoder not initialized"
|
||
|
|
|
||
|
|
var plugin = Engine.get_singleton("VavCorePlugin")
|
||
|
|
return plugin.getGodotIntegrationInfo(_native_decoder)
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.4 Unity/Unreal 엔진 통합 (참조용)
|
||
|
|
Java_com_vavcore_VavCore_createDecoder(JNIEnv* env, jclass clazz) {
|
||
|
|
auto decoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::AUTO);
|
||
|
|
return reinterpret_cast<jlong>(decoder.release());
|
||
|
|
}
|
||
|
|
|
||
|
|
JNIEXPORT jboolean JNICALL
|
||
|
|
Java_com_vavcore_VavCore_setupAndroidSurface(JNIEnv* env, jclass clazz,
|
||
|
|
jlong decoder_ptr, jobject surface) {
|
||
|
|
auto* decoder = reinterpret_cast<IVideoDecoder*>(decoder_ptr);
|
||
|
|
ANativeWindow* native_window = ANativeWindow_fromSurface(env, surface);
|
||
|
|
|
||
|
|
return decoder->SetAndroidSurface(native_window) ? JNI_TRUE : JNI_FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
JNIEXPORT jboolean JNICALL
|
||
|
|
Java_com_vavcore_VavCore_decodeToSurface(JNIEnv* env, jclass clazz,
|
||
|
|
jlong decoder_ptr, jbyteArray packet_data,
|
||
|
|
jint surface_type, jlong surface_handle) {
|
||
|
|
auto* decoder = reinterpret_cast<IVideoDecoder*>(decoder_ptr);
|
||
|
|
|
||
|
|
// JNI 바이트 배열을 네이티브 포인터로 변환
|
||
|
|
jbyte* data = env->GetByteArrayElements(packet_data, nullptr);
|
||
|
|
jsize size = env->GetArrayLength(packet_data);
|
||
|
|
|
||
|
|
void* surface = reinterpret_cast<void*>(surface_handle);
|
||
|
|
VideoFrame output_frame;
|
||
|
|
|
||
|
|
bool result = decoder->DecodeToSurface(
|
||
|
|
reinterpret_cast<const uint8_t*>(data),
|
||
|
|
static_cast<size_t>(size),
|
||
|
|
static_cast<VavCoreSurfaceType>(surface_type),
|
||
|
|
surface,
|
||
|
|
output_frame
|
||
|
|
);
|
||
|
|
|
||
|
|
env->ReleaseByteArrayElements(packet_data, data, JNI_ABORT);
|
||
|
|
return result ? JNI_TRUE : JNI_FALSE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Unity Native Plugin 인터페이스 (크로스 플랫폼)
|
||
|
|
extern "C" {
|
||
|
|
UNITY_INTERFACE_EXPORT void* UNITY_INTERFACE_API
|
||
|
|
VavCore_CreateDecoder() {
|
||
|
|
auto decoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::AUTO);
|
||
|
|
return decoder.release();
|
||
|
|
}
|
||
|
|
|
||
|
|
UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API
|
||
|
|
VavCore_SetupGraphicsAPI(void* decoder_ptr, int surface_type, void* graphics_device) {
|
||
|
|
auto* decoder = static_cast<IVideoDecoder*>(decoder_ptr);
|
||
|
|
|
||
|
|
switch (static_cast<VavCoreSurfaceType>(surface_type)) {
|
||
|
|
case VAVCORE_SURFACE_D3D11_TEXTURE:
|
||
|
|
return decoder->SetD3DDevice(graphics_device, VAVCORE_SURFACE_D3D11_TEXTURE);
|
||
|
|
case VAVCORE_SURFACE_OPENGL_TEXTURE:
|
||
|
|
return decoder->SetOpenGLContext(graphics_device);
|
||
|
|
case VAVCORE_SURFACE_METAL_TEXTURE:
|
||
|
|
return decoder->SetMetalDevice(graphics_device);
|
||
|
|
default:
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 5. Enhanced 성능 최적화 및 Zero-Copy 아키텍처
|
||
|
|
|
||
|
|
### 5.1 완전한 Zero-Copy Graphics Pipeline
|
||
|
|
**Android MediaCodec + GPU 직접 렌더링 최적화:**
|
||
|
|
|
||
|
|
```cpp
|
||
|
|
// Zero-Copy 성능 최적화 클래스
|
||
|
|
class AndroidZeroCopyOptimizer {
|
||
|
|
public:
|
||
|
|
// GPU-to-GPU 직접 전송 (메모리 복사 완전 제거)
|
||
|
|
bool OptimizeForSoC(const std::string& soc_name) {
|
||
|
|
if (IsQualcommSnapdragon(soc_name)) {
|
||
|
|
// Qualcomm Adreno GPU 최적화
|
||
|
|
EnableAdrenoGPUMemoryExtensions();
|
||
|
|
SetOptimalColorFormat(COLOR_FormatYUV420SemiPlanar);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (IsSamsungExynos(soc_name)) {
|
||
|
|
// Samsung Mali GPU 최적화
|
||
|
|
EnableMaliGPUDirectRendering();
|
||
|
|
SetOptimalColorFormat(COLOR_FormatYUV420Flexible);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (IsMediaTekDimensity(soc_name)) {
|
||
|
|
// MediaTek Mali GPU 최적화
|
||
|
|
EnableMaliGPUOptimizations();
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
return false; // 기본 설정 사용
|
||
|
|
}
|
||
|
|
|
||
|
|
// 메모리 대역폭 최적화
|
||
|
|
void OptimizeMemoryBandwidth() {
|
||
|
|
// SoC별 메모리 대역폭 특성에 맞춰 버퍼 크기 조정
|
||
|
|
m_optimal_buffer_count = GetOptimalBufferCount();
|
||
|
|
m_optimal_buffer_size = GetOptimalBufferSize();
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
int m_optimal_buffer_count = 4; // SoC별 최적화
|
||
|
|
size_t m_optimal_buffer_size = 0;
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5.2 Enhanced Graceful Fallback 전략 (다단계)
|
||
|
|
```cpp
|
||
|
|
class EnhancedFallbackStrategy {
|
||
|
|
public:
|
||
|
|
std::unique_ptr<IVideoDecoder> CreateOptimalDecoder(VideoCodecType codec_type) {
|
||
|
|
// 1단계: 하드웨어 가속 시도 (우선순위 순)
|
||
|
|
if (auto decoder = TryHardwareDecoders(codec_type)) {
|
||
|
|
LogInfo("Hardware decoder selected: " + decoder->GetCodecName());
|
||
|
|
return decoder;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2단계: 하이브리드 디코더 시도 (일부 하드웨어 가속)
|
||
|
|
if (auto decoder = TryHybridDecoders(codec_type)) {
|
||
|
|
LogInfo("Hybrid decoder selected: " + decoder->GetCodecName());
|
||
|
|
return decoder;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 3단계: 최적화된 소프트웨어 디코더
|
||
|
|
auto decoder = std::make_unique<AV1Decoder>();
|
||
|
|
decoder->SetOptimizations(GetCPUOptimizations());
|
||
|
|
LogInfo("Optimized software decoder selected");
|
||
|
|
return decoder;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
std::unique_ptr<IVideoDecoder> TryHardwareDecoders(VideoCodecType codec_type) {
|
||
|
|
#ifdef VAVCORE_PLATFORM_ANDROID
|
||
|
|
// Android 하드웨어 디코더들 시도
|
||
|
|
std::vector<std::string> hw_codecs = {
|
||
|
|
"c2.qti.av1.decoder", // Qualcomm 최신
|
||
|
|
"OMX.qcom.video.decoder.av1", // Qualcomm 레거시
|
||
|
|
"c2.mtk.av1.decoder", // MediaTek
|
||
|
|
"c2.exynos.av1.decoder" // Samsung Exynos
|
||
|
|
};
|
||
|
|
|
||
|
|
for (const auto& codec_name : hw_codecs) {
|
||
|
|
if (auto decoder = TryCreateMediaCodec(codec_name)) {
|
||
|
|
return decoder;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
CPUOptimizations GetCPUOptimizations() {
|
||
|
|
CPUOptimizations opts;
|
||
|
|
opts.enable_neon = HasNEONSupport();
|
||
|
|
opts.thread_count = GetOptimalThreadCount();
|
||
|
|
opts.simd_level = GetMaxSIMDLevel();
|
||
|
|
return opts;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5.3 실시간 성능 모니터링 및 동적 최적화
|
||
|
|
```cpp
|
||
|
|
class PerformanceMonitor {
|
||
|
|
public:
|
||
|
|
void UpdateFrameStats(double decode_time_ms, bool hardware_accelerated) {
|
||
|
|
m_frame_times.push_back(decode_time_ms);
|
||
|
|
if (m_frame_times.size() > 30) { // 30프레임 이동평균
|
||
|
|
m_frame_times.pop_front();
|
||
|
|
}
|
||
|
|
|
||
|
|
double avg_time = CalculateAverage(m_frame_times);
|
||
|
|
|
||
|
|
// 성능이 목표치 미달 시 동적 최적화
|
||
|
|
if (avg_time > TARGET_DECODE_TIME_MS) {
|
||
|
|
TriggerPerformanceOptimization();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 하드웨어 가속 효과 모니터링
|
||
|
|
if (!hardware_accelerated && avg_time > SW_FALLBACK_THRESHOLD_MS) {
|
||
|
|
LogWarning("Software decoder performance below threshold, consider resolution scaling");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
static constexpr double TARGET_DECODE_TIME_MS = 16.67; // 60fps 목표
|
||
|
|
static constexpr double SW_FALLBACK_THRESHOLD_MS = 33.33; // 30fps 최소
|
||
|
|
|
||
|
|
std::deque<double> m_frame_times;
|
||
|
|
|
||
|
|
void TriggerPerformanceOptimization() {
|
||
|
|
// 동적 해상도 스케일링
|
||
|
|
// 품질 레벨 조정
|
||
|
|
// 버퍼 크기 최적화
|
||
|
|
}
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
## 6. Enhanced 테스트 및 검증 시스템
|
||
|
|
|
||
|
|
### 6.1 포괄적인 Android 테스트 애플리케이션
|
||
|
|
```cpp
|
||
|
|
// VavCore Android 종합 테스트 애플리케이션
|
||
|
|
class ComprehensiveAndroidTest {
|
||
|
|
public:
|
||
|
|
void RunAllTests() {
|
||
|
|
TestHardwareDetection();
|
||
|
|
TestAllSurfaceTypes();
|
||
|
|
TestPerformanceBenchmark();
|
||
|
|
TestFallbackScenarios();
|
||
|
|
TestMemoryLeaks();
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
void TestAllSurfaceTypes() {
|
||
|
|
auto decoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::AUTO);
|
||
|
|
|
||
|
|
// ANativeWindow 테스트
|
||
|
|
if (decoder->SupportsSurfaceType(VAVCORE_SURFACE_ANDROID_NATIVE_WINDOW)) {
|
||
|
|
TestNativeWindowRendering(decoder.get());
|
||
|
|
}
|
||
|
|
|
||
|
|
// OpenGL ES 텍스처 테스트
|
||
|
|
if (decoder->SupportsSurfaceType(VAVCORE_SURFACE_OPENGL_ES_TEXTURE)) {
|
||
|
|
TestOpenGLESTextureRendering(decoder.get());
|
||
|
|
}
|
||
|
|
|
||
|
|
// Vulkan 이미지 테스트
|
||
|
|
if (decoder->SupportsSurfaceType(VAVCORE_SURFACE_VULKAN_IMAGE)) {
|
||
|
|
TestVulkanImageRendering(decoder.get());
|
||
|
|
}
|
||
|
|
|
||
|
|
// AHardwareBuffer 테스트
|
||
|
|
if (decoder->SupportsSurfaceType(VAVCORE_SURFACE_ANDROID_HARDWARE_BUFFER)) {
|
||
|
|
TestHardwareBufferRendering(decoder.get());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void TestPerformanceBenchmark() {
|
||
|
|
// 다양한 해상도 및 비트레이트 테스트
|
||
|
|
std::vector<TestVideo> test_videos = {
|
||
|
|
{"1080p_av1.webm", 1920, 1080, 5000}, // 5Mbps
|
||
|
|
{"4k_av1.webm", 3840, 2160, 15000}, // 15Mbps
|
||
|
|
{"720p_av1.webm", 1280, 720, 2000} // 2Mbps
|
||
|
|
};
|
||
|
|
|
||
|
|
for (const auto& test_video : test_videos) {
|
||
|
|
BenchmarkVideo(test_video);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### 6.2 성능 벤치마크 및 최적화 메트릭스
|
||
|
|
**측정 항목들:**
|
||
|
|
- **초기화 시간**: MediaCodec vs dav1d 시작 시간 비교
|
||
|
|
- **디코딩 지연시간**: 하드웨어 vs 소프트웨어 프레임별 처리 시간
|
||
|
|
- **GPU 사용률**: 하드웨어 가속 시 GPU 점유율
|
||
|
|
- **전력 소비**: 배터리 소모량 측정 (Android Battery Historian)
|
||
|
|
- **메모리 사용량**: 피크 메모리 및 메모리 누수 검사
|
||
|
|
- **열 관리**: SoC 온도 상승 및 스로틀링 감지
|
||
|
|
- **Surface 렌더링 성능**: 각 Graphics API별 렌더링 성능
|
||
|
|
|
||
|
|
## 7. Enhanced 구현 로드맵 (완전한 크로스 플랫폼 지원)
|
||
|
|
|
||
|
|
### Phase 1: 핵심 크로스 플랫폼 인프라 (1-2주) ✅ **완료**
|
||
|
|
- [x] **VavCoreSurfaceType 시스템**: 완전한 크로스 플랫폼 Surface 타입 열거형
|
||
|
|
- [x] **Enhanced IVideoDecoder 인터페이스**: 모든 플랫폼의 Graphics API 지원
|
||
|
|
- [x] **VideoDecoderFactory 확장**: 플랫폼별 디코더 등록 및 우선순위 시스템
|
||
|
|
- [x] **크로스 플랫폼 빌드 시스템**: CMake + 플랫폼별 조건부 컴파일
|
||
|
|
|
||
|
|
### Phase 2: AndroidMediaCodecAV1Decoder 구현 (2-3주)
|
||
|
|
- [ ] **Enhanced AndroidMediaCodecAV1Decoder**: 모든 IVideoDecoder 메서드 구현
|
||
|
|
- [ ] **Android SoC별 하드웨어 감지**: Qualcomm, Samsung, MediaTek, Google Tensor 지원
|
||
|
|
- [ ] **Graphics API 통합**: OpenGL ES, Vulkan, ANativeWindow, AHardwareBuffer
|
||
|
|
- [ ] **Zero-Copy Surface 디코딩**: GPU-to-GPU 직접 전송 최적화
|
||
|
|
|
||
|
|
### Phase 3: 성능 최적화 및 테스트 (3-4주)
|
||
|
|
- [ ] **포괄적인 테스트 애플리케이션**: 모든 Surface 타입 및 SoC 조합 테스트
|
||
|
|
- [ ] **성능 벤치마킹**: 하드웨어 vs 소프트웨어 성능 비교
|
||
|
|
- [ ] **메모리 및 전력 최적화**: SoC별 최적화 설정 적용
|
||
|
|
- [ ] **Graceful Fallback 시스템**: 다단계 디코더 선택 및 전환
|
||
|
|
|
||
|
|
### Phase 4: 게임 엔진 통합 및 배포 (4-5주)
|
||
|
|
- [ ] **Godot Android 플러그인**: Native Surface 지원 완전 통합
|
||
|
|
- [ ] **Unity/Unreal 플러그인**: 크로스 플랫폼 Native Plugin 인터페이스
|
||
|
|
- [ ] **Android Studio 프로젝트**: 완전한 예제 애플리케이션
|
||
|
|
- [ ] **문서화 및 튜토리얼**: 개발자 가이드 및 API 레퍼런스
|
||
|
|
|
||
|
|
## 8. Enhanced 리스크 관리 및 완화 전략
|
||
|
|
|
||
|
|
### 8.1 하드웨어 호환성 리스크 (CRITICAL)
|
||
|
|
- **리스크**: Android 기기별 AV1 하드웨어 지원 차이
|
||
|
|
- **완화 전략**:
|
||
|
|
- 포괄적인 SoC 데이터베이스 구축 (Qualcomm, Samsung, MediaTek 등)
|
||
|
|
- 런타임 하드웨어 감지 및 자동 최적화
|
||
|
|
- 견고한 dav1d 소프트웨어 fallback 보장
|
||
|
|
- 성능 모니터링 기반 동적 디코더 전환
|
||
|
|
|
||
|
|
### 8.2 Android API 파편화 리스크 (MEDIUM)
|
||
|
|
- **리스크**: Android 버전별 MediaCodec API 변경 및 동작 차이
|
||
|
|
- **완화 전략**:
|
||
|
|
- 안정적인 NDK API만 사용 (API Level 21+)
|
||
|
|
- 버전별 조건부 컴파일 및 호환성 레이어
|
||
|
|
- 광범위한 Android 버전 테스트 (API 21~34)
|
||
|
|
|
||
|
|
### 8.3 성능 최적화 리스크 (MEDIUM)
|
||
|
|
- **리스크**: 특정 상황에서 하드웨어 디코더가 소프트웨어보다 성능 저하
|
||
|
|
- **완화 전략**:
|
||
|
|
- 실시간 성능 모니터링 시스템
|
||
|
|
- SoC별 성능 프로파일링 데이터베이스
|
||
|
|
- 동적 디코더 전환 알고리즘
|
||
|
|
- 사용자 정의 성능 임계값 설정
|
||
|
|
|
||
|
|
### 8.4 메모리 및 전력 소비 리스크 (LOW)
|
||
|
|
- **리스크**: 하드웨어 가속으로 인한 예상치 못한 메모리/전력 증가
|
||
|
|
- **완화 전략**:
|
||
|
|
- Zero-Copy 아키텍처로 메모리 사용량 최소화
|
||
|
|
- SoC별 전력 효율성 프로파일링
|
||
|
|
- 배터리 상태 기반 동적 최적화
|
||
|
|
|
||
|
|
## 9. 결론 및 향후 전망
|
||
|
|
|
||
|
|
### 9.1 프로젝트 성과 요약
|
||
|
|
본 Enhanced VavCore Android MediaCodec 통합 설계는 다음과 같은 혁신적 성과를 달성합니다:
|
||
|
|
|
||
|
|
**✅ 완전한 크로스 플랫폼 지원:**
|
||
|
|
- Windows (NVDEC, VPL, AMF, Media Foundation)
|
||
|
|
- Android (MediaCodec + OpenGL ES/Vulkan)
|
||
|
|
- macOS/iOS (Metal, VideoToolbox - 미래 확장)
|
||
|
|
- Linux (OpenGL, Vulkan - 미래 확장)
|
||
|
|
|
||
|
|
**✅ Zero-Copy 렌더링 아키텍처:**
|
||
|
|
- GPU-to-GPU 직접 전송으로 성능 최적화
|
||
|
|
- 메모리 복사 완전 제거
|
||
|
|
- SoC별 최적화된 Graphics API 선택
|
||
|
|
|
||
|
|
**✅ 완전한 역호환성:**
|
||
|
|
- 기존 Windows 코드 100% 호환
|
||
|
|
- 플랫폼 투명한 API 설계
|
||
|
|
- 점진적 마이그레이션 지원
|
||
|
|
|
||
|
|
### 9.2 기술적 혁신 포인트
|
||
|
|
1. **Unified Surface Type System**: 모든 플랫폼의 Graphics API를 단일 열거형으로 통합
|
||
|
|
2. **Enhanced IVideoDecoder Interface**: 플랫폼별 특성을 반영한 확장 가능한 인터페이스
|
||
|
|
3. **Smart Hardware Detection**: SoC별 최적 디코더 및 Graphics API 자동 선택
|
||
|
|
4. **Multi-layer Fallback**: 하드웨어 → 하이브리드 → 최적화된 소프트웨어 다단계 전환
|
||
|
|
|
||
|
|
### 9.3 향후 확장 계획
|
||
|
|
**즉시 확장 가능한 영역:**
|
||
|
|
- **VP9 지원**: 동일한 아키텍처로 VP9 디코더 추가
|
||
|
|
- **H.264/H.265 지원**: 레거시 코덱 지원 확장
|
||
|
|
- **iOS/macOS 지원**: VideoToolbox + Metal 통합
|
||
|
|
- **Linux 지원**: VAAPI + OpenGL/Vulkan 통합
|
||
|
|
|
||
|
|
**장기 확장 목표:**
|
||
|
|
- **실시간 스트리밍**: WebRTC + MediaCodec 통합
|
||
|
|
- **인코딩 지원**: 디코딩뿐만 아니라 인코딩 파이프라인
|
||
|
|
- **AI 후처리**: SoC NPU를 활용한 실시간 화질 개선
|
||
|
|
- **클라우드 연동**: 클라우드 GPU 리소스 활용
|
||
|
|
|
||
|
|
### 9.4 산업적 영향
|
||
|
|
본 설계는 다음과 같은 산업적 파급 효과를 기대합니다:
|
||
|
|
|
||
|
|
**게임 산업 (Godot 최적화):**
|
||
|
|
- **Godot 4**: Vulkan/OpenGL ES 텍스처와 직접 통합하여 Zero-Copy 비디오 재생
|
||
|
|
- **Unity/Unreal**: 크로스 플랫폼 Native Plugin 인터페이스 지원
|
||
|
|
- **모바일 게임**: 고화질 AV1 컷신 및 배경 영상을 최소 성능 오버헤드로 재생
|
||
|
|
|
||
|
|
**스트리밍 산업:**
|
||
|
|
- 모바일 앱에서의 효율적인 AV1 스트리밍 재생
|
||
|
|
- 배터리 효율성과 화질의 최적 균형
|
||
|
|
|
||
|
|
**교육 및 미디어:**
|
||
|
|
- 크로스 플랫폼 교육 애플리케이션
|
||
|
|
- 고화질 미디어 콘텐츠의 효율적 배포
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 📋 **문서 정보 (최종)**
|
||
|
|
- **버전**: 3.0.0 (완전한 크로스 플랫폼 Graphics API 통합)
|
||
|
|
- **최종 업데이트**: 2025-09-27
|
||
|
|
- **담당자**: Claude Code AI Assistant
|
||
|
|
- **상태**: 구현 준비 완료 (Implementation Ready)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
*이 문서는 VavCore의 Android MediaCodec 통합뿐만 아니라 완전한 크로스 플랫폼 Graphics API 아키텍처를 제시하는 포괄적인 설계 문서입니다. 모든 주요 모바일 및 데스크톱 플랫폼에서 최적의 AV1 디코딩 성능을 보장하는 확장 가능한 솔루션을 제공합니다.*
|