dart_vlc 0.3.0 copy "dart_vlc: ^0.3.0" to clipboard
dart_vlc: ^0.3.0 copied to clipboard

discontinuedreplaced by: media_kit
PlatformLinuxWindows
outdated

Flutter media playback, broadcast, recording & chromecast library. Based on libvlc.

example/lib/main.dart

import 'dart:io';
import 'dart:ui' as ui;
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:dart_vlc/dart_vlc.dart';

void main() async {
  await DartVLC.initialize(useFlutterNativeView: true);
  runApp(DartVLCExample());
}

class DartVLCExample extends StatefulWidget {
  @override
  DartVLCExampleState createState() => DartVLCExampleState();
}

class DartVLCExampleState extends State<DartVLCExample> {
  Player player = Player(
    id: 0,
    videoDimensions: VideoDimensions(640, 360),
    registerTexture: !Platform.isWindows,
  );
  MediaType mediaType = MediaType.file;
  CurrentState current = CurrentState();
  PositionState position = PositionState();
  PlaybackState playback = PlaybackState();
  GeneralState general = GeneralState();
  VideoDimensions videoDimensions = VideoDimensions(0, 0);
  List<Media> medias = <Media>[];
  List<Device> devices = <Device>[];
  TextEditingController controller = TextEditingController();
  TextEditingController metasController = TextEditingController();
  double bufferingProgress = 0.0;
  Media? metasMedia;

  @override
  void initState() {
    super.initState();
    if (this.mounted) {
      this.player.currentStream.listen((current) {
        this.setState(() => this.current = current);
      });
      this.player.positionStream.listen((position) {
        this.setState(() => this.position = position);
      });
      this.player.playbackStream.listen((playback) {
        this.setState(() => this.playback = playback);
      });
      this.player.generalStream.listen((general) {
        this.setState(() => this.general = general);
      });
      this.player.videoDimensionsStream.listen((videoDimensions) {
        this.setState(() => this.videoDimensions = videoDimensions);
      });
      this.player.bufferingProgressStream.listen(
        (bufferingProgress) {
          this.setState(() => this.bufferingProgress = bufferingProgress);
        },
      );
      this.player.errorStream.listen((event) {
        print('libvlc error.');
      });
      this.devices = Devices.all;
      Equalizer equalizer = Equalizer.createMode(EqualizerMode.live);
      equalizer.setPreAmp(10.0);
      equalizer.setBandAmp(31.25, 10.0);
      this.player.setEqualizer(equalizer);
    }
  }

  @override
  Widget build(BuildContext context) {
    bool isTablet;
    bool isPhone;
    final double devicePixelRatio = ui.window.devicePixelRatio;
    final double width = ui.window.physicalSize.width;
    final double height = ui.window.physicalSize.height;
    if (devicePixelRatio < 2 && (width >= 1000 || height >= 1000)) {
      isTablet = true;
      isPhone = false;
    } else if (devicePixelRatio == 2 && (width >= 1920 || height >= 1920)) {
      isTablet = true;
      isPhone = false;
    } else {
      isTablet = false;
      isPhone = true;
    }
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('dart_vlc'),
          centerTitle: true,
        ),
        body: ListView(
          shrinkWrap: true,
          padding: const EdgeInsets.all(4.0),
          children: [
            Row(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Platform.isWindows
                    ? NativeVideo(
                        player: player,
                        width: isPhone ? 320 : 640,
                        height: isPhone ? 180 : 360,
                        volumeThumbColor: Colors.blue,
                        volumeActiveColor: Colors.blue,
                        showControls: !isPhone,
                      )
                    : Video(
                        player: player,
                        width: isPhone ? 320 : 640,
                        height: isPhone ? 180 : 360,
                        volumeThumbColor: Colors.blue,
                        volumeActiveColor: Colors.blue,
                        showControls: !isPhone,
                      ),
              ],
            ),
            Row(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Expanded(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.start,
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      if (isPhone) _controls(context, isPhone),
                      Card(
                        elevation: 2.0,
                        margin: const EdgeInsets.all(4.0),
                        child: Container(
                          margin: const EdgeInsets.all(16.0),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                                  const Text('Playlist creation.'),
                                  Divider(
                                    height: 8.0,
                                    color: Colors.transparent,
                                  ),
                                  Row(
                                    mainAxisAlignment: MainAxisAlignment.start,
                                    children: [
                                      Expanded(
                                        child: TextField(
                                          controller: this.controller,
                                          cursorWidth: 1.0,
                                          autofocus: true,
                                          style: const TextStyle(
                                            fontSize: 14.0,
                                          ),
                                          decoration: InputDecoration.collapsed(
                                            hintStyle: const TextStyle(
                                              fontSize: 14.0,
                                            ),
                                            hintText: 'Enter Media path.',
                                          ),
                                        ),
                                      ),
                                      Container(
                                        width: 152.0,
                                        child: DropdownButton<MediaType>(
                                          value: this.mediaType,
                                          onChanged: (mediaType) => this
                                              .setState(() =>
                                                  this.mediaType = mediaType!),
                                          items: [
                                            DropdownMenuItem<MediaType>(
                                              value: MediaType.file,
                                              child: Text(
                                                MediaType.file.toString(),
                                                style: const TextStyle(
                                                  fontSize: 14.0,
                                                ),
                                              ),
                                            ),
                                            DropdownMenuItem<MediaType>(
                                              value: MediaType.network,
                                              child: Text(
                                                MediaType.network.toString(),
                                                style: const TextStyle(
                                                  fontSize: 14.0,
                                                ),
                                              ),
                                            ),
                                            DropdownMenuItem<MediaType>(
                                              value: MediaType.asset,
                                              child: Text(
                                                MediaType.asset.toString(),
                                                style: const TextStyle(
                                                  fontSize: 14.0,
                                                ),
                                              ),
                                            ),
                                          ],
                                        ),
                                      ),
                                      Padding(
                                        padding: EdgeInsets.only(left: 10.0),
                                        child: ElevatedButton(
                                          onPressed: () {
                                            if (this.mediaType ==
                                                MediaType.file) {
                                              this.medias.add(
                                                    Media.file(
                                                      File(
                                                        controller.text
                                                            .replaceAll(
                                                                '"', ''),
                                                      ),
                                                    ),
                                                  );
                                            } else if (this.mediaType ==
                                                MediaType.network) {
                                              this.medias.add(
                                                    Media.network(
                                                      controller.text,
                                                    ),
                                                  );
                                            }
                                            this.setState(() {});
                                          },
                                          child: Text(
                                            'Add to Playlist',
                                            style: TextStyle(
                                              fontSize: 14.0,
                                            ),
                                          ),
                                        ),
                                      ),
                                    ],
                                  ),
                                  const Divider(
                                    height: 12.0,
                                  ),
                                  const Divider(
                                    height: 8.0,
                                    color: Colors.transparent,
                                  ),
                                  const Text('Playlist'),
                                ] +
                                this
                                    .medias
                                    .map(
                                      (media) => ListTile(
                                        title: Text(
                                          media.resource,
                                          style: const TextStyle(
                                            fontSize: 14.0,
                                          ),
                                        ),
                                        subtitle: Text(
                                          media.mediaType.toString(),
                                          style: const TextStyle(
                                            fontSize: 14.0,
                                          ),
                                        ),
                                      ),
                                    )
                                    .toList() +
                                <Widget>[
                                  const Divider(
                                    height: 8.0,
                                    color: Colors.transparent,
                                  ),
                                  Row(
                                    children: [
                                      ElevatedButton(
                                        onPressed: () => this.setState(
                                          () {
                                            this.player.open(
                                                  Playlist(
                                                    medias: this.medias,
                                                    playlistMode:
                                                        PlaylistMode.single,
                                                  ),
                                                );
                                          },
                                        ),
                                        child: Text(
                                          'Open into Player',
                                          style: const TextStyle(
                                            fontSize: 14.0,
                                          ),
                                        ),
                                      ),
                                      const SizedBox(width: 12.0),
                                      ElevatedButton(
                                        onPressed: () {
                                          this.setState(
                                              () => this.medias.clear());
                                        },
                                        child: Text(
                                          'Clear the list',
                                          style: const TextStyle(
                                            fontSize: 14.0,
                                          ),
                                        ),
                                      ),
                                    ],
                                  ),
                                ],
                          ),
                        ),
                      ),
                      Card(
                        elevation: 2.0,
                        margin: const EdgeInsets.all(4.0),
                        child: Container(
                          margin: const EdgeInsets.all(16.0),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              const Text('Playback event listeners.'),
                              const Divider(
                                height: 12.0,
                                color: Colors.transparent,
                              ),
                              const Divider(
                                height: 12.0,
                              ),
                              const Text('Playback position.'),
                              const Divider(
                                height: 8.0,
                                color: Colors.transparent,
                              ),
                              Slider(
                                min: 0,
                                max: this
                                        .position
                                        .duration
                                        ?.inMilliseconds
                                        .toDouble() ??
                                    1.0,
                                value: this
                                        .position
                                        .position
                                        ?.inMilliseconds
                                        .toDouble() ??
                                    0.0,
                                onChanged: (double position) =>
                                    this.player.seek(
                                          Duration(
                                            milliseconds: position.toInt(),
                                          ),
                                        ),
                              ),
                              const Text('Event streams.'),
                              const Divider(
                                height: 8.0,
                                color: Colors.transparent,
                              ),
                              Table(
                                children: [
                                  TableRow(
                                    children: [
                                      const Text('player.general.volume'),
                                      Text('${this.general.volume}')
                                    ],
                                  ),
                                  TableRow(
                                    children: [
                                      const Text('player.general.rate'),
                                      Text('${this.general.rate}')
                                    ],
                                  ),
                                  TableRow(
                                    children: [
                                      const Text('player.position.position'),
                                      Text('${this.position.position}')
                                    ],
                                  ),
                                  TableRow(
                                    children: [
                                      const Text('player.position.duration'),
                                      Text('${this.position.duration}')
                                    ],
                                  ),
                                  TableRow(
                                    children: [
                                      const Text('player.playback.isCompleted'),
                                      Text('${this.playback.isCompleted}')
                                    ],
                                  ),
                                  TableRow(
                                    children: [
                                      const Text('player.playback.isPlaying'),
                                      Text('${this.playback.isPlaying}')
                                    ],
                                  ),
                                  TableRow(
                                    children: [
                                      const Text('player.playback.isSeekable'),
                                      Text('${this.playback.isSeekable}')
                                    ],
                                  ),
                                  TableRow(
                                    children: [
                                      const Text('player.current.index'),
                                      Text('${this.current.index}')
                                    ],
                                  ),
                                  TableRow(
                                    children: [
                                      const Text('player.current.media'),
                                      Text('${this.current.media}')
                                    ],
                                  ),
                                  TableRow(
                                    children: [
                                      const Text('player.current.medias'),
                                      Text('${this.current.medias}')
                                    ],
                                  ),
                                  TableRow(
                                    children: [
                                      const Text('player.videoDimensions'),
                                      Text('${this.videoDimensions}')
                                    ],
                                  ),
                                  TableRow(
                                    children: [
                                      const Text('player.bufferingProgress'),
                                      Text('${this.bufferingProgress}')
                                    ],
                                  ),
                                ],
                              ),
                            ],
                          ),
                        ),
                      ),
                      Card(
                        elevation: 2.0,
                        margin: const EdgeInsets.all(4.0),
                        child: Container(
                          margin: const EdgeInsets.all(16.0),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: const [
                                  Text('Playback devices.'),
                                  Divider(
                                    height: 12.0,
                                    color: Colors.transparent,
                                  ),
                                  Divider(
                                    height: 12.0,
                                  ),
                                ] +
                                this
                                    .devices
                                    .map(
                                      (device) => ListTile(
                                        title: Text(
                                          device.name,
                                          style: const TextStyle(
                                            fontSize: 14.0,
                                          ),
                                        ),
                                        subtitle: Text(
                                          device.id,
                                          style: const TextStyle(
                                            fontSize: 14.0,
                                          ),
                                        ),
                                        onTap: () =>
                                            this.player.setDevice(device),
                                      ),
                                    )
                                    .toList(),
                          ),
                        ),
                      ),
                      Card(
                        elevation: 2.0,
                        margin: const EdgeInsets.all(4.0),
                        child: Container(
                          margin: const EdgeInsets.all(16.0),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              const Text('Metas parsing.'),
                              Row(
                                mainAxisAlignment: MainAxisAlignment.start,
                                children: [
                                  Expanded(
                                    child: TextField(
                                      controller: this.metasController,
                                      cursorWidth: 1.0,
                                      autofocus: true,
                                      style: const TextStyle(
                                        fontSize: 14.0,
                                      ),
                                      decoration: InputDecoration.collapsed(
                                        hintStyle: const TextStyle(
                                          fontSize: 14.0,
                                        ),
                                        hintText: 'Enter Media path.',
                                      ),
                                    ),
                                  ),
                                  Container(
                                    width: 152.0,
                                    child: DropdownButton<MediaType>(
                                      value: this.mediaType,
                                      onChanged: (mediaType) => this.setState(
                                          () => this.mediaType = mediaType!),
                                      items: [
                                        DropdownMenuItem<MediaType>(
                                          value: MediaType.file,
                                          child: Text(
                                            MediaType.file.toString(),
                                            style: const TextStyle(
                                              fontSize: 14.0,
                                            ),
                                          ),
                                        ),
                                        DropdownMenuItem<MediaType>(
                                          value: MediaType.network,
                                          child: Text(
                                            MediaType.network.toString(),
                                            style: const TextStyle(
                                              fontSize: 14.0,
                                            ),
                                          ),
                                        ),
                                        DropdownMenuItem<MediaType>(
                                          value: MediaType.asset,
                                          child: Text(
                                            MediaType.asset.toString(),
                                            style: const TextStyle(
                                              fontSize: 14.0,
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                  Padding(
                                    padding: EdgeInsets.only(left: 16.0),
                                    child: ElevatedButton(
                                      onPressed: () {
                                        if (this.mediaType == MediaType.file) {
                                          this.metasMedia = Media.file(
                                            File(this.metasController.text),
                                            parse: true,
                                          );
                                        } else if (this.mediaType ==
                                            MediaType.network) {
                                          this.metasMedia = Media.network(
                                            this.metasController.text,
                                            parse: true,
                                          );
                                        }
                                        this.setState(() {});
                                      },
                                      child: const Text(
                                        'Parse',
                                        style: TextStyle(
                                          fontSize: 14.0,
                                        ),
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                              const Divider(
                                height: 12.0,
                              ),
                              const Divider(
                                height: 8.0,
                                color: Colors.transparent,
                              ),
                              Text(
                                JsonEncoder.withIndent('    ')
                                    .convert(this.metasMedia?.metas),
                              ),
                            ],
                          ),
                        ),
                      ),
                      if (isPhone) _playlist(context),
                    ],
                  ),
                ),
                if (isTablet)
                  Expanded(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.start,
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        _controls(context, isPhone),
                        _playlist(context),
                      ],
                    ),
                  ),
              ],
            )
          ],
        ),
      ),
    );
  }

  Widget _controls(BuildContext context, bool isPhone) {
    return Card(
      elevation: 2.0,
      margin: const EdgeInsets.all(4.0),
      child: Container(
        margin: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Playback controls.'),
            const Divider(
              height: 8.0,
              color: Colors.transparent,
            ),
            Row(
              children: [
                ElevatedButton(
                  onPressed: () => this.player.play(),
                  child: const Text(
                    'play',
                    style: TextStyle(
                      fontSize: 14.0,
                    ),
                  ),
                ),
                const SizedBox(width: 12.0),
                ElevatedButton(
                  onPressed: () => this.player.pause(),
                  child: const Text(
                    'pause',
                    style: TextStyle(
                      fontSize: 14.0,
                    ),
                  ),
                ),
                const SizedBox(width: 12.0),
                ElevatedButton(
                  onPressed: () => this.player.playOrPause(),
                  child: const Text(
                    'playOrPause',
                    style: TextStyle(
                      fontSize: 14.0,
                    ),
                  ),
                ),
                const SizedBox(width: 12.0),
              ],
            ),
            const SizedBox(
              height: 8.0,
            ),
            Row(
              children: [
                ElevatedButton(
                  onPressed: () => this.player.stop(),
                  child: const Text(
                    'stop',
                    style: TextStyle(
                      fontSize: 14.0,
                    ),
                  ),
                ),
                const SizedBox(width: 12.0),
                ElevatedButton(
                  onPressed: () => this.player.next(),
                  child: const Text(
                    'next',
                    style: TextStyle(
                      fontSize: 14.0,
                    ),
                  ),
                ),
                const SizedBox(width: 12.0),
                ElevatedButton(
                  onPressed: () => this.player.previous(),
                  child: const Text(
                    'previous',
                    style: TextStyle(
                      fontSize: 14.0,
                    ),
                  ),
                ),
              ],
            ),
            const Divider(
              height: 12.0,
              color: Colors.transparent,
            ),
            const Divider(
              height: 12.0,
            ),
            const Text('Volume control.'),
            const Divider(
              height: 8.0,
              color: Colors.transparent,
            ),
            Slider(
              min: 0.0,
              max: 1.0,
              value: this.player.general.volume,
              onChanged: (volume) {
                this.player.setVolume(volume);
                this.setState(() {});
              },
            ),
            const Text('Playback rate control.'),
            const Divider(
              height: 8.0,
              color: Colors.transparent,
            ),
            Slider(
              min: 0.5,
              max: 1.5,
              value: this.player.general.rate,
              onChanged: (rate) {
                this.player.setRate(rate);
                this.setState(() {});
              },
            ),
          ],
        ),
      ),
    );
  }

  Widget _playlist(BuildContext context) {
    return Card(
      elevation: 2.0,
      margin: const EdgeInsets.all(4.0),
      child: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              margin: const EdgeInsets.only(left: 16.0, top: 16.0),
              alignment: Alignment.topLeft,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: const [
                  Text('Playlist manipulation.'),
                  Divider(
                    height: 12.0,
                    color: Colors.transparent,
                  ),
                  Divider(
                    height: 12.0,
                  ),
                ],
              ),
            ),
            Container(
              height: 456.0,
              child: ReorderableListView(
                shrinkWrap: true,
                onReorder: (int initialIndex, int finalIndex) async {
                  /// 🙏🙏🙏
                  /// In the name of God,
                  /// With all due respect,
                  /// I ask all Flutter engineers to please fix this issue.
                  /// Peace.
                  /// 🙏🙏🙏
                  ///
                  /// Issue:
                  /// https://github.com/flutter/flutter/issues/24786
                  /// Prevention:
                  /// https://stackoverflow.com/a/54164333/12825435
                  ///
                  if (finalIndex > this.current.medias.length)
                    finalIndex = this.current.medias.length;
                  if (initialIndex < finalIndex) finalIndex--;

                  this.player.move(initialIndex, finalIndex);
                  this.setState(() {});
                },
                scrollDirection: Axis.vertical,
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                children: List.generate(
                  this.current.medias.length,
                  (int index) => ListTile(
                    key: Key(index.toString()),
                    leading: Text(
                      index.toString(),
                      style: const TextStyle(fontSize: 14.0),
                    ),
                    title: Text(
                      this.current.medias[index].resource,
                      style: const TextStyle(fontSize: 14.0),
                    ),
                    subtitle: Text(
                      this.current.medias[index].mediaType.toString(),
                      style: const TextStyle(fontSize: 14.0),
                    ),
                  ),
                  growable: true,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
247
likes
130
pub points
87%
popularity

Publisher

unverified uploader

Flutter media playback, broadcast, recording & chromecast library. Based on libvlc.

Repository (GitHub)
View/report issues

Documentation

Documentation
API reference

License

LGPL-2.1 (license)

Dependencies

audio_video_progress_bar, dart_vlc_ffi, flutter, flutter_native_view, path, path_provider, window_manager

More

Packages that depend on dart_vlc