video_decode_plugin/lib/nalu_utils.dart
2025-04-30 16:12:22 +08:00

70 lines
2.0 KiB
Dart

/// NALU相关工具类与结构体
import 'dart:typed_data';
/// NALU单元结构体
class NaluUnit {
final int type; // NALU类型
final List<int> data;
NaluUnit(this.type, this.data);
}
class NaluUtils {
/// 分离一帧数据中的所有NALU单元
static List<NaluUnit> splitNalus(List<int> data) {
final List<NaluUnit> nalus = [];
int i = 0;
List<int> startCodes = [];
// 先找到所有起始码位置
while (i < data.length - 3) {
if (i < data.length - 4 &&
data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && data[i + 3] == 1) {
startCodes.add(i);
i += 4;
} else if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) {
startCodes.add(i);
i += 3;
} else {
i++;
}
}
// 补上结尾
startCodes.add(data.length);
// 分割NALU
int nalusTotalLen = 0;
for (int idx = 0; idx < startCodes.length - 1; idx++) {
int start = startCodes[idx];
int next = startCodes[idx + 1];
int skip = (data[start] == 0 && data[start + 1] == 0 && data[start + 2] == 0 && data[start + 3] == 1) ? 4 : 3;
int naluStart = start + skip;
if (naluStart < next) {
final nalu = data.sublist(start, next);
nalusTotalLen += nalu.length;
if (nalu.isNotEmpty) {
nalus.add(NaluUnit(getNaluType(nalu), nalu));
}
}
}
if (nalus.isEmpty && data.isNotEmpty) {
nalus.add(NaluUnit(getNaluType(data), data));
} else if (nalusTotalLen < data.length) {
nalus.add(NaluUnit(getNaluType(data.sublist(nalusTotalLen)), data.sublist(nalusTotalLen)));
}
return nalus;
}
/// 获取NALU类型
static int getNaluType(List<int> nalu) {
if (nalu.isEmpty) return -1;
int offset = 0;
if (nalu.length >= 4 && nalu[0] == 0x00 && nalu[1] == 0x00) {
if (nalu[2] == 0x01)
offset = 3;
else if (nalu[2] == 0x00 && nalu[3] == 0x01)
offset = 4;
}
if (nalu.length > offset) {
return nalu[offset] & 0x1F;
}
return -1;
}
}