2025-04-21 10:56:28 +08:00
|
|
|
|
import 'dart:async';
|
|
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
import 'dart:typed_data';
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
|
|
|
|
|
|
|
|
import 'video_decode_plugin_platform_interface.dart';
|
|
|
|
|
|
|
|
|
|
|
|
/// 视频解码器配置
|
|
|
|
|
|
class VideoDecoderConfig {
|
2025-04-29 17:11:38 +08:00
|
|
|
|
/// 视频宽度
|
2025-04-21 10:56:28 +08:00
|
|
|
|
final int width;
|
|
|
|
|
|
|
2025-04-29 17:11:38 +08:00
|
|
|
|
/// 视频高度
|
2025-04-21 10:56:28 +08:00
|
|
|
|
final int height;
|
|
|
|
|
|
|
|
|
|
|
|
/// 编码类型,默认h264
|
2025-04-29 17:11:38 +08:00
|
|
|
|
final String codecType;
|
2025-04-24 14:23:26 +08:00
|
|
|
|
|
2025-04-21 10:56:28 +08:00
|
|
|
|
/// 构造函数
|
|
|
|
|
|
VideoDecoderConfig({
|
2025-04-29 17:11:38 +08:00
|
|
|
|
required this.width,
|
|
|
|
|
|
required this.height,
|
|
|
|
|
|
this.codecType = 'h264',
|
2025-04-21 10:56:28 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/// 转换为Map
|
|
|
|
|
|
Map<String, dynamic> toMap() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
'width': width,
|
|
|
|
|
|
'height': height,
|
2025-04-29 17:11:38 +08:00
|
|
|
|
'codecType': codecType,
|
2025-04-21 10:56:28 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 视频解码插件主类
|
|
|
|
|
|
class VideoDecodePlugin {
|
|
|
|
|
|
static const MethodChannel _channel = MethodChannel('video_decode_plugin');
|
|
|
|
|
|
|
2025-04-29 17:11:38 +08:00
|
|
|
|
static int? _textureId;
|
2025-04-21 16:08:23 +08:00
|
|
|
|
|
2025-04-29 17:11:38 +08:00
|
|
|
|
/// 初始化解码器
|
|
|
|
|
|
static Future<int?> initDecoder(VideoDecoderConfig config) async {
|
|
|
|
|
|
final textureId = await _channel.invokeMethod<int>('initDecoder', config.toMap());
|
|
|
|
|
|
_textureId = textureId;
|
|
|
|
|
|
return textureId;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 解码视频帧(参数扩展)
|
|
|
|
|
|
static Future<bool> decodeFrame({
|
|
|
|
|
|
required Uint8List frameData,
|
|
|
|
|
|
required int frameType, // 0=I帧, 1=P帧
|
|
|
|
|
|
required int timestamp, // 毫秒或微秒
|
|
|
|
|
|
required int frameSeq, // 帧序号
|
|
|
|
|
|
int? refIFrameSeq, // P帧时可选
|
|
|
|
|
|
}) async {
|
|
|
|
|
|
if (_textureId == null) return false;
|
|
|
|
|
|
final params = {
|
|
|
|
|
|
'textureId': _textureId,
|
|
|
|
|
|
'frameData': frameData,
|
|
|
|
|
|
'frameType': frameType,
|
|
|
|
|
|
'timestamp': timestamp,
|
|
|
|
|
|
'frameSeq': frameSeq,
|
|
|
|
|
|
if (refIFrameSeq != null) 'refIFrameSeq': refIFrameSeq,
|
|
|
|
|
|
};
|
|
|
|
|
|
final result = await _channel.invokeMethod<bool>('decodeFrame', params);
|
|
|
|
|
|
return result ?? false;
|
2025-04-21 16:08:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-29 17:11:38 +08:00
|
|
|
|
/// 释放解码器资源
|
|
|
|
|
|
static Future<bool> releaseDecoder() async {
|
|
|
|
|
|
if (_textureId == null) return true;
|
|
|
|
|
|
final result = await _channel.invokeMethod<bool>('releaseDecoder', {
|
|
|
|
|
|
'textureId': _textureId,
|
2025-04-21 16:08:23 +08:00
|
|
|
|
});
|
2025-04-29 17:11:38 +08:00
|
|
|
|
_textureId = null;
|
|
|
|
|
|
return result ?? false;
|
2025-04-21 16:08:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-21 10:56:28 +08:00
|
|
|
|
/// 获取平台版本
|
|
|
|
|
|
static Future<String?> getPlatformVersion() {
|
|
|
|
|
|
return VideoDecodePluginPlatform.instance.getPlatformVersion();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 检查当前平台是否支持
|
|
|
|
|
|
static bool get isPlatformSupported {
|
|
|
|
|
|
return Platform.isAndroid || Platform.isIOS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 获取默认纹理ID
|
2025-04-29 17:11:38 +08:00
|
|
|
|
static int? get textureId => _textureId;
|
2025-04-21 10:56:28 +08:00
|
|
|
|
|
|
|
|
|
|
/// 注册插件(不需要手动调用)
|
|
|
|
|
|
static void registerWith() {
|
|
|
|
|
|
// 仅用于插件注册
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-21 16:08:23 +08:00
|
|
|
|
|
|
|
|
|
|
/// 在Dart中实现简单的同步锁
|
|
|
|
|
|
void synchronized(Object lock, Function() action) {
|
|
|
|
|
|
// 在单线程的Dart中,我们不需要真正的锁
|
|
|
|
|
|
// 但我们保留这个结构以便将来可能的改进
|
|
|
|
|
|
action();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 在同步锁中执行并返回结果的版本
|
|
|
|
|
|
T synchronizedWithResult<T>(Object lock, T Function() action) {
|
|
|
|
|
|
return action();
|
|
|
|
|
|
}
|