style:整理代码
This commit is contained in:
parent
b7da72a1ce
commit
23b8257779
BIN
assets/demo.h264
BIN
assets/demo.h264
Binary file not shown.
@ -2,7 +2,6 @@ import 'package:get/get.dart';
|
|||||||
import 'package:star_lock/common/safetyVerification/safetyVerification_binding.dart';
|
import 'package:star_lock/common/safetyVerification/safetyVerification_binding.dart';
|
||||||
import 'package:star_lock/flavors.dart';
|
import 'package:star_lock/flavors.dart';
|
||||||
import 'package:star_lock/login/forgetPassword/starLock_forgetPassword_xhj_page.dart';
|
import 'package:star_lock/login/forgetPassword/starLock_forgetPassword_xhj_page.dart';
|
||||||
import 'package:star_lock/login/login/JMuxerApp.dart';
|
|
||||||
import 'package:star_lock/login/login/starLock_login_xhj_page.dart';
|
import 'package:star_lock/login/login/starLock_login_xhj_page.dart';
|
||||||
import 'package:star_lock/login/register/starLock_register_binding.dart';
|
import 'package:star_lock/login/register/starLock_register_binding.dart';
|
||||||
import 'package:star_lock/login/register/starLock_register_xhj_page.dart';
|
import 'package:star_lock/login/register/starLock_register_xhj_page.dart';
|
||||||
@ -398,7 +397,6 @@ abstract class Routers {
|
|||||||
static const String ownedKeyListPage = '/ownedKeyListPage'; //拥有的钥匙
|
static const String ownedKeyListPage = '/ownedKeyListPage'; //拥有的钥匙
|
||||||
|
|
||||||
static const String starLockLoginPage = '/StarLockLoginPage'; // 登录
|
static const String starLockLoginPage = '/StarLockLoginPage'; // 登录
|
||||||
static const String LocalHtmlPage = '/LocalHtmlPage'; // LocalHtmlPage
|
|
||||||
static const String starLockRegisterPage = '/StarLockRegisterPage'; // 注册
|
static const String starLockRegisterPage = '/StarLockRegisterPage'; // 注册
|
||||||
static const String starLockForgetPasswordPage =
|
static const String starLockForgetPasswordPage =
|
||||||
'/StarLockForgetPasswordPage'; // 忘记密码
|
'/StarLockForgetPasswordPage'; // 忘记密码
|
||||||
@ -640,9 +638,6 @@ abstract class AppRouters {
|
|||||||
page: () => F.sw(
|
page: () => F.sw(
|
||||||
skyCall: () => const StarLockLoginPage(),
|
skyCall: () => const StarLockLoginPage(),
|
||||||
xhjCall: () => const StarLockLoginXHJPage()),
|
xhjCall: () => const StarLockLoginXHJPage()),
|
||||||
),GetPage<dynamic>(
|
|
||||||
name: Routers.LocalHtmlPage,
|
|
||||||
page: () => LocalHtmlPage(),
|
|
||||||
),
|
),
|
||||||
GetPage<dynamic>(
|
GetPage<dynamic>(
|
||||||
name: Routers.starLockRegisterPage,
|
name: Routers.starLockRegisterPage,
|
||||||
|
|||||||
@ -2,22 +2,35 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart' show ByteData, Uint8List, rootBundle;
|
import 'package:flutter/services.dart' show ByteData, Uint8List, rootBundle;
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:star_lock/app_settings/app_colors.dart';
|
import 'package:star_lock/app_settings/app_colors.dart';
|
||||||
|
import 'package:star_lock/talk/startChart/handle/other/talk_data_repository.dart';
|
||||||
import 'package:star_lock/tools/titleAppBar.dart';
|
import 'package:star_lock/tools/titleAppBar.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
|
|
||||||
class LocalHtmlPage extends StatefulWidget {
|
class H264WebView extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
_LocalHtmlPageState createState() => _LocalHtmlPageState();
|
_H264WebViewState createState() => _H264WebViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LocalHtmlPageState extends State<LocalHtmlPage> {
|
class _H264WebViewState extends State<H264WebView> {
|
||||||
late final WebViewController _controller;
|
late final WebViewController _controller;
|
||||||
Timer? timer;
|
Timer? timer;
|
||||||
|
Timer? _sendTimer;
|
||||||
|
|
||||||
|
// 私有缓冲区,外部无法直接访问
|
||||||
|
final List<int> _buffer = [];
|
||||||
|
|
||||||
|
// 发送数据至html文件间隔时间
|
||||||
|
final int sendDataToHtmlIntervalTime = 820;
|
||||||
|
|
||||||
|
// 通话数据流的单例流数据处理类
|
||||||
|
final TalkDataRepository talkDataRepository = TalkDataRepository.instance;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_controller = WebViewController()
|
_controller = WebViewController()
|
||||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||||
..enableZoom(false)
|
..enableZoom(false)
|
||||||
@ -30,135 +43,52 @@ class _LocalHtmlPageState extends State<LocalHtmlPage> {
|
|||||||
|
|
||||||
// 加载本地 HTML
|
// 加载本地 HTML
|
||||||
_loadLocalHtml();
|
_loadLocalHtml();
|
||||||
|
simulateStreamFromAsset();
|
||||||
_sendFramesToHtml();
|
_sendFramesToHtml();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sendFramesToHtml() async {
|
void simulateStreamFromAsset() async {
|
||||||
// 读取 assets/demo.h264 文件
|
// 读取 assets 文件
|
||||||
final ByteData data = await rootBundle.load('assets/talk.h264');
|
final ByteData data = await rootBundle.load('assets/talk.h264');
|
||||||
final List<int> byteData = data.buffer.asUint8List();
|
final List<int> byteData = data.buffer.asUint8List();
|
||||||
|
|
||||||
// 提取 NALU 边界并生成 chunks
|
|
||||||
final List<int> chunks = extractChunks(byteData);
|
|
||||||
final int total = chunks.length;
|
|
||||||
|
|
||||||
int current = 0;
|
int current = 0;
|
||||||
int start = 0;
|
int start = 0;
|
||||||
int end = 0;
|
int end = 0;
|
||||||
List<int> buffer = []; // 用于累积帧数据的缓冲区
|
final List<int> chunks = extractChunks(byteData);
|
||||||
|
// 定时器控制发送数据块的节奏
|
||||||
|
timer ??= Timer.periodic(Duration(milliseconds: 10), (timer) {
|
||||||
// 创建一个定时器,每800毫秒触发一次
|
if (current >= chunks.length) {
|
||||||
timer ??= Timer.periodic(Duration(milliseconds: 800), (timer) async {
|
print('数据已经发完,重新进行发送');
|
||||||
if (current >= total) {
|
|
||||||
current = 0;
|
|
||||||
start = 0;
|
start = 0;
|
||||||
print("All frames sent. Restarting from the beginning.");
|
end = 0;
|
||||||
|
current = 0;
|
||||||
|
timer.cancel();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// 提取 NALU 边界并生成 chunks
|
||||||
end = chunks[current];
|
end = chunks[current];
|
||||||
current++;
|
current++;
|
||||||
|
|
||||||
// 累积当前帧数据到缓冲区
|
|
||||||
List<int> frameData = byteData.sublist(start, end);
|
List<int> frameData = byteData.sublist(start, end);
|
||||||
buffer.addAll(frameData);
|
if (frameData.length == 0) timer.cancel();
|
||||||
|
talkDataRepository.addTalkData(frameData);
|
||||||
start = end;
|
start = end;
|
||||||
|
|
||||||
// 发送累积的数据
|
|
||||||
if (buffer.isNotEmpty) {
|
|
||||||
await _sendBufferedData(buffer);
|
|
||||||
buffer.clear(); // 清空缓冲区
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打印进度信息(可选)
|
|
||||||
if (current % 50 == 0) {
|
|
||||||
print("I am serving, no problem!");
|
|
||||||
}
|
|
||||||
if (current == 0) {
|
|
||||||
print("Started from first chunk...");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果所有帧都已处理完毕,取消定时器
|
|
||||||
if (current >= total) {
|
|
||||||
timer.cancel();
|
|
||||||
print('All frames sent. Stopping timer...');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int getFrameSize(List<int> data, int offset) {
|
void _sendFramesToHtml() async {
|
||||||
// 查找第一个 Start Code (0x000001 或 0x00000001)
|
// 接收到流数据,保存到缓冲区
|
||||||
const List<int> startCode1 = [0, 0, 0, 1]; // Start Code: 0x000001
|
talkDataRepository.talkDataStream.listen((event) async {
|
||||||
const List<int> startCode2 = [
|
_buffer.addAll(event);
|
||||||
0,
|
});
|
||||||
0,
|
// 缓冲800ms的数据,定时发送
|
||||||
1
|
_sendTimer ??= Timer.periodic(
|
||||||
]; // Start Code: 0x000001 (0x00000001 version)
|
Duration(milliseconds: sendDataToHtmlIntervalTime), (timer) async {
|
||||||
|
// 发送累积的数据
|
||||||
// 查找下一个 Start Code 的位置
|
if (_buffer.isNotEmpty) {
|
||||||
int startCodeStart = -1;
|
await _sendBufferedData(_buffer);
|
||||||
int startCodeEnd = -1;
|
_buffer.clear(); // 清空缓冲区
|
||||||
for (int i = offset; i < data.length - 3; i++) {
|
|
||||||
// 判断是否匹配 Start Code (0x000001 或 0x00000001)
|
|
||||||
if (_matchesStartCode(data, i, startCode1)) {
|
|
||||||
startCodeStart = i;
|
|
||||||
startCodeEnd = i + startCode1.length;
|
|
||||||
break;
|
|
||||||
} else if (_matchesStartCode(data, i, startCode2)) {
|
|
||||||
startCodeStart = i;
|
|
||||||
startCodeEnd = i + startCode2.length;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
// 如果找不到有效的 Start Code,返回 0(结束循环)
|
|
||||||
if (startCodeStart == -1) return 0;
|
|
||||||
|
|
||||||
// 查找下一个 Start Code 的位置
|
|
||||||
int nextStartCodeStart = -1;
|
|
||||||
for (int i = startCodeEnd; i < data.length - 3; i++) {
|
|
||||||
if (_matchesStartCode(data, i, startCode1) ||
|
|
||||||
_matchesStartCode(data, i, startCode2)) {
|
|
||||||
nextStartCodeStart = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果找不到下一个 Start Code,说明当前是最后一个 NAL 单元
|
|
||||||
if (nextStartCodeStart == -1) {
|
|
||||||
return data.length - startCodeStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算并返回当前 NAL 单元的大小
|
|
||||||
return nextStartCodeStart - startCodeStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查数据是否匹配 Start Code
|
|
||||||
bool _matchesStartCode(List<int> data, int index, List<int> startCode) {
|
|
||||||
for (int i = 0; i < startCode.length; i++) {
|
|
||||||
if (data[index + i] != startCode[i]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _loadLocalHtml() async {
|
|
||||||
final String fileHtmlContent =
|
|
||||||
await rootBundle.loadString('assets/html/h264.html');
|
|
||||||
_controller.loadHtmlString(fileHtmlContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: WebViewWidget(controller: _controller),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_sendBufferedData(List<int> buffer) async {
|
|
||||||
String jsCode = "feedDataFromFlutter(${buffer});";
|
|
||||||
await _controller.runJavaScript(jsCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取 NALU 边界并生成 chunks
|
// 提取 NALU 边界并生成 chunks
|
||||||
@ -170,7 +100,7 @@ class _LocalHtmlPageState extends State<LocalHtmlPage> {
|
|||||||
int state = 0;
|
int state = 0;
|
||||||
int lastIndex = 0;
|
int lastIndex = 0;
|
||||||
List<int> result = [];
|
List<int> result = [];
|
||||||
const minNaluPerChunk = 30; // 每个数据块包含的最小NALU数量
|
const minNaluPerChunk = 22; // 每个数据块包含的最小NALU数量
|
||||||
|
|
||||||
while (i < length) {
|
while (i < length) {
|
||||||
value = byteData[i++];
|
value = byteData[i++];
|
||||||
@ -215,13 +145,36 @@ class _LocalHtmlPageState extends State<LocalHtmlPage> {
|
|||||||
result.add(lastIndex);
|
result.add(lastIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 加载html文件
|
||||||
|
Future<void> _loadLocalHtml() async {
|
||||||
|
final String fileHtmlContent =
|
||||||
|
await rootBundle.loadString('assets/html/h264.html');
|
||||||
|
_controller.loadHtmlString(fileHtmlContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送数据给js处理
|
||||||
|
_sendBufferedData(List<int> buffer) async {
|
||||||
|
String jsCode = "feedDataFromFlutter(${buffer});";
|
||||||
|
await _controller.runJavaScript(jsCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return WebViewWidget(controller: _controller);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
timer?.cancel();
|
timer?.cancel();
|
||||||
timer=null;
|
timer = null;
|
||||||
|
_sendTimer?.cancel();
|
||||||
|
timer = null;
|
||||||
|
// talkDataRepository.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user