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

discontinuedreplaced by: media_kit
PlatformLinuxWindows

Flutter audio / video playback, broadcast & recording library for Windows & Linux. Based on libvlc.

example/lib/main.dart

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

void main() async {
  DartVLC.initialize();
  runApp(DartVLCExample());
}

class DartVLCExample extends StatelessWidget {
  const DartVLCExample({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('package:dart_vlc'),
          centerTitle: true,
        ),
        body: PrimaryScreen(),
      ),
    );
  }
}

class PrimaryScreen extends StatefulWidget {
  @override
  PrimaryScreenState createState() => PrimaryScreenState();
}

class PrimaryScreenState extends State<PrimaryScreen> {
  Player player = Player(
    id: 0,
    videoDimensions: const VideoDimensions(640, 360),
  );
  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? metadataCurrentMedia;

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

  @override
  Widget build(BuildContext context) {
    bool isTablet;
    bool isPhone;
    final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
    final width = MediaQuery.of(context).size.width;
    final height = MediaQuery.of(context).size.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 ListView(
      shrinkWrap: true,
      padding: const EdgeInsets.all(4.0),
      children: [
        Row(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Card(
              elevation: 4.0,
              clipBehavior: Clip.antiAlias,
              child: 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: controller,
                                      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: mediaType,
                                      onChanged: (value) =>
                                          setState(() => mediaType = value!),
                                      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 (mediaType == MediaType.file) {
                                          medias.add(
                                            Media.file(
                                              File(
                                                controller.text
                                                    .replaceAll('"', ''),
                                              ),
                                            ),
                                          );
                                        } else if (mediaType ==
                                            MediaType.network) {
                                          medias.add(
                                            Media.network(
                                              controller.text,
                                            ),
                                          );
                                        }
                                        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'),
                            ] +
                            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: () => setState(
                                      () {
                                        player.open(
                                          Playlist(medias: medias),
                                        );
                                      },
                                    ),
                                    child: Text(
                                      'Open into Player',
                                      style: const TextStyle(
                                        fontSize: 14.0,
                                      ),
                                    ),
                                  ),
                                  const SizedBox(width: 12.0),
                                  ElevatedButton(
                                    onPressed: () {
                                      setState(() => 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: position.duration?.inMilliseconds.toDouble() ??
                                1.0,
                            value:
                                position.position?.inMilliseconds.toDouble() ??
                                    0.0,
                            onChanged: (double position) => 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(
                                    '${general.volume}',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                              TableRow(
                                children: [
                                  const Text('player.general.rate'),
                                  Text(
                                    '${general.rate}',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                              TableRow(
                                children: [
                                  const Text('player.position.position'),
                                  Text(
                                    '${position.position}',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                              TableRow(
                                children: [
                                  const Text('player.position.duration'),
                                  Text(
                                    '${position.duration}',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                              TableRow(
                                children: [
                                  const Text('player.playback.isCompleted'),
                                  Text(
                                    '${playback.isCompleted}',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                              TableRow(
                                children: [
                                  const Text('player.playback.isPlaying'),
                                  Text(
                                    '${playback.isPlaying}',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                              TableRow(
                                children: [
                                  const Text('player.playback.isSeekable'),
                                  Text(
                                    '${playback.isSeekable}',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                              TableRow(
                                children: [
                                  const Text('player.current.index'),
                                  Text(
                                    '${current.index}',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                              TableRow(
                                children: [
                                  const Text('player.current.media'),
                                  Text(
                                    '${current.media}',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                              TableRow(
                                children: [
                                  const Text('player.current.medias'),
                                  Text(
                                    '${current.medias}',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                              TableRow(
                                children: [
                                  const Text('player.videoDimensions'),
                                  Text(
                                    '$videoDimensions',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                              TableRow(
                                children: [
                                  const Text('player.bufferingProgress'),
                                  Text(
                                    '$bufferingProgress',
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                  )
                                ],
                              ),
                            ],
                          ),
                        ],
                      ),
                    ),
                  ),
                  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,
                              ),
                            ] +
                            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: () => 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: metasController,
                                  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: mediaType,
                                  onChanged: (value) =>
                                      setState(() => mediaType = value!),
                                  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 (mediaType == MediaType.file) {
                                      metadataCurrentMedia = Media.file(
                                        File(metasController.text),
                                        parse: true,
                                      );
                                    } else if (mediaType == MediaType.network) {
                                      metadataCurrentMedia = Media.network(
                                        metasController.text,
                                        parse: true,
                                      );
                                    }
                                    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(metadataCurrentMedia?.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: () => player.play(),
                  child: const Text(
                    'play',
                    style: TextStyle(
                      fontSize: 14.0,
                    ),
                  ),
                ),
                const SizedBox(width: 12.0),
                ElevatedButton(
                  onPressed: () => player.pause(),
                  child: const Text(
                    'pause',
                    style: TextStyle(
                      fontSize: 14.0,
                    ),
                  ),
                ),
                const SizedBox(width: 12.0),
                ElevatedButton(
                  onPressed: () => 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: () => player.stop(),
                  child: const Text(
                    'stop',
                    style: TextStyle(
                      fontSize: 14.0,
                    ),
                  ),
                ),
                const SizedBox(width: 12.0),
                ElevatedButton(
                  onPressed: () => player.next(),
                  child: const Text(
                    'next',
                    style: TextStyle(
                      fontSize: 14.0,
                    ),
                  ),
                ),
                const SizedBox(width: 12.0),
                ElevatedButton(
                  onPressed: () => 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: player.general.volume,
              onChanged: (volume) {
                player.setVolume(volume);
                setState(() {});
              },
            ),
            const Text('Playback rate control.'),
            const Divider(
              height: 8.0,
              color: Colors.transparent,
            ),
            Slider(
              min: 0.5,
              max: 1.5,
              value: player.general.rate,
              onChanged: (rate) {
                player.setRate(rate);
                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(
                physics: const NeverScrollableScrollPhysics(),
                shrinkWrap: true,
                onReorder: (int before, int after) async {
                  // [ReorderableListView] in Flutter is buggy.
                  // The [onReorder] callback receives incorrect indices when the [children] are re-ordered.
                  // Workaround : https://stackoverflow.com/a/54164333/12825435
                  // Issue      : https://github.com/flutter/flutter/issues/24786
                  if (after > current.medias.length) {
                    after = current.medias.length;
                  }
                  if (before < after) after--;
                  player.move(
                    before,
                    after,
                  );
                  setState(() {});
                },
                scrollDirection: Axis.vertical,
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                children: List.generate(
                  current.medias.length,
                  (int index) => ListTile(
                    key: Key(index.toString()),
                    leading: Text(
                      index.toString(),
                      style: const TextStyle(fontSize: 14.0),
                    ),
                    title: Container(
                      padding: const EdgeInsets.only(right: 56.0),
                      child: Text(
                        current.medias[index].resource,
                        overflow: TextOverflow.ellipsis,
                        style: const TextStyle(fontSize: 14.0),
                      ),
                    ),
                    subtitle: Text(
                      current.medias[index].mediaType.toString(),
                      overflow: TextOverflow.ellipsis,
                      style: const TextStyle(fontSize: 14.0),
                    ),
                  ),
                  growable: true,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
247
likes
140
points
4.75k
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter audio / video playback, broadcast & recording library for Windows & Linux. 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, path

More

Packages that depend on dart_vlc