app-starlock/lib/login/login/JMuxerApp.dart
2024-12-12 10:28:03 +08:00

138 lines
4.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show ByteData, Uint8List, rootBundle;
import 'package:webview_flutter/webview_flutter.dart';
class LocalHtmlPage extends StatefulWidget {
@override
_LocalHtmlPageState createState() => _LocalHtmlPageState();
}
class _LocalHtmlPageState extends State<LocalHtmlPage> {
late final WebViewController _controller;
@override
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..enableZoom(false)
..addJavaScriptChannel(
'Flutter',
onMessageReceived: (message) {
print("来自 HTML 的消息: ${message.message}");
},
);
// 加载本地 HTML
_loadLocalHtml();
_sendFramesToHtml();
}
void _sendFramesToHtml() async {
// 读取 assets/demo.h264 文件
final ByteData data = await rootBundle.load('assets/talk.h264');
final List<int> byteData = data.buffer.asUint8List();
int offset = 0;
int frameSize = 0;
// 根据 H.264 数据的帧结构来逐帧读取并发送
while (offset < byteData.length) {
// 获取每一帧的大小
frameSize = getFrameSize(byteData, offset);
if (frameSize == 0) {
print("No more frames or error in frame size calculation.");
break; // 如果没有更多的帧,或者无法计算帧的大小,则退出循环
}
// 提取当前帧数据
List<int> frameData = byteData.sublist(offset, offset + frameSize);
// 将当前帧数据发送到 WebView 中的 feedDataFromFlutter 函数
String jsCode = "feedDataFromFlutter(${frameData});";
await _controller.runJavaScript(jsCode);
// 更新偏移量,继续发送下一个帧
offset += frameSize;
// 控制帧率,模拟每秒 22 帧播放(或者根据你的视频帧率调整)
await Future.delayed(Duration(milliseconds: (1000 / 22).toInt()));
}
}
int getFrameSize(List<int> data, int offset) {
// 查找第一个 Start Code (0x000001 或 0x00000001)
const List<int> startCode1 = [0, 0, 0, 1]; // Start Code: 0x000001
const List<int> startCode2 = [
0,
0,
1
]; // Start Code: 0x000001 (0x00000001 version)
// 查找下一个 Start Code 的位置
int startCodeStart = -1;
int startCodeEnd = -1;
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(
appBar: AppBar(
title: Text("加载本地 HTML"),
),
body: WebViewWidget(controller: _controller),
);
}
}