200 lines
4.3 KiB
Dart
200 lines
4.3 KiB
Dart
// ignore_for_file: avoid_print
|
|
|
|
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:aves/services/cast/cast_fmp4_fragment_parser.dart';
|
|
|
|
Future<void> main(List<String> arguments) async {
|
|
final sourcePath = arguments.isNotEmpty ? arguments.first : 'stream_test.fmp4';
|
|
|
|
final sourceFile = File(sourcePath);
|
|
|
|
if (!await sourceFile.exists()) {
|
|
throw StateError(
|
|
'File fMP4 non trovato: ${sourceFile.absolute.path}',
|
|
);
|
|
}
|
|
|
|
const moofOffset = 1684;
|
|
const moofSize = 3164;
|
|
const mdatOffset = 4848;
|
|
const mdatSize = 2339259;
|
|
const mdatHeaderSize = 8;
|
|
|
|
final source = await sourceFile.open(
|
|
mode: FileMode.read,
|
|
);
|
|
|
|
try {
|
|
await source.setPosition(moofOffset);
|
|
|
|
final moofData = await source.read(
|
|
moofSize,
|
|
);
|
|
|
|
if (moofData.length != moofSize) {
|
|
throw StateError(
|
|
'Lettura moof incompleta: '
|
|
'actual=${moofData.length} '
|
|
'expected=$moofSize',
|
|
);
|
|
}
|
|
|
|
const parser = CastFmp4FragmentParser();
|
|
|
|
final fragment = parser.parse(
|
|
moofBytes: Uint8List.fromList(moofData),
|
|
moofOffset: moofOffset,
|
|
mdatOffset: mdatOffset,
|
|
mdatSize: mdatSize,
|
|
mdatHeaderSize: mdatHeaderSize,
|
|
initialDecodeTimes: const <int, int>{
|
|
1: 0,
|
|
2: 0,
|
|
},
|
|
);
|
|
|
|
print(
|
|
'FRAGMENT '
|
|
'moofOffset=${fragment.moofOffset} '
|
|
'moofSize=${fragment.moofSize} '
|
|
'mdatOffset=${fragment.mdatOffset} '
|
|
'mdatSize=${fragment.mdatSize} '
|
|
'mdatPayloadOffset=${fragment.mdatPayloadOffset} '
|
|
'mdatPayloadSize=${fragment.mdatPayloadSize}',
|
|
);
|
|
|
|
for (final track in fragment.tracks) {
|
|
print(
|
|
'TRACK '
|
|
'trackId=${track.trackId} '
|
|
'sampleCount=${track.sampleCount} '
|
|
'initialDecodeTime=${track.initialDecodeTime} '
|
|
'nextDecodeTime=${track.nextDecodeTime} '
|
|
'totalDuration=${track.totalDuration} '
|
|
'totalSampleBytes=${track.totalSampleBytes} '
|
|
'syncSampleCount=${track.syncSampleCount} '
|
|
'firstSampleOffset=${track.firstSampleAbsoluteOffset}',
|
|
);
|
|
|
|
for (final sample in track.samples.take(3)) {
|
|
print(
|
|
' SAMPLE '
|
|
'index=${sample.index} '
|
|
'offset=${sample.absoluteOffset} '
|
|
'size=${sample.size} '
|
|
'duration=${sample.duration} '
|
|
'dts=${sample.decodeTime} '
|
|
'pts=${sample.presentationTime} '
|
|
'flags=0x${sample.flags.toRadixString(16).padLeft(8, '0')} '
|
|
'sync=${sample.isSync}',
|
|
);
|
|
}
|
|
}
|
|
|
|
final audio = fragment.tracks.singleWhere(
|
|
(track) => track.trackId == 1,
|
|
);
|
|
|
|
final video = fragment.tracks.singleWhere(
|
|
(track) => track.trackId == 2,
|
|
);
|
|
|
|
_expectEqual(
|
|
'audio.sampleCount',
|
|
audio.sampleCount,
|
|
163,
|
|
);
|
|
|
|
_expectEqual(
|
|
'audio.totalDuration',
|
|
audio.totalDuration,
|
|
166912,
|
|
);
|
|
|
|
_expectEqual(
|
|
'audio.totalSampleBytes',
|
|
audio.totalSampleBytes,
|
|
88272,
|
|
);
|
|
|
|
_expectEqual(
|
|
'audio.syncSampleCount',
|
|
audio.syncSampleCount,
|
|
163,
|
|
);
|
|
|
|
_expectEqual(
|
|
'audio.firstSampleOffset',
|
|
audio.firstSampleAbsoluteOffset,
|
|
4856,
|
|
);
|
|
|
|
_expectEqual(
|
|
'video.sampleCount',
|
|
video.sampleCount,
|
|
90,
|
|
);
|
|
|
|
_expectEqual(
|
|
'video.totalDuration',
|
|
video.totalDuration,
|
|
270000,
|
|
);
|
|
|
|
_expectEqual(
|
|
'video.totalSampleBytes',
|
|
video.totalSampleBytes,
|
|
2250979,
|
|
);
|
|
|
|
_expectEqual(
|
|
'video.syncSampleCount',
|
|
video.syncSampleCount,
|
|
3,
|
|
);
|
|
|
|
_expectEqual(
|
|
'video.firstSampleOffset',
|
|
video.firstSampleAbsoluteOffset,
|
|
93128,
|
|
);
|
|
|
|
_expectEqual(
|
|
'video.firstSample.size',
|
|
video.samples.first.size,
|
|
72134,
|
|
);
|
|
|
|
if (!video.samples.first.isSync) {
|
|
throw StateError(
|
|
'Il primo sample video non è sync',
|
|
);
|
|
}
|
|
|
|
_expectEqual(
|
|
'mdatPayloadSize',
|
|
fragment.mdatPayloadSize,
|
|
audio.totalSampleBytes + video.totalSampleBytes,
|
|
);
|
|
|
|
print('FMP4 FRAGMENT PARSER TEST: PASS');
|
|
} finally {
|
|
await source.close();
|
|
}
|
|
}
|
|
|
|
void _expectEqual(
|
|
String name,
|
|
int actual,
|
|
int expected,
|
|
) {
|
|
if (actual != expected) {
|
|
throw StateError(
|
|
'$name inatteso: '
|
|
'actual=$actual '
|
|
'expected=$expected',
|
|
);
|
|
}
|
|
}
|