Library / SDK
ywl5320/wlmedia avatar
ywl5320/wlmedia

wlmedia: an Android and HarmonyOS Next player SDK with FFmpeg under it

Android&HarmonyOS Next 音视频播放器SDK,几句代码即可实现音视频播放功能(支持:手机、车机系统、电视盒子等设备。支持:http、https、rtsp、rtp、rtmp、byte[]、加密视频和各种文件格式视频;包含视频截图、音轨选择、字幕选择、循环播放、设置软解或硬解、透明视频、变速变调、声道切换、无缝切换surface、多Surface渲染、视频比例设置、多实例音视频播放等。)~

837 stars162 forksJavaApache-2.0

At a glance

What is it?
wlmedia wraps an FFmpeg-based engine in a Java player class so an Android or HarmonyOS Next app can play almost any protocol, including encrypted byte arrays, with one surface widget and a handful of callbacks. It is a binary SDK with a closed source sale option, so the fit depends on whether your team can work from a prebuilt AAR rather than from source.
Who is it for?
wlmedia suits app teams that need wide protocol coverage, FFmpeg parameter control, transparent video or multi surface rendering without building their own decoder layer, and it is a poor fit for projects that need to read the player source, ship under a licence that forbids closed components, or support a platform outside Android and HarmonyOS Next.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 119 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One WlPlayer class covers the decode, protocol and rendering stack

wlmedia is a player SDK for Android and HarmonyOS Next that positions itself around a short path from source to playback. The description is that a few lines of code are enough to get audio and video playing, on phones, in-car systems, TV boxes and watches. Underneath it sits FFmpeg, which is why the topic list carries ndk-ffmpeg-android and ffmpeg tags alongside android-player, harmonyos-player and unityplayer.

The API shape is deliberately flat. You construct a WlPlayer, attach a WlOnMediaInfoListener, hand it a URL with setSource, call prepare, and start from the onPrepared callback. Everything else hangs off that listener or off the widget that displays the video. The feature list is long and specific: media info reporting for audio and video, protocol coverage, AV1 decoding, audio-only, video-only and combined modes, software or hardware decoding selection, seamless surface switching, multiple simultaneous player instances, resuming playback after EOF by seeking again, media switching, FFmpeg parameter configuration, byte array sources, encrypted media playback, frame decoding, variable speed and pitch, transparent video, subtitle selection, built-in looping, connection timeout, cache size set on a time dimension, audio track selection, forced sample rate, forced channel count, video screenshots, first frame or arbitrary timestamp stills, arbitrary aspect ratio, rotation in 90 degree steps, mirroring, background colour, rendering to several surfaces at once, live PCM audio data and audio/video sync offset.

That breadth is the product. A team that needs transparent video on a car head unit or a KTV screen with two displays would otherwise assemble this from a decoder, a demuxer, a render pipeline and a sync layer. wlmedia hands it over as a dependency.

Gradle integration goes through JitPack with an explicit version

On Android the SDK is consumed as a Gradle dependency from JitPack, and the documented coordinate is pinned to a specific release rather than a floating version. The repositories block has to include the JitPack maven entry.

gradle
allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

dependencies {
        implementation 'com.github.ywl5320:wlmedia:4.2.0'
}

Two permissions are listed as the common ones: external storage read and internet access.

xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>

Since the native decoder is compiled per ABI, the project has to declare which ones it ships. The documented configuration filters four ABIs in the defaultConfig block.

gradle
defaultConfig {
    ndk {
        abiFilter("armeabi-v7a")
        abiFilter("arm64-v8a")
        abiFilter("x86")
        abiFilter("x86_64")
        }
}

Leaving the abiFilter list untouched means you package all four native binaries into your APK, which costs download size on every install. Picking only the ones your devices need is a decision the integrating team has to make, and the documentation offers no guidance on which to drop.

WlSurfaceView and WlTextureView cover two rendering needs

Video output goes through one of two widgets. WlSurfaceView is the plain path for ordinary playback, and WlTextureView is the one to use when the video needs transparency, movement or rotation. Both are declared in the layout with a match_parent size, which means the video fills the parent by default and any scaling has to be requested afterwards.

The binding step is the same for both. You look the widget up by id and call setWlPlayer with the player instance, then optionally adjust presentation. The setters exposed in the documented sequence cover not clearing the last rendered frame, scale mode through the WlScaleType constants, rotation through WlRotateType constants, and mirroring through WlMirrorType constants.

The clear-last-frame option deserves a note because it is the difference between a black gap and a frozen image when a new source starts. Setting it to false keeps the previous frame visible on the surface, which is the behaviour you want for a playlist that should not flash. The choice of WlTextureView for transparency is not incidental either, since the project lists transparent video playback as a supported capability with its own demonstration, and separately supports external OpenGL rendering for engines such as Unity and Cocos2d. When the video has to composite over your own graphics rather than sit behind them, the texture route is the one that makes that possible.

The listener carries media info, load progress and completion reasons

Everything the player reports comes back through one listener interface, and the completion callback is the part worth reading carefully. It is handed a WlCompleteType value that distinguishes six outcomes, and the documented switch covers normal end of stream, a playback error where the message field holds the reason, a stop you triggered yourself, a source switch made while playing, a timeout, and the start of each new loop iteration.

That taxonomy is more useful than a single error string, because a timeout and a decode error need different handling, and a deliberate stop is not a failure at all. The onLoad callback reports load status with a progress percentage and a speed value, so a buffering indicator can be wired straight to it. onTimeInfo reports the current playback time and the buffer time as doubles, and onSeekFinish fires when a seek completes, which is the point at which a seeking flag can be cleared.

The remaining callbacks are one-shot lifecycle signals. onPrepared fires when the source is ready asynchronously, which is where start belongs. onFirstFrameRendered tells you the first video frame is actually on the surface, which is a better moment to hide a placeholder than onPrepared is. A separate media info listener provides the stream details, and the feature list describes those as audio sample rate, channel count and duration, plus video width, height, frame rate and duration.

HarmonyOS Next uses ohpm and an XComponent controller

The HarmonyOS Next side is packaged separately from the Android one. The repository has two top-level module directories, wlmedia_android and wlmedia_hm, so the two platforms are separate builds rather than one artefact with conditional code. The HarmonyOS package is published on the ohpm registry and installed with a single command.

bash
ohpm i @ywl5320/libwlmedia

The permission model differs there too. The HarmonyOS configuration lives in module.json5 and declares the internet permission in a requestPermissions array.

json
"requestPermissions": [
    {
    "name": "ohos.permission.INTERNET"
    }
]

Rendering uses the ArkUI XComponent, with a WlComponentController constructed from the player instance and passed to the component as its controller. The controller carries the surface type, so the player and the UI element have to be wired together before rendering starts.

typescript
let wlPlayer: WlPlayer = new WlPlayer();
let wlComponentController: WlComponentController = new WlComponentController(this.wlPlayer);
...
XComponent({
        type: XComponentType.SURFACE,
        controller: this.wlComponentController
    })
    .width('100%')
    .height('100%')

The ArkUI example follows the same lifecycle shape as Android, with aboutToAppear creating the player and an object literal implementing the listener, where onPrepared calls start on the player.

The performance comparison is pictures, not numbers

The repository includes a performance section that compares against exoplayer on a Xiaomi Redmi Note 7 using the file big_buck_bunny_cut.mp4. The comparison is presented as images rather than tables of figures, with separate columns for exoplayer, wlplayer without OpenGL, wlplayer with OpenGL, and a wlplayer profiler view. The Android section of the same document shows short screen recordings for normal playback, transparent video, multi surface rendering, multi instance playback, audio playback and volume in decibels, and the HarmonyOS section repeats the same set.

So the honest read is that the comparison exists as evidence of attention to rendering overhead, but it cannot be turned into a claim about frame rates or memory, because no numbers are published alongside the images. Anyone evaluating wlmedia for a performance-critical player should treat this section as a demonstration that the rendering paths work, and measure on their own hardware.

The same point applies to the rest of the feature list. Each item is a checkbox in the documentation, which tells you the capability exists in the shipped binary but not how it behaves at the edges, how much memory a given mode costs, or which devices are affected.

Apache-2.0 on paper, with the source offered separately

The repository carries an Apache-2.0 licence and a LICENSE file, and the top-level layout is small: .gitignore, .gradle, LICENSE, README.md, README_EN.md, a doc directory, wlmedia_android and wlmedia_hm. The README is published in both Chinese and English, with README_EN.md as the counterpart.

One line in the documentation complicates the licence picture: it states that the source code is available for sale and gives a contact address. That means the public repository is not the full source of the shipped library, so the Apache-2.0 grant on the repository is not the same thing as receiving the complete implementation under that licence. Teams whose compliance rules require the full source of every linked binary component need to settle that question with the maintainer before shipping, and that is a licensing question rather than a technical one.

The maintenance picture has a gap worth planning around. The last push to the repository was on 2026-06-30, while the newest release is 4.2.0 from 2025-04-05, preceded by 4.0.1 from 2025-02-06 and 4.0.0 from 2024-12-15. Upgrading means checking what changed in the source between the tag you use and the current head.

Editorial conclusion

wlmedia suits app teams that need wide protocol coverage, FFmpeg parameter control, transparent video or multi surface rendering without building their own decoder layer, and it is a poor fit for projects that need to read the player source, ship under a licence that forbids closed components, or support a platform outside Android and HarmonyOS Next. Before adopting, confirm the published AAR matches your target ABI set, ask the maintainer directly whether the source sale covers your licence terms, and check that the 4.2.0 artifact on JitPack still matches the behaviour you need, since the last push was on 2026-06-30 while the newest tag is 4.2.0 from 2025-04-05.

Frequently asked questions

How do I add wlmedia to an Android project?

Add the JitPack repository to your repositories block and depend on the published coordinate, com.github.ywl5320:wlmedia:4.2.0. You also need to declare the external storage read and internet permissions, and filter the native ABIs you ship.

Which protocols can wlmedia play?

The feature list names file, http, https, udp, rtmp, rtp, rtsp and byte array sources, along with AV1 decoding and encrypted audio and video playback. Connection timeout and cache size are configurable on top of that.

How do I play transparent video in wlmedia?

Use WlTextureView rather than WlSurfaceView, since the texture widget is the one intended for transparency, movement and rotation. Bind the player to it with setWlPlayer the same way as with the surface view.

How do I install wlmedia on HarmonyOS Next?

Install the package from the ohpm registry with ohpm i @ywl5320/libwlmedia, declare the internet permission in module.json5, and render through an XComponent whose controller is a WlComponentController built from the player.

Is the wlmedia source code available?

The documentation states that the source code is available for sale and lists a contact address for enquiries, so the published repository is not the complete implementation. Ask the maintainer what a source purchase covers for your licence terms.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. Releases
  5. ywl5320/wlmedia on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ywl5320-wlmedia.svg)](https://hysenlabs.com/projects/ywl5320-wlmedia)

Was this useful?