📺 tha_player

Native, network‑only video player for Flutter with modern MX/VLC‑style UX. Android uses ExoPlayer; iOS uses AVPlayer. Includes gestures, thumbnails on seek, DRM (Android), fullscreen, BoxFit, and more.


✨ Features

  • âś… Native engines: ExoPlayer (Android) and AVPlayer (iOS)
  • âś… Gestures: tap to show/hide, double‑tap seek, long‑press skip, horizontal scrub, vertical volume/brightness
  • âś… Controls: play/pause, speed, fullscreen (manual or auto), lock, BoxFit (contain/cover/fill/fitWidth/fitHeight)
  • âś… Quality, audio, and subtitle track selection with data saver toggle
  • âś… Configurable retry/backoff, error callbacks, PiP playback controls
  • âś… Thumbnails: WebVTT sprites or image sequences during seek preview (cached in-memory)
  • âś… DRM (Android): Widevine and ClearKey
  • âś… M3U playlist parsing utility
  • âś… Overlay support (watermark, logos)

📦 Install

Add to pubspec.yaml:

dependencies:
  tha_player: ^0.4.0

Then:

flutter pub get

🚀 Quick Start

import 'package:tha_player/tha_player.dart';

final ctrl = ThaNativePlayerController.single(
  ThaMediaSource(
    'https://storage.flutter-io.cn/gtv-videos-bucket/sample/BigBuckBunny.mp4',
    // Optional VTT thumbnails
    // thumbnailVttUrl: 'https://example.com/thumbs.vtt',
  ),
  autoPlay: true,
  playbackOptions: ThaPlaybackOptions(
    maxRetryCount: 5,
    initialRetryDelay: Duration(milliseconds: 800),
  ),
);

// In build:
AspectRatio(
  aspectRatio: 16 / 9,
  child: ThaModernPlayer(
    controller: ctrl,
    doubleTapSeek: Duration(seconds: 10),
    longPressSeek: Duration(seconds: 3),
    autoHideAfter: Duration(seconds: 3),
    initialBoxFit: BoxFit.contain,
  ),
)

Fullscreen

Tap the fullscreen icon in the control bar. Playback position and state are preserved when entering/exiting fullscreen.

BoxFit

Choose between contain, cover, fill, fitWidth, and fitHeight from the menu.

Track Selection

Use the control bar to switch quality, audio, or subtitle tracks at runtime. You can also fetch tracks directly:

final qualities = await ctrl.getVideoTracks();
final audios = await ctrl.getAudioTracks();
final subtitles = await ctrl.getSubtitleTracks();
await ctrl.selectAudioTrack(audios.first.id);
await ctrl.selectSubtitleTrack(null); // disable captions

Lock Controls

Use the lock icon to prevent controls/gestures; unlock with the floating button.

DRM (Android)

final ctrl = ThaNativePlayerController.single(
  ThaMediaSource(
    'https://my.cdn.com/drm/manifest.mpd',
    drm: ThaDrmConfig(
      type: ThaDrmType.widevine, // or ThaDrmType.clearKey
      licenseUrl: 'https://license.server/wv',
      headers: {'Authorization': 'Bearer <token>'},
      // clearKey: '{"keys":[{"kty":"oct","k":"...","kid":"..."}]}'
    ),
  ),
);

Thumbnails (WebVTT)

Provide a .vtt with sprites or images and optional #xywh regions:

ThaMediaSource(
  'https://example.com/video.m3u8',
  thumbnailVttUrl: 'https://example.com/thumbs.vtt',
)

đź›  Platform Notes

  • Android: ExoPlayer backend with Media3; Widevine/ClearKey supported; per‑item HTTP headers.
  • iOS: AVPlayer backend; fitWidth/fitHeight approximate via resizeAspect.
  • Keep‑screen‑on is enabled during playback (Android/iOS).
  • Playability depends on device codecs, stream, and network.

Thumbnails are cached in-memory. Call clearThumbnailCache() if you need to purge the cache.

Resilient playback

ThaPlaybackOptions lets you tweak retry/backoff behaviour and rebuffer handling. Failures are surfaced via ThaNativeEvents.error and the onError callback on ThaModernPlayer.

Custom HTTP (Android)

Provide a bespoke OkHttpClient to inject interceptors or caching:

Register the factory inside your Android Application:

class App : FlutterApplication() {
  override fun onCreate() {
    super.onCreate()
    ThaPlayerPlugin.setHttpClientFactory {
      OkHttpClient.Builder()
        .addInterceptor(MyHeaderInterceptor())
        .cache(Cache(cacheDir.resolve("video"), 100L * 1024L * 1024L))
        .build()
    }
  }
}

Set the factory before creating any Flutter controllers so every instance shares the same client.

16 KB Page Size Support

This plugin does not ship custom native decoder binaries. If you add native libraries, link them with a max page size compatible with 16 KB systems (e.g., -Wl,-z,max-page-size=16384 on Android NDK).


đź§Ş Example

See example/ for a runnable app that demonstrates the modern controls, gestures, fullscreen, and thumbnails.


đź’– Support

If this package helps you, consider a tip:

  • Tron (TRC20): TLbwVrZyaZujcTCXAb94t6k7BrvChVfxzi

📣 Contributing

Issues and PRs are welcome! Please file bugs or ideas at the issue tracker.


đź“„ License

MIT — see LICENSE.

Libraries

tha_player
Top-level library export for tha_player.
tha_player_method_channel
tha_player_platform_interface