Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,23 @@ android {
"\"" + (System.getenv("ANILIST_KEY") ?: localProperties["anilist.key"]) + "\""
)
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

externalNativeBuild {
cmake {
// Static C++ runtime so it can not clash with the other native libraries
arguments += "-DANDROID_STL=c++_static"
// Shared between ABIs and variants so the sources are only downloaded once
arguments += "-DLIBASS_DEPS_DIR=${layout.buildDirectory.get().asFile.invariantSeparatorsPath}/libass-deps"
}
}
}

// libass for ASS/SSA subtitles
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
version = "3.22.1"
}
}

buildTypes {
Expand Down
154 changes: 154 additions & 0 deletions app/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
cmake_minimum_required(VERSION 3.22.1)

# libass (https://github.com/libass/libass) for ASS/SSA subtitles, see LibassSubtitleSupport.kt
#
# libass, FreeType, FriBidi and HarfBuzz are built as static libraries and linked into
# libcs3ass.so. The sources are downloaded by libass-deps.cmake.
# Fontconfig is not used, fonts come from the subtitle (MKV attachments or [Fonts]) or the
# default system font.
project(cs3ass C CXX ASM)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)

# Subtitles are rendered every frame, so optimize debug builds too
add_compile_options(-O2 -ffunction-sections -fdata-sections)

include(libass-deps.cmake)

set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")

# FreeType
set(FT_DISABLE_ZLIB ON CACHE BOOL "" FORCE)
set(FT_DISABLE_BZIP2 ON CACHE BOOL "" FORCE)
set(FT_DISABLE_PNG ON CACHE BOOL "" FORCE)
set(FT_DISABLE_HARFBUZZ ON CACHE BOOL "" FORCE)
set(FT_DISABLE_BROTLI ON CACHE BOOL "" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
add_subdirectory("${FREETYPE_SOURCE_DIR}" freetype EXCLUDE_FROM_ALL)

# FriBidi only has a meson build, so its config headers are written here.
# The release tarball already contains the generated Unicode tables (*.tab.i).
set(FRIBIDI_GENERATED_DIR "${GENERATED_DIR}/fribidi")
file(WRITE "${FRIBIDI_GENERATED_DIR}/config.h"
"#define HAVE_MEMMOVE 1\n"
"#define HAVE_MEMSET 1\n"
"#define HAVE_STRDUP 1\n"
"#define HAVE_STDLIB_H 1\n"
"#define HAVE_STRING_H 1\n"
"#define HAVE_MEMORY_H 0\n"
"#define HAVE_STRINGS_H 1\n"
"#define HAVE_SYS_TIMES_H 1\n"
"#define STDC_HEADERS 1\n"
"#define HAVE_STRINGIZE 1\n"
)
string(REPLACE "." ";" FRIBIDI_VERSION_PARTS "${FRIBIDI_VERSION}")
list(GET FRIBIDI_VERSION_PARTS 0 FRIBIDI_MAJOR_VERSION)
list(GET FRIBIDI_VERSION_PARTS 1 FRIBIDI_MINOR_VERSION)
list(GET FRIBIDI_VERSION_PARTS 2 FRIBIDI_MICRO_VERSION)
set(configure_input "fribidi-config.h generated by CMake")
set(PACKAGE fribidi)
set(PACKAGE_NAME "GNU FriBidi")
set(PACKAGE_BUGREPORT "https://github.com/fribidi/fribidi/issues/new")
set(FRIBIDI_INTERFACE_VERSION 4)
set(SIZEOF_INT 4)
set(FRIBIDI_MSVC_BUILD_PLACEHOLDER "#undef FRIBIDI_BUILT_WITH_MSVC")
configure_file("${FRIBIDI_SOURCE_DIR}/lib/fribidi-config.h.in"
"${FRIBIDI_GENERATED_DIR}/fribidi-config.h" @ONLY)

add_library(fribidi STATIC
"${FRIBIDI_SOURCE_DIR}/lib/fribidi.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-arabic.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-bidi.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-bidi-types.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-char-sets.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-char-sets-cap-rtl.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-char-sets-cp1255.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-char-sets-cp1256.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-char-sets-iso8859-6.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-char-sets-iso8859-8.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-char-sets-utf8.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-deprecated.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-joining.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-joining-types.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-mirroring.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-brackets.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-run.c"
"${FRIBIDI_SOURCE_DIR}/lib/fribidi-shape.c"
)
target_include_directories(fribidi PUBLIC "${FRIBIDI_GENERATED_DIR}" "${FRIBIDI_SOURCE_DIR}/lib")
target_compile_definitions(fribidi PRIVATE HAVE_CONFIG_H)

# HarfBuzz, single file build without any of the optional integrations
add_library(harfbuzz STATIC "${HARFBUZZ_SOURCE_DIR}/src/harfbuzz.cc")
target_include_directories(harfbuzz PUBLIC "${HARFBUZZ_SOURCE_DIR}/src")
target_compile_features(harfbuzz PRIVATE cxx_std_11)
target_compile_options(harfbuzz PRIVATE -fno-exceptions -fno-rtti -fno-threadsafe-statics)

# libass
set(LIBASS_GENERATED_DIR "${GENERATED_DIR}/libass")
set(LIBASS_CONFIG
"#define HAVE_STRDUP 1\n"
"#define HAVE_STRNDUP 1\n"
"#define CONFIG_LARGE_TILES 0\n"
"#define CONFIG_SOURCEVERSION \"cloudstream, release ${LIBASS_VERSION}\"\n"
)
set(LIBASS_SOURCES
"${LIBASS_SOURCE_DIR}/libass/c/c_be_blur.c"
"${LIBASS_SOURCE_DIR}/libass/c/c_blend_bitmaps.c"
"${LIBASS_SOURCE_DIR}/libass/c/c_blur.c"
"${LIBASS_SOURCE_DIR}/libass/c/c_rasterizer.c"
"${LIBASS_SOURCE_DIR}/libass/ass.c"
"${LIBASS_SOURCE_DIR}/libass/ass_arabic_charmap.c"
"${LIBASS_SOURCE_DIR}/libass/ass_bitmap.c"
"${LIBASS_SOURCE_DIR}/libass/ass_bitmap_engine.c"
"${LIBASS_SOURCE_DIR}/libass/ass_blur.c"
"${LIBASS_SOURCE_DIR}/libass/ass_cache.c"
"${LIBASS_SOURCE_DIR}/libass/ass_drawing.c"
"${LIBASS_SOURCE_DIR}/libass/ass_filesystem.c"
"${LIBASS_SOURCE_DIR}/libass/ass_font.c"
"${LIBASS_SOURCE_DIR}/libass/ass_fontselect.c"
"${LIBASS_SOURCE_DIR}/libass/ass_library.c"
"${LIBASS_SOURCE_DIR}/libass/ass_outline.c"
"${LIBASS_SOURCE_DIR}/libass/ass_parse.c"
"${LIBASS_SOURCE_DIR}/libass/ass_rasterizer.c"
"${LIBASS_SOURCE_DIR}/libass/ass_render.c"
"${LIBASS_SOURCE_DIR}/libass/ass_render_api.c"
"${LIBASS_SOURCE_DIR}/libass/ass_shaper.c"
"${LIBASS_SOURCE_DIR}/libass/ass_string.c"
"${LIBASS_SOURCE_DIR}/libass/ass_strtod.c"
"${LIBASS_SOURCE_DIR}/libass/ass_utils.c"
)
# Only the ARM64 assembly is used, the x86 one needs NASM
if(ANDROID_ABI STREQUAL "arm64-v8a")
string(APPEND LIBASS_CONFIG "#define CONFIG_ASM 1\n#define ARCH_AARCH64 1\n")
list(APPEND LIBASS_SOURCES
"${LIBASS_SOURCE_DIR}/libass/aarch64/asm.S"
"${LIBASS_SOURCE_DIR}/libass/aarch64/be_blur.S"
"${LIBASS_SOURCE_DIR}/libass/aarch64/blend_bitmaps.S"
"${LIBASS_SOURCE_DIR}/libass/aarch64/blur.S"
"${LIBASS_SOURCE_DIR}/libass/aarch64/rasterizer.S"
)
endif()
file(WRITE "${LIBASS_GENERATED_DIR}/config.h" ${LIBASS_CONFIG})

add_library(ass STATIC ${LIBASS_SOURCES})
target_include_directories(ass
PRIVATE "${LIBASS_GENERATED_DIR}"
PUBLIC "${LIBASS_SOURCE_DIR}/libass"
)
target_compile_definitions(ass PRIVATE _GNU_SOURCE _XPLATFORM_SOURCE)
target_compile_options(ass PRIVATE $<$<COMPILE_LANGUAGE:C>:-std=gnu99 -fno-math-errno>)
target_link_libraries(ass PRIVATE freetype fribidi harfbuzz m)

# JNI bindings
add_library(cs3ass SHARED libass_jni.c)
target_link_libraries(cs3ass PRIVATE ass freetype fribidi harfbuzz jnigraphics log m)
target_link_options(cs3ass PRIVATE
-Wl,--gc-sections
-Wl,--exclude-libs,ALL
# 16 KB page size support
-Wl,-z,max-page-size=16384
)
77 changes: 77 additions & 0 deletions app/src/main/cpp/libass-deps.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Source tarballs of libass and its dependencies, all from the official releases.
# Every tarball is checked against its SHA-256, nothing prebuilt is downloaded.
#
# The libass and FreeType hashes come from tarballs with a valid PGP signature:
# libass Oneric DDAFC19E46B2AD2D6B26F84397A08E0CFFD70951
# FreeType Werner Lemberg E30674707856409FF1948010BE6C3AAC63AD8E3F
# FriBidi and HarfBuzz do not sign their releases.
#
# When updating a dependency change the version and the hash together.

set(LIBASS_DEPS_DIR "${CMAKE_BINARY_DIR}/libass-deps" CACHE PATH
"Where the dependency sources are downloaded")

set(LIBASS_VERSION 0.17.5)
set(LIBASS_URL "https://github.com/libass/libass/releases/download/${LIBASS_VERSION}/libass-${LIBASS_VERSION}.tar.xz")
set(LIBASS_SHA256 2dca25c0e0c837ddf00b52011b3f82cac1e4ddd3ad018227806b0c2288864acc)

set(FREETYPE_VERSION 2.15.0)
set(FREETYPE_URL "https://download.savannah.gnu.org/releases/freetype/freetype-${FREETYPE_VERSION}.tar.xz")
set(FREETYPE_SHA256 93cd47eb719c325107f2d3cf087d06299e944c3b48a40b55537302304dea1dd5)

set(FRIBIDI_VERSION 1.0.17)
set(FRIBIDI_URL "https://github.com/fribidi/fribidi/releases/download/v${FRIBIDI_VERSION}/fribidi-${FRIBIDI_VERSION}.tar.xz")
set(FRIBIDI_SHA256 6949dcde27d41cebad1fd741fcafc36d55a1020d2d872d4a6eb3914caabbada2)

set(HARFBUZZ_VERSION 14.6.0)
set(HARFBUZZ_URL "https://github.com/harfbuzz/harfbuzz/releases/download/${HARFBUZZ_VERSION}/harfbuzz-${HARFBUZZ_VERSION}.tar.xz")
set(HARFBUZZ_SHA256 d07a007327277708a2a73ae437887cdbaf282937f6d03ca5467723e9099af586)

# Downloads and extracts a tarball if needed, sets <name>_SOURCE_DIR
function(libass_fetch_source name url sha256 top_dir)
get_filename_component(archive_name "${url}" NAME)
set(archive "${LIBASS_DEPS_DIR}/${archive_name}")
set(extract_dir "${LIBASS_DEPS_DIR}/${name}")
set(stamp "${extract_dir}/.sha256-${sha256}")

if(NOT EXISTS "${stamp}")
set(have_archive FALSE)
if(EXISTS "${archive}")
file(SHA256 "${archive}" existing_hash)
if(existing_hash STREQUAL sha256)
set(have_archive TRUE)
endif()
endif()

if(NOT have_archive)
message(STATUS "Downloading ${url}")
file(DOWNLOAD "${url}" "${archive}"
EXPECTED_HASH SHA256=${sha256}
TLS_VERIFY ON
STATUS download_status)
list(GET download_status 0 download_code)
if(NOT download_code EQUAL 0)
list(GET download_status 1 download_error)
file(REMOVE "${archive}")
message(FATAL_ERROR "Could not download ${url}: ${download_error}")
endif()
endif()

file(REMOVE_RECURSE "${extract_dir}")
file(ARCHIVE_EXTRACT INPUT "${archive}" DESTINATION "${extract_dir}")
file(TOUCH "${stamp}")
endif()

set(${name}_SOURCE_DIR "${extract_dir}/${top_dir}" PARENT_SCOPE)
endfunction()

# All ABIs are configured in parallel, only download once
file(MAKE_DIRECTORY "${LIBASS_DEPS_DIR}")
file(LOCK "${LIBASS_DEPS_DIR}/.lock" GUARD FILE TIMEOUT 900)

libass_fetch_source(LIBASS "${LIBASS_URL}" ${LIBASS_SHA256} "libass-${LIBASS_VERSION}")
libass_fetch_source(FREETYPE "${FREETYPE_URL}" ${FREETYPE_SHA256} "freetype-${FREETYPE_VERSION}")
libass_fetch_source(FRIBIDI "${FRIBIDI_URL}" ${FRIBIDI_SHA256} "fribidi-${FRIBIDI_VERSION}")
libass_fetch_source(HARFBUZZ "${HARFBUZZ_URL}" ${HARFBUZZ_SHA256} "harfbuzz-${HARFBUZZ_VERSION}")

file(LOCK "${LIBASS_DEPS_DIR}/.lock" RELEASE)
Loading
Loading