Warning
This project is still in development.
hlmedia is currently in an early and unstable state. Some features may be incomplete, broken, or subject to change at any time.
You can try the latest experimental builds from the nightly releases, but expect bugs and rough edges.
hlmedia is a HashLink native video playback library for Heaps.
It plays local MP4 files with H.264 video and optional AAC audio. FFmpeg handles
demuxing and decoding, video frames are uploaded to Heaps textures, and audio is
sent to an AudioSink supplied by your application. Software-decoded YUV420P
and NV12 frames are uploaded as native planes and converted with a shader;
unsupported formats still use the RGBA fallback path.
Hardware decoding can be requested from Haxe. It is opt-in and falls back to software by default when the requested backend is unavailable.
At the moment, MP4/H.264 is the only supported video format. Support for more containers and codecs is planned for future releases.
The library is still early. Use the nightly builds for testing, but expect API and behavior changes.
VideoPlayer uses OpenALSink as Default sink, else will be used NullAudioSink - video plays silently. Pass your own
hlmedia.audio.AudioSink implementation to route decoded audio to
miniaudio, or another backend.
The OpenAL example uses this setup:
-cp .
-cp ../../
-lib heaps
-lib hlsdl
-lib hlopenal
-hl simple.hl
-main Main
-D hlmediaBasic player code:
final video = new hlmedia.VideoPlayer({
loop: true,
audioSink: new OpenALSink()
});
video.open("res/video/video.mp4");
video.play();
final bitmap = video.createBitmap(s2d);
override function update(dt:Float) {
video.update(dt);
}Controls such as pause, seek, volume, loop, and callbacks are available on the
same VideoPlayer instance:
video.pause();
video.play();
video.seek(12.5);
video.setVolume(0.75);
video.setLoop(false);
video.onStart = () -> trace("started");
video.onFinish = () -> trace("finished");
video.onTime(3.5, () -> trace("3.5 seconds"));You can also open a Heaps resource:
video.open(hxd.Res.load("video/video.mp4"));examples/openalcontains an OpenALAudioSinkwrapper.examples/miniaudiocontains a miniaudioAudioSinkwrapper.examples/performancecompares software, hardware, and RGBA fallback paths.
See examples/README.md for build notes.
hlmedia.VideoPlayer is the main class.
hlmedia.MediaBuild.getInfo() reports the selected distribution, FFmpeg
linkage, version, configuration, and license.
new(?options)creates a player.open(pathOrResource)opens a local file path orhxd.res.Resource.play(),pause(), andstop()control playback.close()closes the current video while keeping the player reusable.dispose()closes the video and releases the player's GPU textures.seek(seconds)jumps to a position.update(dt)must be called every frame.createBitmap(s2d)creates aVideoBitmapfor normal Heaps 2D rendering.getTexture()returns the current output texture for custom rendering.getInfo()returnsVideoInfoafter opening a file.getStats()returns aVideoStatsperformance snapshot.setVolume(value)clamps volume to0...1.setLoop(enabled)changes loop behavior after construction.setAudioSink(sink)replaces the audio output implementation.
VideoBitmap does not own its player or textures. Remove the bitmap from its
scene before calling VideoPlayer.dispose(). Do not reuse a disposed player.
onStart,onFinish, andonTime(seconds, callback)provide playback callbacks.
Useful state:
isPlayingisPauseddurationtimedroppedFramespresentedFramesaverageDecodeTimeMsaverageUploadTimeMscurrentVideoQueueSizehardwareDecodeActive
Player options:
{
?audioSink: hlmedia.audio.AudioSink,
?loop: Bool,
?volume: Float,
?startPaused: Bool,
?videoDecodeMode: hlmedia.types.VideoDecodeMode,
?allowHardwareFallback: Bool,
?preferNativePixelFormat: Bool,
?threadedDecode: Bool,
?maxQueuedVideoFrames: Int,
?targetAudioBufferFrames: Int,
?prebufferSeconds: Float
}Decode modes:
Software;
HardwareAuto;
HardwareD3D11VA;
HardwareDXVA2;
HardwareVAAPI;
HardwareVideoToolbox;
HardwareCUDA;
HardwareD3D12VA;Defaults:
{
videoDecodeMode: Software,
allowHardwareFallback: true,
preferNativePixelFormat: true,
threadedDecode: false,
maxQueuedVideoFrames: 6,
targetAudioBufferFrames: 12000,
prebufferSeconds: 0
}Pixel formats exposed by native frames are in hlmedia.types.VideoPixelFormat:
RGBA, YUV420P, NV12, and P010. P010 is reserved for future support.
Both archives expose the same Haxe/native API and contain hlmedia.hdll. Choose
one runtime variant; do not deploy both together.
hlmedia-windows.zip is the standard, flexible build. It uses the
broad LGPL shared FFmpeg SDK and contains hlmedia.hdll, the required FFmpeg
DLLs, licenses, and build information. Use it when broad codec/container
support matters and deploying FFmpeg DLLs is acceptable.
hlmedia-windows-game.zip statically links a compact LGPL-only
FFmpeg build into hlmedia.hdll. It contains no FFmpeg DLLs and supports only
local MP4/MOV playback with H.264 video and AAC audio. It includes licenses,
the pinned FFmpeg commit, the exact configure command, and build information.
The corresponding FFmpeg source package can be generated locally with
deps/ffmpeg/create-source-package.sh when compliance or relinking materials
are required.
Requirements:
- HashLink native runtime
- Haxe and Heaps
- FFmpeg development package with:
avformatavcodecavutilswresampleswscale
Download shared dependencies and build the shared distribution:
./scripts/ci/download-hashlink.ps1
./scripts/ci/download-ffmpeg-shared.ps1
cmake --preset windows -DFFMPEG_ROOT="$env:FFMPEG_SHARED_ROOT"
cmake --build --preset windows
./scripts/ci/stage-package.ps1 -Variant shared -Preset windows `
-OutputDirectory dist/hlmedia-windows
./scripts/ci/verify-package.ps1 -Variant shared `
-Directory dist/hlmedia-windowsBuild the pinned compact FFmpeg SDK from an x64 MSVC-enabled MSYS2 shell:
export FFMPEG_SOURCE="$PWD/out/deps/ffmpeg-source"
export FFMPEG_BUILD_DIR="$PWD/out/deps/ffmpeg-game-build"
export FFMPEG_INSTALL_DIR="$PWD/out/deps/ffmpeg-game-static"
bash ./deps/ffmpeg/build-game-static.shThen build and package hlmedia from PowerShell:
$env:FFMPEG_GAME_STATIC_ROOT = "$pwd/out/deps/ffmpeg-game-static"
cmake --preset game -DFFMPEG_ROOT="$env:FFMPEG_GAME_STATIC_ROOT"
cmake --build --preset game
./scripts/ci/stage-package.ps1 -Variant game -Preset game `
-OutputDirectory dist/hlmedia-windows-game
./scripts/ci/verify-package.ps1 -Variant game `
-Directory dist/hlmedia-windows-gameSet HASHLINK to the HashLink SDK root before configuring. Both FFmpeg SDKs use
the include/ and lib/ layout under FFMPEG_ROOT.
Place these files next to your HashLink executable, or make them available on
PATH:
hlmedia.hdllavformat-*.dllavcodec-*.dllavutil-*.dllswresample-*.dllswscale-*.dll
Each example build runs examples/copy-runtime.ps1, which copies runtime files
from the staged shared package by default. Pass -Source to use another staged
runtime package.
Release packages should also include:
LICENSELICENSE_FFMPEG.md
The GitHub workflow publishes them in hlmedia-windows.zip and hlmedia-windows-game.zip.
HLMEDIA_WITH_LIBYUV=ON/OFFHLMEDIA_DISTRIBUTION=SHARED/GAMEHLMEDIA_FFMPEG_LINKAGE=SHARED/STATIC
hlmedia is MIT licensed. Release packages include shared FFmpeg DLLs, which
keep their own license terms.
The shared distribution uses the BtbN LGPL shared FFmpeg build. The game-static
distribution disables GPL, nonfree, version 3, and external codec libraries.
See LICENSE_FFMPEG.md and the locally generated source package for compliance
details.
Use MP4/H.264/AAC files. A good default encoding command is documented in
tools/encode_mp4_h264_aac.md.
Examples use examples/res/video/video.mp4 by default.