sonopost_preview_helper.dart 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import 'dart:convert';
  2. import 'dart:math' as math;
  3. import 'dart:typed_data';
  4. import 'package:fis_common/event/event_type.dart';
  5. import 'package:fis_common/logger/logger.dart';
  6. import 'package:flutter/material.dart';
  7. class ShellSonopostPlayController {
  8. static bool _playing = false;
  9. final int width;
  10. final int height;
  11. static final bufferFragmentReceived = FEventHandler<Uint8List>();
  12. ShellSonopostPlayController({
  13. this.width = 1280,
  14. this.height = 720,
  15. });
  16. Future<void> init() {
  17. return Future(() => null);
  18. }
  19. void play() {
  20. if (_playing) return;
  21. _playing = true;
  22. logger.i("ShellSonopost start");
  23. }
  24. static void setPreviewImageData(String imageData) {
  25. try {
  26. if (_playing) {
  27. var data = base64Decode(imageData);
  28. bufferFragmentReceived.emit("shell_sonopost", data);
  29. } else {
  30. logger.i(
  31. "refresh sonopost preview failed since publish already stopped!");
  32. }
  33. } catch (e) {}
  34. }
  35. void stop() {
  36. _playing = false;
  37. logger.i("ShellSonopost stop");
  38. }
  39. }
  40. class ShellSonopostPlayer extends StatefulWidget {
  41. final ShellSonopostPlayController controller;
  42. const ShellSonopostPlayer({super.key, required this.controller});
  43. @override
  44. State<StatefulWidget> createState() => _ShellSonopostPlayer();
  45. }
  46. class _ShellSonopostPlayer extends State<ShellSonopostPlayer> {
  47. static const int _RETRY_LIMIT = 10;
  48. Uint8List? _frameBuffer;
  49. // late Uint8List _bufferArea;
  50. // int _bufferPosition = 0;
  51. bool _hasError = false;
  52. int _rgbaSize = 0;
  53. int _retryCount = 0;
  54. @override
  55. void initState() {
  56. super.initState();
  57. _rgbaSize = 4 * widget.controller.width * widget.controller.height;
  58. // _bufferArea = Uint8List(_rgbaSize);
  59. WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  60. ShellSonopostPlayController.bufferFragmentReceived
  61. .addListener(_onBufferOnce);
  62. });
  63. }
  64. @override
  65. dispose() {
  66. ShellSonopostPlayController.bufferFragmentReceived
  67. .removeListener(_onBufferOnce);
  68. super.dispose();
  69. }
  70. @override
  71. Widget build(BuildContext context) {
  72. Widget child;
  73. if (_hasError) {
  74. child = const Center(
  75. child: Text("Error", style: TextStyle(color: Colors.white)),
  76. );
  77. } else if (_frameBuffer != null) {
  78. child = Image.memory(
  79. _frameBuffer!,
  80. fit: BoxFit.contain,
  81. gaplessPlayback: true,
  82. );
  83. // 水平翻转
  84. // child = Transform(
  85. // alignment: Alignment.center,
  86. // transform: Matrix4.rotationY(math.pi),
  87. // child: child,
  88. // );
  89. } else {
  90. child = const SizedBox();
  91. }
  92. return Container(
  93. color: Colors.black,
  94. child: child,
  95. );
  96. }
  97. void _onBufferOnce(Object sender, Uint8List e) {
  98. setState(() {
  99. _frameBuffer = e;
  100. });
  101. }
  102. void _onBuffer(Object sender, Uint8List e) {
  103. try {
  104. _onBufferOnce(sender, e);
  105. } catch (e) {
  106. _handleError();
  107. }
  108. }
  109. void _handleError() {
  110. widget.controller.stop();
  111. if (_retryCount > _RETRY_LIMIT) {
  112. setState(() {
  113. _hasError = true;
  114. });
  115. }
  116. Future.delayed(const Duration(milliseconds: 800), () {
  117. widget.controller.play();
  118. });
  119. _retryCount++;
  120. }
  121. static int readInt64(Uint8List data, [int index = 0]) {
  122. var intData = data.buffer.asByteData(index, 8);
  123. return intData.getInt64(0, Endian.little);
  124. }
  125. static int readInt64V2(Uint8List data, [int index = 0]) {
  126. int low = readInt(data, index);
  127. int high = readInt(data, index + 4);
  128. int value = high >> 32;
  129. value |= low;
  130. return value;
  131. }
  132. static int readInt(Uint8List data, [int index = 0]) {
  133. var intData = data.buffer.asByteData(index, 4);
  134. return intData.getInt32(0, Endian.little);
  135. }
  136. }