zeroratehls 1.0.7 copy "zeroratehls: ^1.0.7" to clipboard
zeroratehls: ^1.0.7 copied to clipboard

A comprehensive Flutter SDK for seamless HLS (HTTP Live Streaming) video playback. This package provides a robust, feature-rich player with advanced capabilities including adaptive bitrate streaming, [...]

example/lib/main.dart

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:zeroratehls/models/zerorate_hls_player_events.dart';
import 'package:zeroratehls/models/zerorate_hls_player_options.dart';
import 'package:zeroratehls/utils/device_information.dart';
import 'package:zeroratehls_example/player_config.dart';
import 'package:zeroratehls/zerorate_hls_player.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  ZerorateHlsSDK.initialize();

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: PlayerTestScreen(),
    );
  }
}

class PlayerTestScreen extends StatefulWidget {
  const PlayerTestScreen({super.key});

  @override
  State<PlayerTestScreen> createState() => _PlayerTestScreenState();
}

class _PlayerTestScreenState extends State<PlayerTestScreen> {
  ZerorateHlsPlayer? _player;
  String _deviceInfo = 'Loading...';
  List<String> _eventLog = [];

  @override
  void initState() {
    super.initState();
    _initializePlayer();
    _loadDeviceInfo();
  }

  Future<void> _loadDeviceInfo() async {
    final info = await DeviceInformation.getDeviceInfo(context);
    if (mounted) {
      setState(() {
        final decoded = utf8.decode(base64Decode(info));
        final Map<String, dynamic> deviceData = json.decode(decoded);
        _deviceInfo = const JsonEncoder.withIndent('  ').convert(deviceData);
      });
    }
  }

  void _updatePlayer(ZerorateHlsPlayerOptions optionsOriginal) {
    final options = ZerorateHlsPlayerOptions(
      appId: optionsOriginal.appId,
      region: optionsOriginal.region,
      grantType: optionsOriginal.grantType,
      subscriberId: optionsOriginal.subscriberId,
      authUrl: optionsOriginal.authUrl,
      type: optionsOriginal.type,
      src: optionsOriginal.src,
      autoplay: optionsOriginal.autoplay,
      mediaType: optionsOriginal.mediaType,
      poster: optionsOriginal.poster,
      muted: optionsOriginal.muted,
      aspectRatio: optionsOriginal.aspectRatio,
      placeholder: optionsOriginal.placeholder,
      placeholderOnTop: optionsOriginal.placeholderOnTop,
      audioControlsConfiguration: optionsOriginal.audioControlsConfiguration,
      videoControlsConfig: optionsOriginal.videoControlsConfig,
      iconsColor: Colors.purple,
      eventListeners: {
        ZerorateHlsPlayerEventType.play: _handleEvent,
        ZerorateHlsPlayerEventType.pause: _handleEvent,
        ZerorateHlsPlayerEventType.seeked: _handleEvent,
        ZerorateHlsPlayerEventType.bufferingStart: _handleEvent,
        ZerorateHlsPlayerEventType.bufferingEnd: _handleEvent,
        ZerorateHlsPlayerEventType.error: _handleEvent,
        ZerorateHlsPlayerEventType.loaded: _handleEvent,
        ZerorateHlsPlayerEventType.positionChanged: _handleEvent,
        ZerorateHlsPlayerEventType.completed: _handleEvent,
        ZerorateHlsPlayerEventType.thumbnailGenerated: _handleEvent,
      },
      errorBuilder: (error) => Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.error, color: Colors.red, size: 48),
            const SizedBox(height: 16),
            Text(
              'An error occurred: ${error.toString()}',
              style: const TextStyle(color: Colors.red),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: () => _initializePlayer(),
              child: const Text('Retry'),
            ),
          ],
        ),
      ),
    );

    setState(() {
      _player = ZerorateHlsPlayer(
        options: options,
      );
      _eventLog.clear();
    });
  }

  void _handleEvent(ZerorateHlsPlayerEvent event) {
    if (event.type == ZerorateHlsPlayerEventType.positionChanged &&
        _eventLog.length > 10) {
      return;
    }

    setState(() {
      String eventData = '';
      if (event.data != null) {
        if (event.data is Duration) {
          eventData = _formatDuration(event.data);
        } else if (event.data is Map) {
          eventData = event.data.toString();
        } else {
          eventData = event.data.toString();
        }
      }

      _eventLog.add('${event.type}: $eventData');

      if (_eventLog.length > 100) {
        _eventLog = _eventLog.sublist(_eventLog.length - 100);
      }
    });
  }

  String _formatDuration(Duration duration) {
    String twoDigits(int n) => n.toString().padLeft(2, '0');
    final minutes = twoDigits(duration.inMinutes.remainder(60));
    final seconds = twoDigits(duration.inSeconds.remainder(60));
    return '$minutes:$seconds';
  }

  void _initializePlayer() {
    // _updatePlayer(PlayerConfig.defaultControlsVideo());
    _updatePlayer(PlayerConfig.liveVideo());
  }

  @override
  Widget build(BuildContext context) {
    final isAudio = _player?.options.type == MediaType.audio;

    Widget buildPlayerControls() {
      final isAudio = _player?.options.type == MediaType.audio;

      return Padding(
        padding: const EdgeInsets.symmetric(vertical: 8.0),
        child: Column(
          children: [
            // Playback controls
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                IconButton(
                  icon: const Icon(Icons.play_arrow),
                  onPressed: () => _player?.play(),
                  tooltip: 'Play',
                ),
                IconButton(
                  icon: const Icon(Icons.pause),
                  onPressed: () => _player?.pause(),
                  tooltip: 'Pause',
                ),
                IconButton(
                  icon: const Icon(Icons.replay_10),
                  onPressed: () {
                    final position = _player?.currentPosition;
                    if (position != null) {
                      _player?.seekTo(
                        Duration(seconds: position.inSeconds - 10),
                      );
                    }
                  },
                  tooltip: 'Rewind 10s',
                ),
                IconButton(
                  icon: const Icon(Icons.forward_10),
                  onPressed: () {
                    final position = _player?.currentPosition;
                    if (position != null) {
                      _player?.seekTo(
                        Duration(seconds: position.inSeconds + 10),
                      );
                    }
                  },
                  tooltip: 'Forward 10s',
                ),
              ],
            ),

            // Audio-specific controls
            if (isAudio)
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const Text('Playback Speed:'),
                  const SizedBox(width: 8),
                  for (final speed in [0.5, 1.0, 1.5, 2.0])
                    Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 4.0),
                      child: ElevatedButton(
                        onPressed: () => _player?.setPlaybackSpeed(speed),
                        style: ElevatedButton.styleFrom(
                          padding: const EdgeInsets.symmetric(horizontal: 8),
                        ),
                        child: Text('${speed}x'),
                      ),
                    ),
                ],
              ),
          ],
        ),
      );
    }

    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutterhls Player Test'),
      ),
      body: Column(
        children: [
          if (_player != null)
            SafeArea(
              child: AspectRatio(
                aspectRatio: _player!.options.aspectRatio ?? 16 / 9,
                child: _player!,
              ),
            )
          else
            const SizedBox(
              height: 40,
              child: Center(child: CircularProgressIndicator()),
            ),
          if ((_player!.options.type == MediaType.video &&
                  _player!.options.videoControlsConfig?.useDefaultControls ==
                      false) ||
              (_player!.options.type == MediaType.audio &&
                  _player!.options.audioControlsConfiguration
                          ?.useDefaultControls ==
                      false))
            buildPlayerControls(),
          Expanded(
            child: DefaultTabController(
              length: 2,
              child: Column(
                children: [
                  const TabBar(
                    tabs: [
                      Tab(text: 'Controls'),
                      Tab(text: 'Event Log'),
                    ],
                  ),
                  Expanded(
                    child: TabBarView(
                      children: [
                        SingleChildScrollView(
                          child: Column(
                            children: [
                              const SizedBox(height: 20),
                              if (isAudio) ...[
                                ElevatedButton(
                                  onPressed: () => _updatePlayer(
                                      PlayerConfig.defaultControlsAudio()),
                                  child: const Text('Default Audio Controls'),
                                ),
                                const SizedBox(height: 10),
                                ElevatedButton(
                                  onPressed: () => _updatePlayer(
                                      PlayerConfig.customAudioControls()),
                                  child: const Text('Custom Audio Controls'),
                                ),
                                const SizedBox(height: 10),
                                ElevatedButton(
                                  onPressed: () => _updatePlayer(
                                      PlayerConfig.fullyCustomAudioControls()),
                                  child: const Text('Fully Custom Audio UI'),
                                ),
                                ElevatedButton(
                                  onPressed: () => _updatePlayer(
                                      PlayerConfig.audioWithSpeedControl()),
                                  child: const Text('Audio with Speed Control'),
                                ),
                              ] else ...[
                                ElevatedButton(
                                  onPressed: () => _updatePlayer(
                                      PlayerConfig.defaultControlsVideo()),
                                  child: const Text('Default Video Controls'),
                                ),
                                const SizedBox(height: 10),
                                ElevatedButton(
                                  onPressed: () => _updatePlayer(
                                      PlayerConfig.onDemandVideo()),
                                  child: const Text('On-Demand Video'),
                                ),
                                const SizedBox(height: 10),
                                ElevatedButton(
                                  onPressed: () =>
                                      _updatePlayer(PlayerConfig.liveVideo()),
                                  child: const Text('Live Video'),
                                ),
                                ElevatedButton(
                                  onPressed: () => _updatePlayer(
                                      PlayerConfig.externalControlsVideo()),
                                  child: const Text('External Controls'),
                                ),
                              ],
                              // status information
                              Padding(
                                padding: const EdgeInsets.all(16.0),
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Text(
                                        'Media Type: ${_player?.options.type}'),
                                    Text(
                                        'Stream Type: ${_player?.options.mediaType}'),
                                    Text(
                                        'Autoplay: ${_player?.options.autoplay}'),
                                    Text('Muted: ${_player?.options.muted}'),
                                    if (_player?.options.type ==
                                            MediaType.video &&
                                        _player?.options.videoControlsConfig !=
                                            null)
                                      Text(
                                          'Seek Preview Enabled: ${_player?.options.videoControlsConfig?.enableSeekPreview}'),
                                  ],
                                ),
                              ),
                              ExpansionTile(
                                title: const Text('Device Information'),
                                children: [
                                  Padding(
                                    padding: const EdgeInsets.all(8.0),
                                    child: SingleChildScrollView(
                                      scrollDirection: Axis.horizontal,
                                      child: SelectableText(_deviceInfo),
                                    ),
                                  ),
                                ],
                              ),
                            ],
                          ),
                        ),
                        ListView.builder(
                          padding: const EdgeInsets.all(8),
                          itemCount: _eventLog.length,
                          itemBuilder: (context, index) {
                            return Padding(
                              padding: const EdgeInsets.symmetric(vertical: 2),
                              child: Text(
                                _eventLog[index],
                                style: const TextStyle(fontSize: 12),
                              ),
                            );
                          },
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
  }
}
0
likes
120
points
221
downloads

Publisher

verified publishersoa.live

Weekly Downloads

A comprehensive Flutter SDK for seamless HLS (HTTP Live Streaming) video playback. This package provides a robust, feature-rich player with advanced capabilities including adaptive bitrate streaming, seek preview, custom controls, subtitle support, picture-in-picture mode, and quality selection.

Homepage

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

better_player_plus, device_info_plus, ffmpeg_kit_flutter_new, flutter, gif_view, just_audio, media_kit, media_kit_libs_video, media_kit_video, package_info_plus, path_provider, plugin_platform_interface

More

Packages that depend on zeroratehls

Packages that implement zeroratehls