// ignore_for_file: avoid_print import 'dart:io'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:path_provider/path_provider.dart'; import 'package:aves/services/cast/cast_fmp4_fragment_parser.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); const channel = MethodChannel( 'aves/cast_video_optimizer', ); testWidgets( 'genera il primo segmento TS dal fragmented MP4', (tester) async { final cacheDirectory = await getApplicationCacheDirectory(); final inputFile = File( '${cacheDirectory.path}/stream_test.fmp4', ); final outputFile = File( '${cacheDirectory.path}/segment_00000.ts', ); expect( await inputFile.exists(), isTrue, reason: 'Copia prima stream_test.fmp4 nella cache Android', ); expect( await inputFile.length(), greaterThan(2344107), ); if (await outputFile.exists()) { await outputFile.delete(); } final partialOutput = File( '${outputFile.path}.part', ); if (await partialOutput.exists()) { await partialOutput.delete(); } const moofOffset = 1684; const moofSize = 3164; const mdatOffset = 4848; const mdatSize = 2339259; const mdatHeaderSize = 8; final source = await inputFile.open( mode: FileMode.read, ); late final List moofBytes; try { await source.setPosition( moofOffset, ); moofBytes = await source.read( moofSize, ); } finally { await source.close(); } expect( moofBytes.length, moofSize, ); const parser = CastFmp4FragmentParser(); final fragment = parser.parse( moofBytes: Uint8List.fromList( moofBytes, ), moofOffset: moofOffset, mdatOffset: mdatOffset, mdatSize: mdatSize, mdatHeaderSize: mdatHeaderSize, initialDecodeTimes: const { 1: 0, 2: 0, }, ); final audioTrack = fragment.tracks.singleWhere( (track) => track.trackId == 1, ); final videoTrack = fragment.tracks.singleWhere( (track) => track.trackId == 2, ); final audioSamples = audioTrack.samples .where( (sample) => sample.decodeTime < 144000, ) .map(_sampleToMap) .toList(growable: false); final videoSamples = videoTrack.samples .where( (sample) => sample.decodeTime < 270000, ) .map(_sampleToMap) .toList(growable: false); expect( audioSamples.length, inInclusiveRange(140, 143), ); expect( videoSamples.length, 90, ); expect( videoTrack.samples.first.isSync, isTrue, ); print( 'FMP4 TOOL INPUT ' 'input=${inputFile.path} ' 'audioSamples=${audioSamples.length} ' 'videoSamples=${videoSamples.length}', ); final report = await channel.invokeMapMethod( 'writeFmp4FirstTsSegmentTest', { 'inputPath': inputFile.path, 'outputPath': outputFile.path, 'audioSamples': audioSamples, 'videoSamples': videoSamples, }, ); expect( report, isNotNull, ); expect( report!['success'], isTrue, ); expect( report['videoSamples'], 90, ); expect( report['audioSamples'], inInclusiveRange(140, 143), ); expect( report['keyframes'], 3, ); expect( report['accessUnitDelimiterCount'], 90, ); expect( await outputFile.exists(), isTrue, ); final outputBytes = await outputFile.length(); expect( outputBytes, greaterThan(0), ); expect( outputBytes % 188, 0, ); print( 'FMP4 FIRST TS TOOL PASS ' 'output=${outputFile.path} ' 'bytes=$outputBytes ' 'report=$report', ); print( 'FILE READY FOR ADB COPY ' 'path=${outputFile.path} ' 'waitingSeconds=120', ); await Future.delayed( const Duration(minutes: 2), ); }, ); } Map _sampleToMap( Fmp4SampleInfo sample, ) { return { 'offset': sample.absoluteOffset, 'size': sample.size, 'dts': sample.decodeTime, 'pts': sample.presentationTime, 'duration': sample.duration, 'sync': sample.isSync, }; }