[鸿蒙PC三方库适配实战] 跨平台媒体播放器 mpv 的 鸿蒙PC 平台迁移实践
3.3 编写交叉编译配置 在 cross_file.txt 中配置鸿蒙PC 的交叉编译工具链和标准库路径: [binaries] c = 'aarch64-linux-ohos-clang' cpp = 'aarch64-linux-ohos-clang++' ar = 'llvm-ar' strip = 'llvm-strip' [host_machine] system = 'linux' c
摘要:本文详细介绍了如何将功能强大的开源媒体播放器 mpv 适配到 鸿蒙PC 平台。文章将系统性地讲解如何利用 lycium_plusplus 构建框架,处理基于 Meson 构建系统的 C/C++ 项目在鸿蒙环境下的交叉编译流程,展示如何处理复杂的依赖链管理(FFmpeg、libplacebo、libass 等)、pkg-config 路径配置、头文件路径修复以及 HNP 包生成的完整实践。
本文是软件鸿蒙化迁移实践系列文章之一,专注于 C/C++ 原生库的鸿蒙适配,为开发者提供完整的迁移指南。
欢迎加入开源鸿蒙PC社区:https://harmonypc.csdn.net/
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
AtomGit仓库地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_mpv_pc
项目信息说明
| 项目 | 说明 |
|---|---|
| 名称 | mpv (libmpv) |
| 开源协议 | LGPL-2.1-or-later |
| 源码版本 | 0.41.0 |
| 目标平台 | 鸿蒙 PC |
| 依赖项 | Meson, Ninja, FFmpeg, libplacebo, libass |
| 操作系统平台 | WSL Ubuntu 24.04 |
一、背景介绍
1.0 功能与效果
mpv 在本实践中的预期能力如下:
功能:提供功能强大的媒体播放核心库 libmpv,支持广泛的音视频格式、字幕渲染(ASS/SSA)、硬件加速、GPU 渲染等核心功能。作为嵌入式播放器库,可被鸿蒙应用通过 NAPI 调用。
效果:在鸿蒙平台上提供高质量的音视频播放能力,便于在鸿蒙应用开发中实现视频播放器、媒体浏览器、字幕渲染等场景的多媒体功能。
1.1 什么是 鸿蒙PC HNP 生态
HNP(Harmony Native Package)是 鸿蒙PC 的原生包格式,lycium 是增强型构建框架,支持自动下载源码、交叉编译(arm64-v8a、armeabi-v7a)、一键生成 HNP 包以及开源声明聚合(README.OpenSource)。C/C++ 原生库的适配是鸿蒙系统生态建设中的重要一环。
1.2 为什么适配 C/C++ 原生库会有难度
常见挑战包括:
- 构建系统差异:mpv 使用 Meson + Ninja 构建系统,需要配置交叉编译工具链(aarch64-linux-ohos-clang/clang++)和交叉编译配置文件。
- 复杂依赖链:mpv 依赖 FFmpeg(音视频编解码)、libplacebo(GPU 渲染)、libass(字幕渲染),而 libass 又依赖 fontconfig、harfbuzz、fribidi、freetype2 等,形成多层依赖树。
- pkg-config 路径管理:Meson 依赖 pkg-config 查找依赖库,需要正确配置所有依赖库的 pkgconfig 路径,包括传递依赖。
- 头文件路径问题:部分依赖库(如 libplacebo、fribidi)的安装路径不规范,需要手动添加头文件搜索路径。
- 链接路径配置:部分依赖库安装在非标准路径(如 usr/lib 而非 lib),需要在交叉编译配置中显式指定链接路径。
- 鸿蒙平台特性限制:需要禁用 Android 特定的音频后端(opensles)、X11/Wayland 图形后端等鸿蒙不支持的特性。
1.3 mpv 简介
mpv 是一个由 mpv-player 社区开发的自由开源媒体播放器(以 libmpv 库形式提供)。其主要特点包括:
- 强大的播放核心:基于 FFmpeg,支持广泛的音视频格式和编解码器。
- GPU** 加速渲染**:通过 libplacebo 实现高质量的 GPU 加速视频渲染。
- 字幕支持:内置 libass,完美支持 ASS/SSA 高级字幕格式。
- 嵌入式****设计:libmpv.so 可被其他应用通过 API 调用,适合嵌入式场景。
- 跨平台特性:原生支持 Windows、macOS、Linux,本次适配扩展到 鸿蒙PC 平台。
- 开源地址:
- GitHub:https://github.com/mpv-player/mpv
- AtomGit:https://atomgit.com/weixin_62765017/mpv
二、环境准备
2.0 系统要求
- 开发环境:Ubuntu 24.04(推荐 WSL 2)
- 核心工具:Meson(v0.60+)、Ninja、GCC/G++、Git
- 构建框架:lycium_plusplus
- 鸿蒙 SDK:鸿蒙PC SDK(提供交叉编译工具链 aarch64-linux-ohos-clang/clang++)
- 目标架构:arm64-v8a(AArch64)
2.0.1 扩展阅读与参考教程
下方汇总展示了多位老师在鸿蒙 鸿蒙PC 适配方面的高质量教程。若在前提准备(环境、工具链、框架)部分还有不清楚的地方,可参考这些文章进一步学习。 以下资源不分先后顺序,均具有参考价值。
| 资源类型 | 描述 | 链接 |
|---|---|---|
| 三方库交叉编译环境(Ubuntu) | 在 Ubuntu 中搭建鸿蒙PC 三方库交叉编译构建开发环境 | 👉 点击查看 |
| 三方库交叉编译环境(macOS) | 在 macOS 中搭建鸿蒙PC 三方库交叉编译开发环境 | 👉 点击查看 |
| 基础环境搭建 | Windows 10 上安装和使用 WSL 2、安装 Ubuntu 24 详细指南 | 👉 点击查看 |
| Mac 移植指南 | 鸿蒙PC命令行适配指南(Mac 版) | 👉 点击查看 |
| Win 移植指南 | 鸿蒙PC 生态三方软件移植:开发环境搭建及三方库移植指南 | 👉 点击查看 |
| 全流程适配指南 | OpenHarmony Linux 命令行工具适配实战:基于 Cursor × WSL 的 tree 2.2.1 交叉编译与 HNP 打包全流程指南 | 👉 点击查看 |
| 官方构建文档 | 新脚手架:社区维护的鸿蒙PC 生态命令行工具构建框架 lycium_plusplus(原 build 仓库为旧方式,请以本仓库为准) | 👉 点击查看 |
2.1 lycium_plusplus 框架
lycium_plusplus 是本次适配工作的核心工具,主要用于统一管理各类第三方库的构建流程,通过规范编译、依赖与打包逻辑,实现三方库在目标平台上高效、稳定地编译与集成,是整个适配环节中保障构建一致性与可维护性的关键支撑。
# 克隆 lycium_plusplus 项目
git clone https://gitcode.com/OpenHarmonyPCDeveloper/lycium_plusplus.git
cd lycium_plusplus
2.2 Meson 与交叉编译环境
由于 mpv 是 C/C++ 项目,使用 Meson + Ninja 构建系统,需要 鸿蒙PC SDK 提供的交叉编译工具链。
# 安装 Meson 和 Ninja
sudo apt-get install -y meson ninja-build
# 验证安装
meson --version
ninja --version
# 配置 鸿蒙PC SDK 环境变量
export OHOS_SDK=/home/weishuo/ohos-sdk/linux
三、实战:以 mpv 为例的适配步骤
3.1 创建项目目录结构
在 lycium_plusplus/thirdparty/ 目录下为 mpv 创建专属目录。
cd lycium_plusplus/thirdparty
mkdir -p mpv
cd mpv
3.2 创建 HPKBUILD 文件
HPKBUILD 作为 lycium 框架的核心构建脚本,完整定义了三方库的元信息配置及下载、编译、打包等全流程构建逻辑。
#!/bin/bash
# -----------------------------------------------------------------------------
# mpv HPKBUILD - OpenHarmony 鸿蒙适配
# -----------------------------------------------------------------------------
pkgname=mpv
pkgver=0.41.0
pkgrel=0
pkgdesc="A free, open source, and cross-platform media player"
url="https://mpv.io"
archs=("arm64-v8a")
license=("LGPL-2.1-or-later")
depends=("FFmpeg" "libplacebo")
makedepends=("meson" "ninja")
autounpack=false
downloadpackage=false
buildtools="meson"
srcpath="${LYCIUM_ROOT}/../Projects/${pkgname}"
builddir="${pkgname}-${pkgver}"
# -----------------------------------------------------------------------------
# prepare():准备源码
# -----------------------------------------------------------------------------
prepare() {
if [ -d "$srcpath" ]; then
echo "Using local source from: $srcpath"
mkdir -p "$builddir"
cp -rf "$srcpath"/* "$builddir/"
find "$builddir" -name "*.bak" -type f -delete 2>/dev/null || true
find "$builddir" -name "*:Zone.Identifier" -type f -delete 2>/dev/null || true
echo "Prepare completed in: $builddir"
else
echo "ERROR: Source not found at $srcpath"
exit 1
fi
}
# -----------------------------------------------------------------------------
# build():编译构建
# -----------------------------------------------------------------------------
build() {
cd "$builddir"
# 设置交叉编译环境变量
export CC="${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang"
export CXX="${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang++"
export AR="${OHOS_SDK}/native/llvm/bin/llvm-ar"
export RANLIB="${OHOS_SDK}/native/llvm/bin/llvm-ranlib"
export STRIP="${OHOS_SDK}/native/llvm/bin/llvm-strip"
export CFLAGS="--target=aarch64-linux-ohos --sysroot=${OHOS_SDK}/native/sysroot -O2 -fPIC -I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include"
export CXXFLAGS="--target=aarch64-linux-ohos --sysroot=${OHOS_SDK}/native/sysroot -O2 -fPIC -I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include"
export LDFLAGS="--target=aarch64-linux-ohos --sysroot=${OHOS_SDK}/native/sysroot"
# 创建 Meson 交叉编译配置文件
cat > ohos-cross.ini << EOF
[binaries]
c = '${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang'
cpp = '${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang++'
ar = '${OHOS_SDK}/native/llvm/bin/llvm-ar'
strip = '${OHOS_SDK}/native/llvm/bin/llvm-strip'
pkgconfig = 'pkg-config'
[properties]
pkg_config_path = ['${LYCIUM_ROOT}/usr/FFmpeg/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib/pkgconfig', '${LYCIUM_ROOT}/usr/libass/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/fontconfig/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/libexpat/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/harfbuzz/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/lib/pkgconfig', '${LYCIUM_ROOT}/usr/freetype2/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/zlib/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/libpng/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/brotli/${ARCH}/lib/pkgconfig']
[built-in options]
c_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-O2', '-fPIC', '-I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include']
cpp_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-O2', '-fPIC', '-I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include']
c_link_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib']
cpp_link_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib']
[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'
EOF
# 设置 FFmpeg、libplacebo 和 libass 及其所有依赖的 pkg-config 路径
export PKG_CONFIG_PATH="${LYCIUM_ROOT}/usr/FFmpeg/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib/pkgconfig:${LYCIUM_ROOT}/usr/libass/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/fontconfig/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libexpat/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/harfbuzz/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/lib/pkgconfig:${LYCIUM_ROOT}/usr/freetype2/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/zlib/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libpng/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/brotli/${ARCH}/lib/pkgconfig:${PKG_CONFIG_PATH}"
export PKG_CONFIG_LIBDIR="${LYCIUM_ROOT}/usr/FFmpeg/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib/pkgconfig:${LYCIUM_ROOT}/usr/libass/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/fontconfig/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libexpat/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/harfbuzz/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/lib/pkgconfig:${LYCIUM_ROOT}/usr/freetype2/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/zlib/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libpng/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/brotli/${ARCH}/lib/pkgconfig"
echo "PKG_CONFIG_PATH: $PKG_CONFIG_PATH"
pkg-config --list-all | grep -E 'libav|libplacebo|libass' || true
# 设置 LDFLAGS 包含 libplacebo 的库路径
export LDFLAGS="-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib ${LDFLAGS}"
# Meson 配置:禁用图形界面和不支持的特性
meson setup ohos-build \
--cross-file ohos-cross.ini \
--prefix=/usr \
--buildtype=release \
-Dgpl=false \
-Dcplayer=false \
-Dlibmpv=true \
-Dbuild-date=false \
-Dtests=false \
-Dfuzzers=false \
-Dmanpage-build=disabled \
-Dcdda=disabled \
-Ddvbin=disabled \
-Ddvdnav=disabled \
-Djavascript=disabled \
-Djpeg=disabled \
-Dlcms2=disabled \
-Dlibarchive=disabled \
-Dlibavdevice=disabled \
-Dlibbluray=disabled \
-Dlua=disabled \
-Drubberband=disabled \
-Dsdl2-gamepad=disabled \
-Dsdl2-audio=disabled \
-Dsdl2-video=disabled \
-Dsubrandr=disabled \
-Duchardet=disabled \
-Dvapoursynth=disabled \
-Dzimg=disabled \
-Dalsa=disabled \
-Daudiounit=disabled \
-Dcoreaudio=disabled \
-Djack=disabled \
-Dopenal=disabled \
-Dopensles=disabled \
-Doss-audio=disabled \
-Dpipewire=disabled \
-Dpulse=disabled \
-Dsndio=disabled \
-Dgl=disabled \
-Degl-android=disabled \
-Degl-x11=disabled \
-Degl-wayland=disabled \
-Ddrm=disabled \
-Dgbm=disabled \
-Dx11=disabled \
-Dwayland=disabled \
-Dcocoa=disabled \
-Dmacos-media-player=disabled \
-Dios-gl=disabled \
-Dandroid-media-ndk=disabled \
-Dcaca=disabled \
-Dplain-gl=disabled \
-Dzlib=enabled \
> "$buildlog" 2>&1
ret=$?
if [ $ret -ne 0 ]; then
echo "Meson configuration failed!"
cat "$buildlog" >&2
cd "$OLDPWD"
return $ret
fi
# 编译
ninja -C ohos-build >> "$buildlog" 2>&1
ret=$?
cd "$OLDPWD"
return $ret
}
# -----------------------------------------------------------------------------
# check():验证构建产物
# -----------------------------------------------------------------------------
check() {
echo "The test must be on an OpenHarmony device!"
}
# -----------------------------------------------------------------------------
# package():打包产物
# -----------------------------------------------------------------------------
package() {
: ${destdir:=${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}}
# 进入源码目录
cd ${builddir}
# 手动复制编译产物
mkdir -p "${destdir}/usr/bin"
mkdir -p "${destdir}/usr/lib"
mkdir -p "${destdir}/usr/include/mpv"
# 复制 mpv 可执行文件
if [ -f ohos-build/mpv ]; then
cp -f ohos-build/mpv "${destdir}/usr/bin/mpv"
chmod +x "${destdir}/usr/bin/mpv"
echo " ✅ Installed mpv binary"
fi
# 复制 libmpv 库文件
if ls ohos-build/libmpv.so* 1> /dev/null 2>&1; then
find ohos-build -maxdepth 1 -name 'libmpv.so*' -type f -exec cp -f {} "${destdir}/usr/lib/" \;
echo " ✅ Installed libmpv library"
fi
# 复制头文件
if [ -d include/mpv ]; then
cp -rf include/mpv/* "${destdir}/usr/include/mpv/"
echo " ✅ Installed mpv headers"
fi
find "${destdir}" -name "*.bak" -type f -delete 2>/dev/null || true
find "${destdir}" -name "*:Zone.Identifier" -type f -delete 2>/dev/null || true
echo "Package completed!"
return 0
}
# -----------------------------------------------------------------------------
# archive():打包成 tar.gz 和 HNP
# -----------------------------------------------------------------------------
archive() {
export HNP_TOOL="${HNP_TOOL:-${OHOS_SDK}/toolchains/hnpcli}"
mkdir -p ${LYCIUM_ROOT}/output/$ARCH
# 打包 tar.gz
pushd ${LYCIUM_ROOT}/usr/${pkgname}/${ARCH} > /dev/null 2>&1
tar -zcf ${LYCIUM_ROOT}/output/$ARCH/${pkgname}_${pkgver}.tar.gz .
echo "Archive completed: ${LYCIUM_ROOT}/output/$ARCH/${pkgname}_${pkgver}.tar.gz"
popd > /dev/null 2>&1
# 打包 HNP
if [ -f "${HNP_TOOL}" ]; then
cp ${LYCIUM_ROOT}/../thirdparty/${pkgname}/hnp.json ${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}/
${HNP_TOOL} pack \
-i ${LYCIUM_ROOT}/usr/${pkgname}/${ARCH} \
-o ${LYCIUM_ROOT}/output/$ARCH/
echo "Archive completed: ${LYCIUM_ROOT}/output/$ARCH/${pkgname}.hnp"
else
echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
fi
}
# -----------------------------------------------------------------------------
# cleanbuild():清理构建产物
# -----------------------------------------------------------------------------
cleanbuild() {
echo "Cleaning build artifacts for ${pkgname}..."
# 清理构建目录
rm -rf "${LYCIUM_ROOT}/../thirdparty/${pkgname}/${builddir}"
# 清理 output
rm -rf "${LYCIUM_ROOT}/output/${pkgname}"*
# 清理 usr 产物
rm -rf "${LYCIUM_ROOT}/usr/${pkgname}"
echo "Clean completed"
}

3.3 创建 hnp.json(包元数据)
hnp.json 文件用于描述 HNP 包的元信息,类似于 package.json。
{
"type": "hnp-config",
"name": "mpv",
"version": "0.41.0",
"description": "A free, open source, and cross-platform media player",
"license": "LGPL-2.1-or-later",
"arch": "arm64-v8a",
"install": {
"bin": ["usr/bin/mpv"],
"lib": ["usr/lib/libmpv.so*"],
"include": ["usr/include/mpv"]
}
}

3.4 创建 README.OpenSource(开源声明)
为了满足开源合规性,需要提供 README.OpenSource 文件来声明许可证和依赖库信息。
[
{
"Name": "mpv",
"License": "LGPL-2.1-or-later",
"License File": "https://github.com/mpv-player/mpv/blob/master/Copyright",
"Version Number": "0.41.0",
"Owner": "your-email@example.com",
"Upstream URL": "https://github.com/mpv-player/mpv/archive/refs/tags/v0.41.0.tar.gz",
"Description": "mpv is a free (as in freedom) media player for the command line. It supports a wide variety of media file formats, audio and video codecs, and subtitle types."
},
{
"Name": "FFmpeg",
"License": "LGPL-2.1-or-later",
"License File": "https://github.com/FFmpeg/FFmpeg/blob/master/LICENSE.md",
"Version Number": "8.0",
"Owner": "your-email@example.com",
"Upstream URL": "https://ffmpeg.org/releases/ffmpeg-8.0.tar.xz",
"Description": "FFmpeg is a complete, cross-platform solution to record, convert and stream audio and video. It includes libavcodec, libavformat, libavutil, libswscale, libswresample and other libraries."
},
{
"Name": "libplacebo",
"License": "LGPL-2.1-or-later",
"License File": "https://github.com/haasn/libplacebo/blob/master/LICENSE",
"Version Number": "7.362",
"Owner": "your-email@example.com",
"Upstream URL": "https://github.com/haasn/libplacebo/archive/refs/tags/v7.362.tar.gz",
"Description": "Reusable library for GPU-accelerated video/image rendering primitives, with a focus on vulkan"
},
{
"Name": "libass",
"License": "ISC",
"License File": "https://github.com/libass/libass/blob/master/COPYING",
"Version Number": "0.17.1",
"Owner": "your-email@example.com",
"Upstream URL": "https://github.com/libass/libass/releases/download/0.17.1/libass-0.17.1.tar.gz",
"Description": "LibASS is an SSA/ASS subtitles rendering library"
},
{
"Name": "fontconfig",
"License": "MIT",
"License File": "https://gitlab.freedesktop.org/fontconfig/fontconfig/-/blob/main/COPYING",
"Version Number": "2.14.2",
"Owner": "your-email@example.com",
"Upstream URL": "https://www.freedesktop.org/software/fontconfig/release/fontconfig-2.14.2.tar.gz",
"Description": "Font configuration and customization library"
},
{
"Name": "freetype",
"License": "FTL",
"License File": "https://sourceforge.net/p/freetype/code/ci/master/docs/FTL.TXT",
"Version Number": "2.13.0",
"Owner": "your-email@example.com",
"Upstream URL": "https://sourceforge.net/projects/freetype/files/freetype2/2.13.0/freetype-2.13.0.tar.xz",
"Description": "FreeType is a freely available software library to render fonts"
},
{
"Name": "harfbuzz",
"License": "MIT",
"License File": "https://github.com/harfbuzz/harfbuzz/blob/main/COPYING",
"Version Number": "7.1.0",
"Owner": "your-email@example.com",
"Upstream URL": "https://github.com/harfbuzz/harfbuzz/releases/download/7.1.0/harfbuzz-7.1.0.tar.xz",
"Description": "HarfBuzz is an OpenType text shaping engine"
},
{
"Name": "fribidi",
"License": "LGPL-2.1-or-later",
"License File": "https://github.com/fribidi/fribidi/blob/master/COPYING",
"Version Number": "1.0.13",
"Owner": "your-email@example.com",
"Upstream URL": "https://github.com/fribidi/fribidi/releases/download/v1.0.13/fribidi-1.0.13.tar.xz",
"Description": "GNU FriBidi is an implementation of the Unicode Bidirectional Algorithm"
}
]

3.5 创建 HPKCHECK 检查脚本
HPKCHECK 是 lycium 框架的构建检查脚本,用于在编译前验证环境是否满足构建要求。
#!/bin/bash
# HPKCHECK for mpv
# 检查 mpv 构建产物
echo "=== Checking mpv build artifacts ==="
# 检查 mpv 可执行文件
if [ -f "$1/usr/bin/mpv" ]; then
echo "✓ mpv binary found"
file "$1/usr/bin/mpv"
else
echo "⚠ Warning: mpv binary not found"
fi
# 检查 libmpv 库文件
if [ -f "$1/usr/lib/libmpv.so" ]; then
echo "✓ Shared library found: libmpv.so"
file "$1/usr/lib/libmpv.so"
elif [ -f "$1/usr/lib/libmpv.a" ]; then
echo "✓ Static library found: libmpv.a"
file "$1/usr/lib/libmpv.a"
else
echo "✗ ERROR: No libmpv library found!"
exit 1
fi
# 检查头文件
if [ -d "$1/usr/include/mpv" ]; then
echo "✓ Header directory found: mpv/"
ls "$1/usr/include/mpv/"
else
echo "✗ ERROR: Header directory not found!"
exit 1
fi
echo "=== Check completed ==="

四、编译流程与完整示例
4.1 环境准备
配置用于前置环境检查与变量设置,通过指定 鸿蒙PC SDK 路径、验证 Meson/Ninja 环境,为 lycium_plusplus 构建三方库提供基础运行环境。
# 1. 确保 OpenHarmony SDK 已安装
export OHOS_SDK=/home/weishuo/ohos-sdk/linux
# 2. 确保 Meson 和 Ninja 已安装
meson --version
ninja --version
4.2 创建项目结构并执行编译
通过目录操作、脚本创建、清理缓存、执行构建指令,完成 lycium_plusplus 中 mpv 三方库的从零构建全流程。
cd lycium_plusplus/thirdparty
mkdir -p mpv
cd mpv
# 创建 HPKBUILD 文件(内容见第三章)
vim HPKBUILD
cd ../../lycium
# 清理历史构建记录(可选,但推荐)
grep -v 'mpv' usr/hpk_build.csv > usr/hpk_build.csv.tmp
mv usr/hpk_build.csv.tmp usr/hpk_build.csv
rm -rf ../thirdparty/mpv/mpv-0.41.0
rm -rf output/*/mpv*
# 开始构建
./build.sh mpv
4.3 构建成功输出示例

4.4 验证产物
构建成功后,编译产物会统一输出至 output 目录,包含标准 tar 压缩包与鸿蒙专用 hnp 格式包。

五、鸿蒙PC 上验证结果(测试)

先解压 mpv 编译产物,进入库目录后查看文件,验证该 arm64 架构 ELF 共享库的有效性,再为其添加执行权限,最后执行鸿蒙系统签名操作
# 解压mpv编译产物
tar -zxf mpv_0.41.0.tar.gz
# 进入库目录
cd usr/lib
# 查看文件是否存在
ls
# 验证是否为鸿蒙 arm64 有效库(核心验证)
file libmpv.so.2.5.0
# 查看ELF魔数,确认架构合法
od -N 4 libmpv.so.2.5.0
通过 strings 命令提取 libmpv.so.2.5.0 共享库中的字符串信息,并结合 grep 过滤出版本号相关内容,成功匹配到 mpv v0.41.0-UNKNOWN 标识,验证了该动态库的版本正确性与编译完整性
strings libmpv.so.2.5.0 | grep "0.41.0"

六、常见问题与解决方案(FAQ)
Q1:Meson 配置时报错 “ERROR: Unknown options: libplacebo_ldflags”?
A:这是因为 libplacebo_ldflags 不是有效的 Meson 选项。正确的做法是在交叉编译配置文件的 c_link_args 中添加库路径:
[built-in options]
c_link_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib']
cpp_link_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib']
不要在 meson setup 命令中使用 -Dlibplacebo_ldflags 参数。
Q2:编译时报错 “fatal error: libplacebo/colorspace.h: No such file or directory”?
A:这是因为 libplacebo 的头文件路径未正确配置。需要在 CFLAGS 和 CPPFLAGS 中添加:
export CFLAGS="--target=aarch64-linux-ohos --sysroot=${OHOS_SDK}/native/sysroot -O2 -fPIC -I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include"
export CXXFLAGS="--target=aarch64-linux-ohos --sysroot=${OHOS_SDK}/native/sysroot -O2 -fPIC -I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include"
同时在 Meson 交叉编译配置中添加:
[built-in options]
c_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-O2', '-fPIC', '-I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include']
cpp_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-O2', '-fPIC', '-I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include']
Q3:编译时报错 “fatal error: libplacebo/config.h: No such file or directory”?
A:这是因为 libplacebo 构建时生成的 config.h 没有被安装到产物目录。需要在 libplacebo 的 HPKBUILD 的 package() 函数中添加:
# 复制构建生成的 config.h
if [ -f ohos-build/src/include/libplacebo/config.h ]; then
cp -f ohos-build/src/include/libplacebo/config.h "${destdir}/usr/include/libplacebo/"
echo " ✅ Installed config.h"
fi
然后重新构建 libplacebo:
# 清理 libplacebo 缓存
cat lycium/usr/hpk_build.csv | grep -v libplacebo > /tmp/hpk_temp.csv
mv /tmp/hpk_temp.csv lycium/usr/hpk_build.csv
rm -rf lycium/usr/libplacebo
rm -rf thirdparty/libplacebo/libplacebo-*/ohos-build
# 重新构建
./lycium/build.sh libplacebo
Q4:链接时报错 “ld.lld: error: unable to find library -lplacebo”?
A:这是因为链接器找不到 libplacebo 的库文件。libplacebo 安装在 usr/lib 而不是 lib。需要在 Meson 交叉编译配置中添加链接路径:
[built-in options]
c_link_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib']
cpp_link_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib']
Q5:配置时报错 “ERROR: Dependency “libass” not found”?
A:这是因为 pkg-config 路径不完整。libass 依赖 fontconfig、harfbuzz、fribidi、freetype2 等库,需要在 pkg_config_path 中包含所有这些库的路径:
[properties]
pkg_config_path = [
'${LYCIUM_ROOT}/usr/FFmpeg/${ARCH}/lib/pkgconfig',
'${LYCIUM_ROOT}/usr/libass/${ARCH}/lib/pkgconfig',
'${LYCIUM_ROOT}/usr/fontconfig/${ARCH}/lib/pkgconfig',
'${LYCIUM_ROOT}/usr/harfbuzz/${ARCH}/lib/pkgconfig',
'${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/lib/pkgconfig',
'${LYCIUM_ROOT}/usr/freetype2/${ARCH}/lib/pkgconfig',
'${LYCIUM_ROOT}/usr/zlib/${ARCH}/lib/pkgconfig',
'${LYCIUM_ROOT}/usr/libpng/${ARCH}/lib/pkgconfig',
'${LYCIUM_ROOT}/usr/brotli/${ARCH}/lib/pkgconfig'
]
注意:fribidi 的路径是 usr/lib/pkgconfig 而不是 lib/pkgconfig。
Q6:编译时报错 “fatal error: fribidi.h: No such file or directory”?
A:这是因为 fribidi 的头文件安装在 usr/include/fribidi/ 而不是 include/fribidi/。这是 fribidi 的 HPKBUILD 中 prefix 设置为 /usr 导致的路径问题。
解决方案是在依赖 libass 的项目中显式添加 fribidi 头文件路径:
export PKG_CONFIG_PATH="${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/lib/pkgconfig:${PKG_CONFIG_PATH}"
如果仍有问题,可以直接添加头文件路径到 CFLAGS:
export CFLAGS="${CFLAGS} -I${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/include"
Q7:配置时报错 “dependency SLES/OpenSLES_Android.h not found”?
A:这是因为 mpv 默认启用了 Android 的 OpenSL ES 音频后端。鸿蒙不支持这个后端,需要显式禁用:
meson setup ohos-build \
--cross-file ohos-cross.ini \
...
-Dopensles=disabled \
...
Q8:package 阶段产物只有 hnp.json,没有实际的库文件?
A:这是因为 package() 函数中的路径问题。需要在 package 函数开头添加 cd ${builddir} 进入正确的构建目录:
package() {
: ${destdir:=${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}}
# 进入源码目录(关键!)
cd ${builddir}
# 复制产物...
}
Q9:复制库文件时报错 “cp: -r not specified; omitting directory”?
A:这是因为通配符 libmpv.so* 匹配到了目录 libmpv.so.2.5.0.p。需要使用 find 命令只复制文件:
# 错误的做法
cp -f ohos-build/libmpv.so* "${destdir}/usr/lib/"
# 正确的做法
find ohos-build -maxdepth 1 -name 'libmpv.so*' -type f -exec cp -f {} "${destdir}/usr/lib/" \;
Q10:修改 HPKBUILD 后 lycium 直接跳过构建?
A:这是 lycium 的构建缓存机制导致的。lycium 使用 hpk_build.csv 文件记录构建状态,如果存在记录则会跳过构建。解决方案是删除缓存文件:
# 删除构建状态缓存
cat lycium/usr/hpk_build.csv | grep -v mpv > /tmp/hpk_temp.csv
mv /tmp/hpk_temp.csv lycium/usr/hpk_build.csv
# 同时清理旧产物
rm -rf thirdparty/mpv/mpv-*/ohos-build
rm -rf lycium/usr/mpv
rm -f lycium/output/*/*mpv*
# 重新构建
./lycium/build.sh mpv
Q11:为什么没有mpv可执行文件?
A:这是因为配置中使用了 -Dcplayer=false 禁用了命令行播放器。这是有意为之的,因为:
- 鸿蒙是图形化系统,没有传统终端环境
- 命令行播放器无法直接使用
- 缺少 X11/Wayland 图形后端
- 鸿蒙应用通过 NAPI 调用 libmpv.so 实现播放功能
如果需要 mpv 可执行文件,需要将 -Dcplayer=false 改为 -Dcplayer=true,并适配图形后端。
七、技术总结
本次成功将 mpv 适配至 鸿蒙PC 平台,形成了一套可复用的 Meson 类项目的鸿蒙移植范式。核心要点如下:
- 标准化适配模板:建立了 Meson 类项目的 HPKBUILD 配置规范,统一交叉编译与依赖管理流程
- 复杂依赖链管理:通过正确配置 pkg-config 路径,解决多层依赖树(FFmpeg、libplacebo、libass 等)的查找问题
- 关键问题解决:通过修复 libplacebo 头文件路径、添加链接路径配置、禁用不支持的音频/图形后端,有效解决编译和链接问题
- 产物规范化:使用 README.OpenSource 规范化开源声明格式,确保开源合规性
- 通用适配能力:方案可直接迁移至 VLC、GStreamer 等同类多媒体播放器的鸿蒙移植
八、结语
本次实践成功将 mpv 移植至 鸿蒙PC 平台,验证了 lycium_plusplus 框架对 Meson 构建系统项目交叉编译的支撑能力。通过规范 HPKBUILD 构建流程、正确配置复杂依赖链的 pkg-config 路径、修复头文件和链接路径问题、禁用不支持的平台特性等关键措施,有效解决了适配中的兼容性与构建问题,为同类开源项目迁移至鸿蒙生态提供了可复用的实践参考,助力鸿蒙原生多媒体应用生态的完善与发展。
提示:本文基于 mpv 0.41.0 版本进行适配。不同版本的依赖和构建脚本可能有所差异,建议在适配前先熟悉目标项目的 meson.build 和构建配置文件。
更多推荐




所有评论(0)