Repository navigation
alpha-video 1.0.0
·
0 commits
to af17379948ebeb3eae5289020dabc8f601f6ccf2
since this release
Transparent video for Android, iOS, React Native and every modern browser: VP8 or VP9 WebM with alpha, and dual-stream VP8, VP9 or AV1.
Install
| Platform | Package |
|---|---|
| React Native | npm install react-native-alpha-video react-native-range-source |
| Android | dev.mediacache:alpha-video:1.0.0, with alpha-video-vpx (VP8, VP9) and alpha-video-av1 (AV1) |
| iOS, Swift Package Manager | https://github.com/MediaCacheDev/alpha-video, products AlphaVideoVPX and AlphaVideoAV1 |
| iOS, CocoaPods | pod 'alpha-video', '1.0.0' |
| Web | npm install alpha-video-web |
See the README for usage, and the demo app to compare it with other transparent formats.
Changes
First public release.
- Plays single-stream VP9 WebM with alpha (YUVA) on Android, iOS and the web. On Android and iOS a C++ core demuxes with libwebm's parser and decodes with libvpx 1.14.0 (VP9, with row multithreading) and dav1d 1.5.1 (AV1), without FFmpeg; the web decodes in WebAssembly with FFmpeg 6.1's VP9 decoder and dav1d. iOS renders with Metal, Android with OpenGL ES on a
TextureView. - On Android, two MediaCodec decoders decode colour and alpha in hardware, told the clip's colour range and matrix by the same rules as the C++ core. They take dual-stream WebM (colour and alpha in separate VP9 or AV1 tracks), and standard alpha WebM too: the demuxer hands each block's BlockAdditional, a VP9 frame of the alpha, to the second decoder. The view picks the path from the file, and sends it to MediaCodec's software decoders once the hardware decoder hasn't 2 instances free, then to the C++ core. Where the GPU has
GL_EXT_YUV_target, the shader reads the decoders' raw YUV and converts it with the clip's matrix itself, since drivers can ignore the colour tags of a software decoder's frames (BT.709 AV1 drew as BT.601 on a Snapdragon 778G withc2.android.av1-dav1d). Without the extension the driver converts. A VP9 track in a profile no MediaCodec decoder lists (profile 1, which agbrpalpha track encodes to) sends the file to the C++ core instead. Elsewhere the C++ core decodes dual-stream VP9, and dual-stream AV1 on dav1d (8- to 12-bit, drawn at 8 bits), in every playback mode, and expands a limited-range alpha track to the full 0-255. iOS plays dual-stream AV1 this way too. 10-bit VP9 reportsonErroron the C++ core. MediaCodec's software decoders are asked for 8-bit output, since their 10-bit P010 frames drew blank on Adreno. - VP8 everywhere VP9 plays, with its alpha in BlockAdditional (the YUVA WebM FFmpeg and libvpx write) or in a second VP8 track. The core reads each keyframe's colour space and clamping bits as FFmpeg's VP8 decoder does: BT.601, limited range unless the clamping bit says full. libvpx decodes it on Android and iOS (the vpx module, whose libraries already held the VP8 decoder), MediaCodec (
video/x-vnd.on2.vp8) on Android, and on the web<video>in Chromium and Firefox, WebCodecs (vp8) and FFmpeg's VP8 decoder. - The Android
decoderprop (setDecoderonAlphaVideoView) forces the engine:mediacodec(hardware per track where an instance is free, else software),mediacodec-hw,mediacodec-sworsoftware(the C++ core). A forced engine reportsonErrorrather than fall back. The default,auto, takes MediaCodec's hardware decoders, else its software ones, else the C++ core.onLoadreports the engine and decoders used, e.g.mediacodec-hw (c2.qti.vp9.decoder)orsoftware (dav1d). iOS and the web accept the prop. - Colour is converted with the clip's range and matrix (limited or full; BT.601, BT.709 or BT.2020), matching FFmpeg's own conversion. An untagged clip is taken as limited range, BT.601 up to 720x576 and BT.709 above. Odd frame sizes keep their last chroma column and row.
- Playback modes for the software path:
stream(the default: keepsstreamPrefetchAheadframes decoded after the shown one, 1 or more, and drops each frame once played; with verbose logging on, each pass logs the fewest frames it had ahead and how often it ran out),preload(decode every frame once) andstreamAndPreload. A global decode queue (useDecodeQueue) keeps many players from saturating the CPU. - Sources:
https://,file://, absolute paths,asset://(Android assets, the iOS bundle, the web root),res/rawnames andcontent://on Android. On Android and iOS, http(s) files are read by range requests as they play, through the range-source add-on, withsource.headerssent with every request: the stream modes start with the first frames, a seek fetches the Cues and the cluster it lands in, and a server without range support works too. Between plays the bytes are kept on disk in the app's cache folder (storage:'auto','disk','memory'or'none';maxStorageBytes, default 512 MB), partially, so a clip played through plays again offline;cacheKeynames the stored copy. - Playback control:
play,pause,stop,seekToFrameandseekToTime, pluspaused,autoPlay,loopandplaybackSpeed. WithautoPlayoff the first frame shows, in every mode. Events:onLoad(frames, size and decoder),onErrorandonEnd. - The software decoders are codec modules, so an app ships only those it uses: vpx (libvpx, VP8 and VP9) and av1 (dav1d), each behind a versioned C plugin interface (
cpp/AlphaVideoDecoderPlugin.h) and registering itself. Android:dev.mediacache:alpha-videoplays through MediaCodec alone, andalpha-video-vpxandalpha-video-av1add the software decoders, each its own AAR and native library. iOS: Swift Package Manager productsAlphaVideoVPXandAlphaVideoAV1(no core-only product, as iOS has no platform decoder for these files), pod subspecsalpha-video/VPXandalpha-video/AV1(pod 'alpha-video'has both). React Native: one package, both codecs unless the app'spackage.jsonlists them ("react-native-alpha-video": { "codecs": ["vpx"] }), read by Gradle andpod install. A file whose codec has no module reportsonErrorwith the codeNO_DECODERand a message naming the module;AlphaVideoCodecs.softwareDecoderslists what's registered. The core parses AV1 sequence headers itself, so the web demuxer has no dav1d either. On the web each codec module is its own lazily loaded module: FFmpeg's VP8 and VP9 decoders (1.2 MB) or dav1d (480 KB), loaded only for streams they decode. - Android decoder status:
getDecoderStatus(withsoftwareDecoders),getDecoderInfo,getMaxDecoderInstancesandgetActiveDecoderCount. - React Native:
AlphaVideoViewon both the new architecture (a Fabric view, and a TurboModule for the decoder status) and the old one. On react-native-web it plays throughalpha-video-web, a dependency:<video>where the browser keeps the alpha, otherwise WebCodecs or WebAssembly decoding drawn in WebGL2, so the alpha shows in Safari and for dual-stream files too. ThewebDecoderprop forces an engine, and web errors carry acode.sourcetakesheaders, and on the web aBlobor byte source too. alpha-video-webfor plain JS/TS and React, fromweb/. Its canvas engines run the C++ core's demuxer (libwebm's parser) in WebAssembly, reading the file by HTTP range requests as it plays through range-source-web (an npm dependency ofalpha-video-web): playback starts with the first frames, a seek fetches the Cues and the cluster it lands in, and a server without range support works too. Between plays a URL's bytes are kept in OPFS, else IndexedDB (storage, default'auto';maxStorageBytes, default 512 MB), so a clip played through plays again with no requests.<video>does the same through range-source's Service Worker, which an app registers before rendering (registerRangeSourceWorker, re-exported): it reads by range from the same store, sendsheaders, and plays Blobs, bytes and byte sources. Without the worker,<video>takes a URL without headers, or a Blob as ablob:URL of itself; other sources play on a canvas, anddecoder: 'browser'with one of them reportsNEEDS_SERVICE_WORKER.srctakes a URL (withheaders), aBlob, bytes or a byte source of the app's own;cacheKeynames the stored copy. The canvas engines share one WebGL2 context, so a page can show more of them than the browser's limit of about 16 contexts. The demuxer module is 183 KB (63 KB gzipped).- range-source is an add-on the player finds at runtime, and includes by default: a dependency of
dev.mediacache:alpha-video(dev.mediacache:range-source), the pod'sSourcesubspec, and the Swift package's default traitSource. React Native apps installreact-native-range-sourcebeside the player. An app can leave it out (Gradleexclude, naming the pod's subspecs,traits: []from a package, or not installing it); the player then downloads a URL whole into a temporary file for each play, and logs once that range-source isn't installed. An Xcode app project can't turn a package's traits off, so SwiftPM apps added in Xcode always have it. - Data sources, for apps that fetch, cache or decrypt the bytes themselves: range-source's
RangeDataSourceon Android and iOS, registered by name inRangeDataSourcesforsource.dataSource, one for this player andalpha-video-gpu.dev.mediacache:range-source-media3adapts a Media3DataSource.Factory(OkHttp, Cronet,CacheDataSource). Without range-source, a data source reportsonErrorwith the codeNO_SOURCE_MODULE. - Standalone Android and iOS libraries.
- MIT. The native core bundles libwebm's parser (BSD-3-Clause), the vpx module libvpx (BSD-3-Clause) and the av1 module dav1d (BSD-2-Clause);
alpha-video-webbundles libwebm's parser, FFmpeg's VP8 and VP9 decoders (LGPL-2.1-or-later) in its vpx Workers only, and dav1d in its AV1 Workers. Their notices are inTHIRD_PARTY_NOTICES.mdandweb/THIRD_PARTY_NOTICES.md. - Android libraries are linked for 16 KB pages.
Assets
| File | What |
|---|---|
AlphaVideoLibvpx.xcframework.zip, AlphaVideoDav1d.xcframework.zip |
libvpx 1.14.0 and dav1d 1.5.1 for iOS (device and simulator), the binary targets Package.swift downloads |
alpha-video-1.0.0-ios.zip |
The iOS sources and both xcframeworks, which the CocoaPods pod downloads |
prebuilt-libvpx1.14.0-dav1d1.5.1.tar.gz |
The prebuilt static libraries for Android and iOS, which scripts/fetch-prebuilt.sh unpacks into prebuilt/ so a git clone can build |
SHA256SUMS |
Checksums of the above |
Licence
The code in this repository is MIT. The native players bundle libwebm's parser and libvpx (BSD-3-Clause, plus the WebM patent grant) and dav1d (BSD-2-Clause), all unmodified. The web player decodes VP8 and VP9 with FFmpeg 6.1 (LGPL-2.1-or-later). See THIRD_PARTY_NOTICES.md and web/THIRD_PARTY_NOTICES.md.