Flutter音视频流处理插件flutter_streamer的使用

发布于 1周前 作者 itying888 来自 Flutter

Flutter音视频流处理插件flutter_streamer的使用

flutter_streamer 是一个基于标准 Dart Stream 的纯 Dart 状态管理类。它可以帮助你轻松地管理和处理应用中的状态变化。

保持简单

实现自己的模式:

class CounterController extends Streamer<int> {
  CounterController(super.initialValue);

  void increment(Increment event) => emit(++last);
}

一个简单的逻辑类扩展自Streamer

class CounterLogic extends Streamer<CounterState> {
  int _value;

  CounterLogic(this._value) : super(CounterState(_value)) {
    on<Increment>(onIncrement);
  }

  set value(int newValue) {
    if (newValue >= 10) {
      emit(MaxReached());
    } else {
      _value = newValue;
    }
  }

  int get value => _value;

  void onIncrement(Increment event) => emit(CounterState(++value));
}

检查示例部分以了解EASE模式的简单实现

EASE模式灵感来源于BloC模式:

  • 在BloC模式中,UI发出事件,而Cubit/Bloc类响应状态。
  • 这可能会导致处理视图逻辑(如导航、显示对话框)变得复杂。

EASE模式定义了事件、动作、状态和错误类:

  • 它们用于通过流在我们的逻辑类和视图之间进行通信。
  • 因为一个简单的视图应该只依赖于事件/状态/错误的流,并且发出用户动作。
  • 一个简单的逻辑应该只依赖于用户的动作流,并发出事件/状态/错误。

这种方式使得视图触发导航或对话框变得非常容易。 你的视图甚至不需要知道逻辑实现。 你的逻辑甚至不需要知道视图实现。

示例代码

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_inject/flutter_inject.dart';
import 'package:stream_listener_widget/stream_listener_widget.dart';
import 'package:streamer/streamer.dart';

void main() => runApp(
      const MaterialApp(
        home: CounterView(initialValue: 5),
      ),
    );

class CounterLogic extends StateStreamer<CounterState, CounterIO> {
  CounterLogic(int value) : super(CounterState(value)) {
    on<Increment>(onIncrement);
    on<Decrement>(onDecrement);
  }

  [@override](/user/override)
  CounterIO? mapState(CounterState newState) {
    if (newState.value > 10) {
      return MaxReached();
    } else if (newState.value < 0) {
      return UnauthorizedValue('A counter under zero is not allowed');
    }
    return newState;
  }

  void onIncrement(Increment event) => state = CounterState(state.value + 1);
  void onDecrement(Decrement event) => state = CounterState(state.value - 1);
}

class CounterView extends StatelessWidget {
  final int initialValue;

  const CounterView({super.key, required this.initialValue});

  void _showDialog(BuildContext context, String message) => showDialog(
        context: context,
        barrierDismissible: true,
        builder: (context) {
          return Dialog(
            child: Padding(
              padding: const EdgeInsets.all(20),
              child: Text(message),
            ),
          );
        },
      );

  void _onMaxReached(BuildContext context) => _showDialog(context, 'Your counter has reached max value');

  void _onError(BuildContext context, CounterError event) => _showDialog(context, event.message);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Inject<Streamer<CounterIO>>(
        factory: (context) => CounterLogic(initialValue),
        builder: (context) {
          final streamer = Dependency.get<Streamer<CounterIO>>(context);
          return StreamListener(
            listeners: [
              (context) => streamer.on<MaxReached>((e) => _onMaxReached(context)),
              (context) => streamer.on<CounterError>((e) => _onError(context, e)),
            ],
            child: Scaffold(
              appBar: AppBar(title: const Text('Counter demo')),
              body: Center(
                child: StreamBuilder<CounterState>(
                  stream: streamer.select<CounterState>(),
                  builder: (context, snapshot) {
                    if (snapshot.hasError) return Text(snapshot.error.toString());
                    if (!snapshot.hasData) return const CircularProgressIndicator();
                    final state = snapshot.data!;
                    return Text('Counter: ${state.value}');
                  },
                ),
              ),
              floatingActionButton: Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  FloatingActionButton(
                    onPressed: () => streamer.emit(Increment()),
                    child: const Icon(Icons.add),
                  ),
                  FloatingActionButton(
                    onPressed: () => streamer.emit(Decrement()),
                    child: const Icon(Icons.remove),
                  ),
                ],
              ),
            ),
          );
        });
  }
}

/// 这里是一个简单的EASE模式实现的例子

/// 事件
sealed class CounterEvent extends CounterIO {}

class MaxReached extends CounterEvent {}

/// 动作
sealed class CounterAction extends CounterIO {}

class Increment extends CounterAction {}

class Decrement extends CounterAction {}

/// 状态
class CounterState extends CounterIO {
  final int value;
  CounterState(this.value);
}

class Loading extends CounterState {
  Loading(super.value);
}

/// 错误
sealed class CounterError extends CounterIO {
  final String message;

  CounterError(this.message);
}

class UnauthorizedValue extends CounterError {
  UnauthorizedValue(super.message);
}

class UnknownError extends CounterError {
  UnknownError(super.message);
}

更多关于Flutter音视频流处理插件flutter_streamer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter音视频流处理插件flutter_streamer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中进行音视频流处理时,flutter_streamer 是一个强大的插件,它允许开发者在Flutter应用中集成音视频流的播放和处理功能。以下是一个使用 flutter_streamer 的代码案例,展示了如何进行基本的音视频流播放。

首先,确保你已经在 pubspec.yaml 文件中添加了 flutter_streamer 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_streamer: ^0.x.x  # 请替换为最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来,是一个完整的 Flutter 应用示例,展示如何使用 flutter_streamer 播放一个网络上的视频流:

import 'package:flutter/material.dart';
import 'package:flutter_streamer/flutter_streamer.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Streamer Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: StreamerDemo(),
    );
  }
}

class StreamerDemo extends StatefulWidget {
  @override
  _StreamerDemoState createState() => _StreamerDemoState();
}

class _StreamerDemoState extends State<StreamerDemo> {
  FlutterStreamer? _streamer;

  @override
  void initState() {
    super.initState();
    // 初始化 FlutterStreamer 实例
    _streamer = FlutterStreamer(
      url: 'http://your-video-stream-url-here', // 替换为你的视频流URL
      isLive: true, // 如果是直播流,设置为 true
      autoPlay: true, // 是否自动播放
      controls: true, // 是否显示控制按钮
    );

    // 监听播放状态变化
    _streamer!.playerStatusStream!.listen((status) {
      print('Player Status: $status');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Streamer Demo'),
      ),
      body: Center(
        child: _streamer!.videoPlayerController!.value.isInitialized
            ? AspectRatio(
                aspectRatio: _streamer!.videoPlayerController!.value.aspectRatio,
                child: _streamer!.videoPlayer!,
              )
            : CircularProgressIndicator(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (_streamer!.videoPlayerController!.value.isPlaying) {
            _streamer!.pause();
          } else {
            _streamer!.play();
          }
        },
        tooltip: 'Play/Pause',
        child: Icon(
          _streamer!.videoPlayerController!.value.isPlaying
              ? Icons.pause
              : Icons.play_arrow,
        ),
      ),
    );
  }

  @override
  void dispose() {
    _streamer!.dispose();
    super.dispose();
  }
}

在这个示例中,我们做了以下几件事情:

  1. 初始化 FlutterStreamer 实例:在 initState 方法中,我们创建了一个 FlutterStreamer 实例,并设置了视频流的 URL、是否是直播流、是否自动播放以及是否显示控制按钮。
  2. 监听播放状态:通过 _streamer!.playerStatusStream!.listen 方法,我们可以监听播放状态的变化,并在控制台中打印状态信息。
  3. 构建 UI:在 build 方法中,我们使用 AspectRatio 来确保视频播放器能够保持正确的宽高比。如果视频播放器已经初始化,则显示视频播放器;否则,显示一个加载指示器。
  4. 播放/暂停控制:我们添加了一个浮动操作按钮(FAB),用于控制视频的播放和暂停。
  5. 释放资源:在 dispose 方法中,我们调用 _streamer!.dispose() 来释放资源。

请确保将 'http://your-video-stream-url-here' 替换为你实际的视频流 URL。此外,根据你的需求,你可以进一步自定义和扩展这个示例。

回到顶部