vlc-android: 编译自己的libvlc
概述
VLC 媒体播放器作为一款由志愿者开发团队精心维护的自由、开源且跨平台的多媒体播放器,能轻松驾驭绝大多数多媒体文件,无论是本地磁盘中的视频、音频,还是来自网络的流媒体协议. VLC for Android 支持网络串流,无论是基于 HLS 的自适应流媒体,还是 DASH 流,都能稳定播放。对于有 NAS(网络附属存储)设备,或者需要访问共享驱动器的用户而言,它也提供了便捷的浏览支持。在兼容性方面,其早期版本支持 Android 2.2 及以上,而当前版本则要求 Android 4.2 及更高版本,同时对 ARM v7、ARMv8/A arch 64、MIPS 和 x86 等多种硬件架构提供支持,甚至还兼容 Android TV ,大大拓展了其使用场景。
编译环境
- 系统: ubuntu 22.04
- ndk: 27
- gradle: 8.13
- cmake: 4.0.3
编译
环境依赖
sudo apt install automake ant autopoint cmake build-essential libtool-bin \patch pkg-config protobuf-compiler ragel subversion unzip git \openjdk-8-jre openjdk-8-jdk flex python wget
编译命令:
# 设置AndroidSDK 和AndroidNDK
export ANDROID_NDK=~/Android/Sdk/ndk/27.0.12077973/
export ANDROID_SDK=~/Android/Sdk/
./buildsystem/compile.sh -l -a arm64
一些问题
1. cmake 3.22 太旧
编译vlc-android出错:-- The C compiler identification is Clang 18.0.1-- The CXX compiler identification is Clang 18.0.1CMake Warning (dev) at path-to-Android/Sdk/ndk/27.0.12077973/build/cmake/flags.cmake:46 (if):Policy CMP0057 is not set: Support new IN_LIST if() operator. Run "cmake--help-policy CMP0057" for policy details. Use the cmake_policy command toset the policy and suppress this warning.IN_LIST will be interpreted as an operator when the policy is set to NEW.Since the policy is not set the OLD behavior will be used.Call Stack (most recent call first):/usr/share/cmake-3.22/Modules/Platform/Android-Clang.cmake:23 (include)/usr/share/cmake-3.22/Modules/Platform/Android-Clang-C.cmake:1 (include)/usr/share/cmake-3.22/Modules/CMakeCInformation.cmake:48 (include)CMakeLists.txt:3 (project)This warning is for project developers. Use -Wno-dev to suppress it.CMake Error at /home/anson/Android/Sdk/ndk/27.0.12077973/build/cmake/flags.cmake:46 (if):if given arguments:"hwaddress" "IN_LIST" "ANDROID_SANITIZE"Unknown arguments specifiedCall Stack (most recent call first):/usr/share/cmake-3.22/Modules/Platform/Android-Clang.cmake:23 (include)/usr/share/cmake-3.22/Modules/Platform/Android-Clang-C.cmake:1 (include)/usr/share/cmake-3.22/Modules/CMakeCInformation.cmake:48 (include)CMakeLists.txt:3 (project)
下载新版本cmake 编译安装
2. /usr/bin/install: cannot stat ‘…/…/share/vlc.appdata.xml’: No such file or directory
cp vlc/share/vlc.appdata.xml.in.in vlc/share/vlc.appdata.xml
3. kotlin-compiler-embeddable-1.6.10.jar 下载太慢
修改源:libvlcjni/build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.buildscript {ext.android_plugin_version = '8.11.0'ext.kotlin_version = '1.6.10'ext.kotlinx_version = '1.6.0'repositories {flatDir dirs: "gradle/plugins"maven { url "https://maven.aliyun.com/repository/public" } // 阿里云镜像maven { url "https://maven.aliyun.com/repository/gradle-plugin" } // 阿里云插件仓库mavenCentral() // 保留官方仓库作为 fallback google()}dependencies {classpath "com.android.tools.build:gradle:$android_plugin_version"classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'classpath 'com.vanniktech:gradle-maven-publish-plugin:0.25.2'}}allprojects {repositories {maven { url "https://maven.aliyun.com/repository/public" } // 阿里云镜像maven { url "https://maven.aliyun.com/repository/gradle-plugin" } // 阿里云插件仓库mavenCentral()google()}tasks.withType(Javadoc) {// Ignores errors from mavenAndroidJavadocs task// (reference: github.com/novoda/bintray-release/issues/71#issuecomment-164324255)options.addStringOption('Xdoclint:none', '-quiet')options.addStringOption('encoding', 'UTF-8')}}ext {libvlcVersion = '3.6.2'androidxLegacyVersion = '1.0.0'androidxAnnotationVersion = '1.7.1'}
使用(aar)播放.H264参考代码
输出文件: libvlcjni/libvlc/build/outputs/aar/libvlc-dev.aar
build.gradle
dependencies {implementation files("path-to-vlc-android/libvlcjni/libvlc/build/outputs/aar/libvlc-dev.aar");
}
h264_player.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><SurfaceView android:id="@+id/sv"android:layout_width="match_parent"android:layout_height="match_parent"/>
</RelativeLayout>
H264Player.java
import android.net.Uri;
import android.os.Bundle;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;import com.ansondroider.acore.BaseActivity;
import com.ansondroider.acore.Logger;
import com.nmbb.vlc.R;import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.Media;
import org.videolan.libvlc.MediaPlayer;
import org.videolan.libvlc.interfaces.IMedia;import java.util.ArrayList;public class H264Player extends BaseActivity {SurfaceView sv;String path = "/sdcard/test.h264";MediaPlayer vlcMp;LibVLC libVLC;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.h264_player);sv = (SurfaceView) findViewById(R.id.sv);sv.getHolder().addCallback(new SurfaceHolder.Callback() {@Overridepublic void surfaceCreated(SurfaceHolder surfaceHolder) {playH264();}@Overridepublic void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {}@Overridepublic void surfaceDestroyed(SurfaceHolder surfaceHolder) { }});if(!isPermissionReady(getRequiredPermissions()))getPermissions(getRequiredPermissions(), REQ_PERMS);}void playH264() {Logger.d(TAG, "playH264");if(libVLC == null) {// 初始化 LibVLC(可添加额外配置参数)ArrayList<String> options = new ArrayList<>();options.add("--no-drop-late-frames"); // 不丢弃延迟帧options.add("--no-skip-frames"); // 不跳过帧libVLC = new LibVLC(this, options);vlcMp = new MediaPlayer(libVLC);vlcMp.setEventListener(new MediaPlayer.EventListener() {@Overridepublic void onEvent(MediaPlayer.Event event) {Logger.d(TAG, "onEvent: " + event.type);switch (event.type) {case MediaPlayer.Event.EndReached:Logger.d(TAG, "播放结束");break;case MediaPlayer.Event.EncounteredError:Logger.e(TAG, "遇到错误:" + event.getRecordPath());break;}}});//设置显示的控件vlcMp.getVLCVout().setVideoView(sv);vlcMp.getVLCVout().attachViews();}// 创建媒体对象并指定格式参数Media media = new Media(libVLC, Uri.parse("file://" + path));// 关键:强制指定为 H.264 格式和解复用器media.addOption(":input-format=h264"); // 输入格式为 h264media.addOption(":demux=h264"); // 使用 h264 解复用器// 额外添加解码器选项(强制使用FFmpeg解码)//media.addOption(":codec=avcodec");media.setHWDecoderEnabled(true, false); // 启用硬件解码(可选)media.setEventListener(new Media.EventListener() {@Overridepublic void onEvent(Media.Event event) {Logger.d(TAG, "onEvent: " + event.type);if(event.type == Media.Event.MetaChanged){Logger.d(TAG, "媒体元数据改变");int trackCount = media.getTrackCount();for(int i = 0; i < trackCount; i++){IMedia.Track track = media.getTrack(i);if(track instanceof IMedia.VideoTrack){Logger.d(TAG, "视频轨道:" + track.type);Logger.d(TAG, "Size: " + ((IMedia.VideoTrack) track).width + "x" + ((IMedia.VideoTrack) track).height);}}}}});// 设置媒体并播放vlcMp.setMedia(media);media.release(); // 释放 media 对象vlcMp.play();}@Overrideprotected void onDestroy() {super.onDestroy();// 释放资源vlcMp.stop();vlcMp.release();libVLC.release();}
}
参考
- vlc-android
- Ubuntu 16.04 Compile VLC for Android Failed