9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
146 lines
4.2 KiB
Dart
146 lines
4.2 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:buzz/shared/relay/mp4_fast_start.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
late Directory tempDirectory;
|
|
|
|
setUp(() async {
|
|
tempDirectory = await Directory.systemTemp.createTemp(
|
|
'buzz-faststart-test-',
|
|
);
|
|
});
|
|
|
|
tearDown(() async {
|
|
await tempDirectory.delete(recursive: true);
|
|
});
|
|
|
|
for (final offsetBox in ['stco', 'co64']) {
|
|
test('moves moov before mdat and patches $offsetBox offsets', () async {
|
|
final ftyp = _box('ftyp', [
|
|
...ascii.encode('isom'),
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
...ascii.encode('isom'),
|
|
]);
|
|
final mdat = _box('mdat', [1, 2, 3, 4]);
|
|
final originalMediaOffset = ftyp.length + 8;
|
|
final offsetPayload = BytesBuilder()
|
|
..add([0, 0, 0, 0])
|
|
..add(_uint32(1))
|
|
..add(
|
|
offsetBox == 'stco'
|
|
? _uint32(originalMediaOffset)
|
|
: _uint64(originalMediaOffset),
|
|
);
|
|
final sampleTable = _box(offsetBox, offsetPayload.takeBytes());
|
|
final moov = _nestedMoov(sampleTable);
|
|
final sourceBytes = Uint8List.fromList([...ftyp, ...mdat, ...moov]);
|
|
final source = File('${tempDirectory.path}/source.mp4');
|
|
final destination = File('${tempDirectory.path}/output.mp4');
|
|
await source.writeAsBytes(sourceBytes);
|
|
|
|
await rewriteMp4ForFastStart(source, destination);
|
|
|
|
final output = await destination.readAsBytes();
|
|
expect(_topLevelTypes(output), ['ftyp', 'moov', 'mdat']);
|
|
expect(
|
|
output.sublist(ftyp.length + moov.length + 8),
|
|
equals([1, 2, 3, 4]),
|
|
);
|
|
|
|
final typeOffset = _findAscii(output, offsetBox);
|
|
expect(typeOffset, greaterThanOrEqualTo(4));
|
|
final entryOffset = typeOffset + 12;
|
|
final adjusted = offsetBox == 'stco'
|
|
? _readUint32(output, entryOffset)
|
|
: _readUint64(output, entryOffset);
|
|
expect(adjusted, originalMediaOffset + moov.length);
|
|
});
|
|
}
|
|
|
|
test(
|
|
'rejects excessive nested box depth and deletes partial output',
|
|
() async {
|
|
final ftyp = _box('ftyp', [
|
|
...ascii.encode('isom'),
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
...ascii.encode('isom'),
|
|
]);
|
|
final mdat = _box('mdat', [1]);
|
|
var nested = _box('stco', [0, 0, 0, 0, ..._uint32(0)]);
|
|
for (var index = 0; index < 34; index++) {
|
|
nested = _box('stbl', nested);
|
|
}
|
|
final source = File('${tempDirectory.path}/deep.mp4');
|
|
final destination = File('${tempDirectory.path}/output.mp4');
|
|
await source.writeAsBytes([...ftyp, ...mdat, ..._box('moov', nested)]);
|
|
|
|
await expectLater(
|
|
rewriteMp4ForFastStart(source, destination),
|
|
throwsA(isA<FormatException>()),
|
|
);
|
|
expect(await destination.exists(), isFalse);
|
|
},
|
|
);
|
|
}
|
|
|
|
Uint8List _nestedMoov(List<int> leaf) =>
|
|
_box('moov', _box('trak', _box('mdia', _box('minf', _box('stbl', leaf)))));
|
|
|
|
Uint8List _box(String type, List<int> payload) => Uint8List.fromList([
|
|
..._uint32(payload.length + 8),
|
|
...ascii.encode(type),
|
|
...payload,
|
|
]);
|
|
|
|
Uint8List _uint32(int value) {
|
|
final bytes = ByteData(4)..setUint32(0, value, Endian.big);
|
|
return bytes.buffer.asUint8List();
|
|
}
|
|
|
|
Uint8List _uint64(int value) {
|
|
final bytes = ByteData(8)..setUint64(0, value, Endian.big);
|
|
return bytes.buffer.asUint8List();
|
|
}
|
|
|
|
int _readUint32(Uint8List bytes, int offset) =>
|
|
ByteData.sublistView(bytes).getUint32(offset, Endian.big);
|
|
|
|
int _readUint64(Uint8List bytes, int offset) =>
|
|
ByteData.sublistView(bytes).getUint64(offset, Endian.big);
|
|
|
|
List<String> _topLevelTypes(Uint8List bytes) {
|
|
final types = <String>[];
|
|
var offset = 0;
|
|
while (offset < bytes.length) {
|
|
final size = _readUint32(bytes, offset);
|
|
types.add(ascii.decode(bytes.sublist(offset + 4, offset + 8)));
|
|
offset += size;
|
|
}
|
|
return types;
|
|
}
|
|
|
|
int _findAscii(Uint8List bytes, String value) {
|
|
final needle = ascii.encode(value);
|
|
for (var offset = 0; offset + needle.length <= bytes.length; offset++) {
|
|
var matches = true;
|
|
for (var index = 0; index < needle.length; index++) {
|
|
if (bytes[offset + index] != needle[index]) {
|
|
matches = false;
|
|
break;
|
|
}
|
|
}
|
|
if (matches) return offset;
|
|
}
|
|
return -1;
|
|
}
|