123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- import 'dart:convert';
- import 'dart:math' as math;
- import 'dart:typed_data';
- import 'package:fis_common/event/event_type.dart';
- import 'package:fis_common/logger/logger.dart';
- import 'package:flutter/material.dart';
- class ShellSonopostPlayController {
- static bool _playing = false;
- final int width;
- final int height;
- static final bufferFragmentReceived = FEventHandler<Uint8List>();
- ShellSonopostPlayController({
- this.width = 1280,
- this.height = 720,
- });
- Future<void> init() {
- return Future(() => null);
- }
- void play() {
- if (_playing) return;
- _playing = true;
- logger.i("ShellSonopost start");
- }
- static void setPreviewImageData(String imageData) {
- try {
- if (_playing) {
- var data = base64Decode(imageData);
- bufferFragmentReceived.emit("shell_sonopost", data);
- } else {
- logger.i(
- "refresh sonopost preview failed since publish already stopped!");
- }
- } catch (e) {}
- }
- void stop() {
- _playing = false;
- logger.i("ShellSonopost stop");
- }
- }
- class ShellSonopostPlayer extends StatefulWidget {
- final ShellSonopostPlayController controller;
- const ShellSonopostPlayer({super.key, required this.controller});
- @override
- State<StatefulWidget> createState() => _ShellSonopostPlayer();
- }
- class _ShellSonopostPlayer extends State<ShellSonopostPlayer> {
- static const int _RETRY_LIMIT = 10;
- Uint8List? _frameBuffer;
- // late Uint8List _bufferArea;
- // int _bufferPosition = 0;
- bool _hasError = false;
- int _rgbaSize = 0;
- int _retryCount = 0;
- @override
- void initState() {
- super.initState();
- _rgbaSize = 4 * widget.controller.width * widget.controller.height;
- // _bufferArea = Uint8List(_rgbaSize);
- WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
- ShellSonopostPlayController.bufferFragmentReceived
- .addListener(_onBufferOnce);
- });
- }
- @override
- dispose() {
- ShellSonopostPlayController.bufferFragmentReceived
- .removeListener(_onBufferOnce);
- super.dispose();
- }
- @override
- Widget build(BuildContext context) {
- Widget child;
- if (_hasError) {
- child = const Center(
- child: Text("Error", style: TextStyle(color: Colors.white)),
- );
- } else if (_frameBuffer != null) {
- child = Image.memory(
- _frameBuffer!,
- fit: BoxFit.contain,
- gaplessPlayback: true,
- );
- // 水平翻转
- // child = Transform(
- // alignment: Alignment.center,
- // transform: Matrix4.rotationY(math.pi),
- // child: child,
- // );
- } else {
- child = const SizedBox();
- }
- return Container(
- color: Colors.black,
- child: child,
- );
- }
- void _onBufferOnce(Object sender, Uint8List e) {
- setState(() {
- _frameBuffer = e;
- });
- }
- void _onBuffer(Object sender, Uint8List e) {
- try {
- _onBufferOnce(sender, e);
- } catch (e) {
- _handleError();
- }
- }
- void _handleError() {
- widget.controller.stop();
- if (_retryCount > _RETRY_LIMIT) {
- setState(() {
- _hasError = true;
- });
- }
- Future.delayed(const Duration(milliseconds: 800), () {
- widget.controller.play();
- });
- _retryCount++;
- }
- static int readInt64(Uint8List data, [int index = 0]) {
- var intData = data.buffer.asByteData(index, 8);
- return intData.getInt64(0, Endian.little);
- }
- static int readInt64V2(Uint8List data, [int index = 0]) {
- int low = readInt(data, index);
- int high = readInt(data, index + 4);
- int value = high >> 32;
- value |= low;
- return value;
- }
- static int readInt(Uint8List data, [int index = 0]) {
- var intData = data.buffer.asByteData(index, 4);
- return intData.getInt32(0, Endian.little);
- }
- }
|