Skip to content

Commit

Permalink
Features absolute position from hls (#223)
Browse files Browse the repository at this point in the history
* Features absolute position from hls

* Flutter format absolute position

Co-authored-by: Egor <ead@tvip.ru>
  • Loading branch information
FlutterSu and Egor authored Jan 20, 2021
1 parent fd4b63e commit 77bdd3a
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 2 deletions.
11 changes: 11 additions & 0 deletions android/src/main/java/com/jhomlala/better_player/BetterPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.EventListener;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
Expand Down Expand Up @@ -550,6 +551,16 @@ long getPosition() {
return exoPlayer.getCurrentPosition();
}

long getAbsolutePosition() {
Timeline timeline = exoPlayer.getCurrentTimeline();
if (!timeline.isEmpty()) {
long windowStartTimeMs = timeline.getWindow(0, new Timeline.Window()).windowStartTimeMs;
long pos = exoPlayer.getCurrentPosition();
return (windowStartTimeMs + pos);
}
return exoPlayer.getCurrentPosition();
}

@SuppressWarnings("SuspiciousNameCombination")
private void sendInitialized() {
if (isInitialized) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class BetterPlayerPlugin implements FlutterPlugin, ActivityAware, MethodC
private static final String PAUSE_METHOD = "pause";
private static final String SEEK_TO_METHOD = "seekTo";
private static final String POSITION_METHOD = "position";
private static final String ABSOLUTE_POSITION_METHOD = "absolutePosition";
private static final String SET_SPEED_METHOD = "setSpeed";
private static final String SET_TRACK_PARAMETERS_METHOD = "setTrackParameters";
private static final String DISPOSE_METHOD = "dispose";
Expand Down Expand Up @@ -232,6 +233,9 @@ private void onMethodCall(MethodCall call, Result result, long textureId, Better
result.success(player.getPosition());
player.sendBufferingUpdate();
break;
case ABSOLUTE_POSITION_METHOD:
result.success(player.getAbsolutePosition());
break;
case SET_SPEED_METHOD:
player.setSpeed(call.argument(SPEED_PARAMETER));
result.success(null);
Expand Down
10 changes: 10 additions & 0 deletions ios/Classes/FLTBetterPlayerPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ int64_t FLTCMTimeToMillis(CMTime time) {
return time.value * 1000 / time.timescale;
}

int64_t FLTNSTimeIntervalToMillis(NSTimeInterval interval) {
return (int64_t)(interval * 1000.0);
}

@interface FLTFrameUpdater : NSObject
@property(nonatomic) int64_t textureId;
@property(nonatomic, weak, readonly) NSObject<FlutterTextureRegistry>* registry;
Expand Down Expand Up @@ -477,6 +481,10 @@ - (int64_t)position {
return FLTCMTimeToMillis([_player currentTime]);
}

- (int64_t)absolutePosition {
return FLTNSTimeIntervalToMillis([[[_player currentItem] currentDate] timeIntervalSince1970]);
}

- (int64_t)duration {
CMTime time;
if (@available(iOS 13, *)) {
Expand Down Expand Up @@ -1065,6 +1073,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
result(nil);
} else if ([@"position" isEqualToString:call.method]) {
result(@([player position]));
} else if ([@"absolutePosition" isEqualToString:call.method]) {
result(@([player absolutePosition]));
} else if ([@"seekTo" isEqualToString:call.method]) {
[player seekTo:[argsMap[@"location"] intValue]];
result(nil);
Expand Down
11 changes: 11 additions & 0 deletions lib/src/video_player/method_channel_video_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,17 @@ class MethodChannelVideoPlayer extends VideoPlayerPlatform {
}

@override
Future<DateTime> getAbsolutePosition(int textureId) async {
final int milliseconds = await _channel.invokeMethod<int>(
'absolutePosition',
<String, dynamic>{'textureId': textureId},
);

if (milliseconds <= 0) return null;

return DateTime.fromMillisecondsSinceEpoch(milliseconds);
}

Future<void> enablePictureInPicture(int textureId, double top, double left,
double width, double height) async {
return _channel.invokeMethod<void>(
Expand Down
24 changes: 22 additions & 2 deletions lib/src/video_player/video_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class VideoPlayerValue {
@required this.duration,
this.size,
this.position = const Duration(),
this.absolutePosition,
this.caption = const Caption(),
this.buffered = const <DurationRange>[],
this.isPlaying = false,
Expand Down Expand Up @@ -61,6 +62,11 @@ class VideoPlayerValue {
/// The current playback position.
final Duration position;

/// The current absolute playback position.
///
/// Is null when is not available.
final DateTime absolutePosition;

/// The [Caption] that should be displayed based on the current [position].
///
/// This field will never be null. If there is no caption for the current
Expand Down Expand Up @@ -124,6 +130,7 @@ class VideoPlayerValue {
Duration duration,
Size size,
Duration position,
DateTime absolutePosition,
Caption caption,
List<DurationRange> buffered,
bool isPlaying,
Expand All @@ -138,6 +145,7 @@ class VideoPlayerValue {
duration: duration ?? this.duration,
size: size ?? this.size,
position: position ?? this.position,
absolutePosition: absolutePosition ?? this.absolutePosition,
caption: caption ?? this.caption,
buffered: buffered ?? this.buffered,
isPlaying: isPlaying ?? this.isPlaying,
Expand All @@ -157,6 +165,7 @@ class VideoPlayerValue {
'duration: $duration, '
'size: $size, '
'position: $position, '
'absolutePosition: $absolutePosition, '
'caption: $caption, '
'buffered: [${buffered.join(', ')}], '
'isPlaying: $isPlaying, '
Expand Down Expand Up @@ -464,11 +473,12 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
return;
}
final Duration newPosition = await position;
final DateTime newAbsolutePosition = await absolutePosition;
// ignore: invariant_booleans
if (_isDisposed) {
return;
}
_updatePosition(newPosition);
_updatePosition(newPosition, absolutePosition: newAbsolutePosition);
},
);
} else {
Expand Down Expand Up @@ -498,6 +508,15 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
return _videoPlayerPlatform.getPosition(_textureId);
}

/// The absolute position in the current video stream
/// (i.e. EXT-X-PROGRAM-DATE-TIME in HLS).
Future<DateTime> get absolutePosition async {
if (!value.initialized && _isDisposed) {
return null;
}
return _videoPlayerPlatform.getAbsolutePosition(_textureId);
}

/// Sets the video's current timestamp to be at [moment]. The next
/// time the video is played it will resume from the given [moment].
///
Expand Down Expand Up @@ -577,8 +596,9 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
return const Caption();
}

void _updatePosition(Duration position) {
void _updatePosition(Duration position, {DateTime absolutePosition}) {
value = value.copyWith(position: position);
value = value.copyWith(absolutePosition: absolutePosition);
value = value.copyWith(caption: _getCaptionAt(position));
}

Expand Down
5 changes: 5 additions & 0 deletions lib/src/video_player/video_player_platform_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ abstract class VideoPlayerPlatform {
throw UnimplementedError('getPosition() has not been implemented.');
}

/// Gets the video position as [DateTime].
Future<DateTime> getAbsolutePosition(int textureId) {
throw UnimplementedError('getAbsolutePosition() has not been implemented.');
}

///Enables PiP mode.
Future<void> enablePictureInPicture(
int textureId, double top, double left, double width, double height) {
Expand Down

0 comments on commit 77bdd3a

Please sign in to comment.