本地视频延迟优化+视频的获取链路播放
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
// Copyright 2013 The Flutter Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:video_player_example/main.dart' as app;
|
||||
|
||||
/// Entry point for integration tests that require espresso.
|
||||
@pragma('vm:entry-point')
|
||||
void integrationTestMain() {
|
||||
enableFlutterDriverExtension();
|
||||
|
||||
app.main();
|
||||
}
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// Since this file is lacking integration tests, this test ensures the example
|
||||
// app can be launched on an emulator/device.
|
||||
testWidgets('Launch Test', (WidgetTester tester) async {});
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
// Copyright 2013 The Flutter Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/services.dart' show rootBundle;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:video_player_android/video_player_android.dart';
|
||||
import 'package:video_player_platform_interface/video_player_platform_interface.dart';
|
||||
|
||||
const Duration _playDuration = Duration(seconds: 1);
|
||||
const String _videoAssetKey = 'assets/Butterfly-209.mp4';
|
||||
|
||||
// Returns the URL to load an asset from this example app as a network source.
|
||||
//
|
||||
// TODO(stuartmorgan): Convert this to a local `HttpServer` that vends the
|
||||
// assets directly, https://github.com/flutter/flutter/issues/95420
|
||||
String getUrlForAssetAsNetworkSource(String assetKey) {
|
||||
return 'https://github.com/flutter/packages/blob/'
|
||||
// This hash can be rolled forward to pick up newly-added assets.
|
||||
'2e1673307ff7454aff40b47024eaed49a9e77e81'
|
||||
'/packages/video_player/video_player/example/'
|
||||
'$assetKey'
|
||||
'?raw=true';
|
||||
}
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
late AndroidVideoPlayer player;
|
||||
|
||||
setUp(() async {
|
||||
player = AndroidVideoPlayer();
|
||||
await player.init();
|
||||
});
|
||||
|
||||
testWidgets('registers expected implementation', (_) async {
|
||||
AndroidVideoPlayer.registerWith();
|
||||
expect(VideoPlayerPlatform.instance, isA<AndroidVideoPlayer>());
|
||||
});
|
||||
|
||||
testWidgets('initializes at the start', (_) async {
|
||||
final int playerId = (await player.create(
|
||||
DataSource(sourceType: DataSourceType.asset, asset: _videoAssetKey),
|
||||
))!;
|
||||
|
||||
expect(
|
||||
await _getDuration(player, playerId),
|
||||
const Duration(seconds: 7, milliseconds: 540),
|
||||
);
|
||||
|
||||
await player.dispose(playerId);
|
||||
});
|
||||
|
||||
testWidgets('can be played', (WidgetTester tester) async {
|
||||
final int playerId = (await player.create(
|
||||
DataSource(sourceType: DataSourceType.asset, asset: _videoAssetKey),
|
||||
))!;
|
||||
|
||||
await player.play(playerId);
|
||||
await tester.pumpAndSettle(_playDuration);
|
||||
|
||||
expect(await player.getPosition(playerId), greaterThan(Duration.zero));
|
||||
await player.dispose(playerId);
|
||||
});
|
||||
|
||||
testWidgets('can seek', (WidgetTester tester) async {
|
||||
final int playerId = (await player.create(
|
||||
DataSource(sourceType: DataSourceType.asset, asset: _videoAssetKey),
|
||||
))!;
|
||||
|
||||
await player.seekTo(playerId, const Duration(seconds: 3));
|
||||
await tester.pumpAndSettle(_playDuration);
|
||||
|
||||
expect(
|
||||
await player.getPosition(playerId),
|
||||
greaterThanOrEqualTo(const Duration(seconds: 3)),
|
||||
);
|
||||
await player.dispose(playerId);
|
||||
});
|
||||
|
||||
testWidgets('can pause', (WidgetTester tester) async {
|
||||
final int playerId = (await player.create(
|
||||
DataSource(sourceType: DataSourceType.asset, asset: _videoAssetKey),
|
||||
))!;
|
||||
|
||||
await player.play(playerId);
|
||||
await tester.pumpAndSettle(_playDuration);
|
||||
|
||||
await player.pause(playerId);
|
||||
await tester.pumpAndSettle(_playDuration);
|
||||
final Duration pausedDuration = await player.getPosition(playerId);
|
||||
await tester.pumpAndSettle(_playDuration);
|
||||
|
||||
expect(await player.getPosition(playerId), pausedDuration);
|
||||
await player.dispose(playerId);
|
||||
});
|
||||
|
||||
testWidgets('can play a video from a file', (WidgetTester tester) async {
|
||||
final Directory directory = await getTemporaryDirectory();
|
||||
final file = File('${directory.path}/video.mp4');
|
||||
await file.writeAsBytes(
|
||||
Uint8List.fromList(
|
||||
(await rootBundle.load(_videoAssetKey)).buffer.asUint8List(),
|
||||
),
|
||||
);
|
||||
|
||||
final int playerId = (await player.create(
|
||||
DataSource(sourceType: DataSourceType.file, uri: file.path),
|
||||
))!;
|
||||
|
||||
await player.play(playerId);
|
||||
await tester.pumpAndSettle(_playDuration);
|
||||
|
||||
expect(await player.getPosition(playerId), greaterThan(Duration.zero));
|
||||
await directory.delete(recursive: true);
|
||||
await player.dispose(playerId);
|
||||
});
|
||||
|
||||
testWidgets('can play a video from network', (WidgetTester tester) async {
|
||||
final int playerId = (await player.create(
|
||||
DataSource(
|
||||
sourceType: DataSourceType.network,
|
||||
uri: getUrlForAssetAsNetworkSource(_videoAssetKey),
|
||||
),
|
||||
))!;
|
||||
|
||||
await player.play(playerId);
|
||||
await player.seekTo(playerId, const Duration(seconds: 5));
|
||||
await tester.pumpAndSettle(_playDuration);
|
||||
await player.pause(playerId);
|
||||
|
||||
expect(await player.getPosition(playerId), greaterThan(Duration.zero));
|
||||
|
||||
final DurationRange range = await _getBufferingRange(player, playerId);
|
||||
expect(range.start, Duration.zero);
|
||||
expect(range.end, greaterThan(Duration.zero));
|
||||
|
||||
await player.dispose(playerId);
|
||||
});
|
||||
}
|
||||
|
||||
Future<Duration> _getDuration(AndroidVideoPlayer player, int playerId) {
|
||||
return player
|
||||
.videoEventsFor(playerId)
|
||||
.firstWhere((VideoEvent event) {
|
||||
return event.eventType == VideoEventType.initialized;
|
||||
})
|
||||
.then((VideoEvent event) {
|
||||
return event.duration!;
|
||||
});
|
||||
}
|
||||
|
||||
Future<DurationRange> _getBufferingRange(
|
||||
AndroidVideoPlayer player,
|
||||
int playerId,
|
||||
) {
|
||||
return player
|
||||
.videoEventsFor(playerId)
|
||||
.firstWhere((VideoEvent event) {
|
||||
return event.eventType == VideoEventType.bufferingUpdate;
|
||||
})
|
||||
.then((VideoEvent event) {
|
||||
return event.buffered!.first;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user