Files
video-v1/vav2/docs/completed/cross-platform/Android_dav1d_Build_Guide.md
2025-09-28 17:10:41 +09:00

11 KiB

Godot용 Android dav1d 라이브러리 빌드 가이드

1. 개요

이 문서는 Godot 엔진에서 사용할 수 있는 Android용 dav1d AV1 디코더 라이브러리를 빌드하는 전체 과정을 설명합니다. ARM64 (aarch64)와 ARM32 (armv7a) 아키텍처를 모두 지원하며, Android NDK 26.0.10792818을 사용합니다.

2. 빌드 환경 설정

2.1 필요 도구

  • Android NDK: 26.0.10792818
  • Meson Build System: 최신 버전
  • Python: 3.7 이상
  • Ninja: Build backend

2.2 환경 변수 설정

# Android NDK 경로 설정
export ANDROID_NDK_HOME="C:/Users/emocr/AppData/Local/Android/Sdk/ndk/26.0.10792818"

# 빌드 도구 경로 확인
export NDK_TOOLCHAIN="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/windows-x86_64/bin"

3. Cross-compilation 설정 파일

3.1 ARM64 (aarch64) 설정

파일: oss/dav1d/android-arm64.cross

[binaries]
c = 'C:/Users/emocr/AppData/Local/Android/Sdk/ndk/26.0.10792818/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android21-clang.cmd'
cpp = 'C:/Users/emocr/AppData/Local/Android/Sdk/ndk/26.0.10792818/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android21-clang++.cmd'
ar = 'C:/Users/emocr/AppData/Local/Android/Sdk/ndk/26.0.10792818/toolchains/llvm/prebuilt/windows-x86_64/bin/llvm-ar'
strip = 'C:/Users/emocr/AppData/Local/Android/Sdk/ndk/26.0.10792818/toolchains/llvm/prebuilt/windows-x86_64/bin/llvm-strip'
pkgconfig = 'false'

[host_machine]
system = 'android'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

[built-in options]
c_args = ['-fPIC']
cpp_args = ['-fPIC']
c_link_args = ['-static-libgcc']
cpp_link_args = ['-static-libgcc', '-static-libstdc++']

3.2 ARM32 (armv7a) 설정

파일: oss/dav1d/android-arm32.cross

[binaries]
c = 'C:/Users/emocr/AppData/Local/Android/Sdk/ndk/26.0.10792818/toolchains/llvm/prebuilt/windows-x86_64/bin/armv7a-linux-androideabi21-clang.cmd'
cpp = 'C:/Users/emocr/AppData/Local/Android/Sdk/ndk/26.0.10792818/toolchains/llvm/prebuilt/windows-x86_64/bin/armv7a-linux-androideabi21-clang++.cmd'
ar = 'C:/Users/emocr/AppData/Local/Android/Sdk/ndk/26.0.10792818/toolchains/llvm/prebuilt/windows-x86_64/bin/llvm-ar'
strip = 'C:/Users/emocr/AppData/Local/Android/Sdk/ndk/26.0.10792818/toolchains/llvm/prebuilt/windows-x86_64/bin/llvm-strip'
pkgconfig = 'false'

[host_machine]
system = 'android'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'

[built-in options]
c_args = ['-fPIC']
cpp_args = ['-fPIC']
c_link_args = ['-static-libgcc']
cpp_link_args = ['-static-libgcc', '-static-libstdc++']

4. 빌드 과정

4.1 ARM64 빌드

# dav1d 소스 디렉토리로 이동
cd D:\Project\video-av1\oss\dav1d

# ARM64 빌드 디렉토리 생성 및 설정
meson setup build-android-arm64 --cross-file android-arm64.cross --buildtype=release

# 빌드 실행
meson compile -C build-android-arm64

# 결과 확인
ls build-android-arm64/src/

4.2 ARM32 빌드

# ARM32 빌드 디렉토리 생성 및 설정
meson setup build-android-arm32 --cross-file android-arm32.cross --buildtype=release

# 빌드 실행
meson compile -C build-android-arm32

# 결과 확인
ls build-android-arm32/src/

5. 빌드 결과물

5.1 생성된 라이브러리 파일

ARM64 결과물:

  • build-android-arm64/src/libdav1d.a (정적 라이브러리)
  • build-android-arm64/src/libdav1d.so (동적 라이브러리)

ARM32 결과물:

  • build-android-arm32/src/libdav1d.a (정적 라이브러리)
  • build-android-arm32/src/libdav1d.so (동적 라이브러리)

5.2 라이브러리 배치

Android 프로젝트에서 사용하기 위해 다음 구조로 배치:

vav2/platforms/android/
├── libs/
│   ├── arm64-v8a/
│   │   ├── libdav1d.so
│   │   └── libdav1d.a
│   └── armeabi-v7a/
│       ├── libdav1d.so
│       └── libdav1d.a
└── include/
    └── dav1d/
        ├── dav1d.h
        ├── picture.h
        └── headers.h

6. Android 프로젝트 통합

6.1 CMakeLists.txt 설정

파일: vav2/platforms/android/CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(VavCore-Android)

# Set Android ABI
if(NOT ANDROID_ABI)
    set(ANDROID_ABI "arm64-v8a")
endif()

# Set library directory based on ABI
if(ANDROID_ABI STREQUAL "arm64-v8a")
    set(LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libs/arm64-v8a")
elseif(ANDROID_ABI STREQUAL "armeabi-v7a")
    set(LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libs/armeabi-v7a")
else()
    message(FATAL_ERROR "Unsupported Android ABI: ${ANDROID_ABI}")
endif()

# Include directories
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)

# Import dav1d as prebuilt library
add_library(dav1d SHARED IMPORTED)
set_target_properties(dav1d PROPERTIES
    IMPORTED_LOCATION ${LIB_DIR}/libdav1d.so
    INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include
)

# Also provide static library option
add_library(dav1d_static STATIC IMPORTED)
set_target_properties(dav1d_static PROPERTIES
    IMPORTED_LOCATION ${LIB_DIR}/libdav1d.a
    INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include
)

# Create a simple test library that uses dav1d
add_library(vavcore-android SHARED
    src/android_test.cpp
)

target_link_libraries(vavcore-android
    dav1d
    log  # Android log library
)

6.2 Gradle 빌드 설정

파일: vav2/platforms/android/build.gradle

apply plugin: 'com.android.library'

android {
    compileSdkVersion 34
    buildToolsVersion "34.0.0"

    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 34

        ndk {
            abiFilters 'arm64-v8a', 'armeabi-v7a'
        }

        externalNativeBuild {
            cmake {
                cppFlags "-std=c++17"
                arguments "-DANDROID_STL=c++_shared"
            }
        }
    }

    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
            version "3.22.1"
        }
    }

    sourceSets {
        main {
            java.srcDirs = ['src/main/java']
            jniLibs.srcDirs = ['libs']
        }
    }
}

7. 테스트 및 검증

7.1 기본 테스트 코드

파일: vav2/platforms/android/src/android_test.cpp

#include <jni.h>
#include <android/log.h>
#include <dav1d/dav1d.h>

#define LOG_TAG "VavCore"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

extern "C" {

JNIEXPORT jstring JNICALL
Java_com_vavcore_android_VavCore_getDav1dVersion(JNIEnv *env, jclass clazz) {
    const char* version = dav1d_version();
    LOGI("dav1d version: %s", version);
    return env->NewStringUTF(version);
}

JNIEXPORT jboolean JNICALL
Java_com_vavcore_android_VavCore_testDav1dDecoder(JNIEnv *env, jclass clazz) {
    Dav1dSettings settings;
    Dav1dContext *ctx = nullptr;

    // Initialize default settings
    dav1d_default_settings(&settings);
    settings.n_threads = 1; // Use single thread for Android

    // Create decoder context
    int ret = dav1d_open(&ctx, &settings);
    if (ret < 0) {
        LOGE("Failed to create dav1d decoder context: %d", ret);
        return JNI_FALSE;
    }

    LOGI("dav1d decoder context created successfully");

    // Clean up
    dav1d_close(&ctx);
    LOGI("dav1d decoder context closed");

    return JNI_TRUE;
}

} // extern "C"

7.2 Java 인터페이스

파일: src/main/java/com/vavcore/android/VavCore.java

package com.vavcore.android;

public class VavCore {
    static {
        System.loadLibrary("vavcore-android");
    }

    public static native String getDav1dVersion();
    public static native boolean testDav1dDecoder();
}

8. Godot 통합 가이드

8.1 GDExtension 구조

godot-project/
├── addons/
│   └── vavcore/
│       ├── bin/
│       │   ├── android/
│       │   │   ├── arm64/libvavcore.so
│       │   │   └── arm32/libvavcore.so
│       │   └── windows/
│       │       └── x64/vavcore.dll
│       ├── vavcore.gdextension
│       └── README.md

8.2 GDExtension 설정 파일

파일: addons/vavcore/vavcore.gdextension

[configuration]
entry_symbol = "vavcore_library_init"

[libraries]
android.debug.arm64 = "res://addons/vavcore/bin/android/arm64/libvavcore.so"
android.release.arm64 = "res://addons/vavcore/bin/android/arm64/libvavcore.so"
android.debug.arm32 = "res://addons/vavcore/bin/android/arm32/libvavcore.so"
android.release.arm32 = "res://addons/vavcore/bin/android/arm32/libvavcore.so"
windows.debug.x86_64 = "res://addons/vavcore/bin/windows/x64/vavcore.dll"
windows.release.x86_64 = "res://addons/vavcore/bin/windows/x64/vavcore.dll"

9. 성능 최적화

9.1 빌드 최적화 옵션

# Release 빌드 with 최적화
meson setup build-android-arm64 \
    --cross-file android-arm64.cross \
    --buildtype=release \
    -Db_lto=true \
    -Db_ndebug=true \
    -Denable_asm=true \
    -Denable_tools=false \
    -Denable_tests=false

9.2 런타임 최적화

  • 스레드 수 조정: Android 기기의 CPU 코어 수에 맞춰 설정
  • 메모리 사용량 최적화: 작은 해상도 우선 처리
  • 배터리 최적화: GPU 가속 사용 시 전력 소비 고려

10. 트러블슈팅

10.1 일반적인 문제들

문제: NDK 경로 오류

ERROR: C compiler not found

해결책: NDK 경로와 실행 파일 확장자(.cmd) 확인

문제: 링크 오류

undefined reference to 'dav1d_version'

해결책: 라이브러리 경로와 아키텍처 일치 확인

문제: 런타임 크래시

java.lang.UnsatisfiedLinkError

해결책: JNI 함수 시그니처와 실제 구현 일치 확인

10.2 디버깅 도구

  • Android Studio Logcat: 런타임 로그 확인
  • ndk-stack: 네이티브 크래시 분석
  • objdump: 라이브러리 심볼 확인
# 라이브러리 심볼 확인
objdump -T libdav1d.so | grep dav1d_version

# 아키텍처 확인
file libdav1d.so

11. 결론

이 가이드를 통해 Android용 dav1d 라이브러리를 성공적으로 빌드하고 Godot 프로젝트에 통합할 수 있습니다. ARM64와 ARM32 아키텍처를 모두 지원하므로 다양한 Android 기기에서 AV1 비디오 디코딩이 가능합니다.

주요 성과:

  • Cross-platform 빌드 시스템: Meson 기반 안정적인 빌드
  • 멀티 아키텍처 지원: ARM64/ARM32 동시 지원
  • Godot 통합 준비: GDExtension 구조 완성
  • 테스트 검증: JNI 인터페이스를 통한 동작 확인

향후 VavCore Android MediaCodec 통합 시 이 dav1d 라이브러리가 소프트웨어 fallback으로 사용되어 안정적인 AV1 디코딩 환경을 제공할 것입니다.


문서 버전: 1.0 작성일: 2025-09-27 작성자: Claude Code AI Assistant