Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[video_player_videohole] Implement video, audio and text track selections. #607

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 82 additions & 1 deletion packages/video_player_videohole/lib/src/messages.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,33 @@ class PlaybackSpeedMessage {
}
}

class TrackSelectionsMessage {
TrackSelectionsMessage({
required this.playerId,
required this.trackSelections,
});

int playerId;

List<Map<Object?, Object?>?> trackSelections;

Object encode() {
return <Object?>[
playerId,
trackSelections,
];
}

static TrackSelectionsMessage decode(Object result) {
result as List<Object?>;
return TrackSelectionsMessage(
playerId: result[0]! as int,
trackSelections:
(result[1] as List<Object?>?)!.cast<Map<Object?, Object?>?>(),
);
}
}

class PositionMessage {
PositionMessage({
required this.playerId,
Expand Down Expand Up @@ -268,9 +295,12 @@ class _VideoPlayerVideoholeApiCodec extends StandardMessageCodec {
} else if (value is PositionMessage) {
buffer.putUint8(134);
writeValue(buffer, value.encode());
} else if (value is VolumeMessage) {
} else if (value is TrackSelectionsMessage) {
buffer.putUint8(135);
writeValue(buffer, value.encode());
} else if (value is VolumeMessage) {
buffer.putUint8(136);
writeValue(buffer, value.encode());
} else {
super.writeValue(buffer, value);
}
Expand All @@ -294,6 +324,8 @@ class _VideoPlayerVideoholeApiCodec extends StandardMessageCodec {
case 134:
return PositionMessage.decode(readValue(buffer)!);
case 135:
return TrackSelectionsMessage.decode(readValue(buffer)!);
case 136:
return VolumeMessage.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
Expand Down Expand Up @@ -518,6 +550,55 @@ class VideoPlayerVideoholeApi {
}
}

Future<TrackSelectionsMessage> trackSelections(PlayerMessage arg_msg) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerVideoholeApi.trackSelections', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_msg]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else if (replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (replyList[0] as TrackSelectionsMessage?)!;
}
}

Future<void> setTrackSelection(TrackSelectionsMessage arg_msg) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerVideoholeApi.setTrackSelection', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_msg]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}

Future<void> pause(PlayerMessage arg_msg) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerVideoholeApi.pause', codec,
Expand Down
78 changes: 78 additions & 0 deletions packages/video_player_videohole/lib/src/video_player_tizen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,77 @@ class VideoPlayerTizen extends VideoPlayerPlatform {
PositionMessage(playerId: playerId, position: position.inMilliseconds));
}

@override
Future<List<TrackSelection>> getTrackSelections(int playerId) async {
final TrackSelectionsMessage response =
await _api.trackSelections(PlayerMessage(playerId: playerId));

final List<TrackSelection> trackSelections = <TrackSelection>[];

for (final Map<Object?, Object?>? trackSelectionMap
in response.trackSelections) {
final TrackSelectionType trackSelectionType =
_intTrackSelectionTypeMap[trackSelectionMap!['trackType']]!;
final bool isUnknown = trackSelectionMap['isUnknown']! as bool;
final int trackId = trackSelectionMap['trackId']! as int;

if (isUnknown) {
trackSelections.add(TrackSelection(
trackId: trackId,
trackType: trackSelectionType,
));
} else {
switch (trackSelectionType) {
case TrackSelectionType.video:
{
final int bitrate = trackSelectionMap['bitrate']! as int;
final int width = trackSelectionMap['width']! as int;
final int height = trackSelectionMap['height']! as int;

trackSelections.add(TrackSelection(
trackId: trackId,
trackType: trackSelectionType,
width: width,
height: height,
bitrate: bitrate == 0 ? null : bitrate,
));
break;
}
case TrackSelectionType.audio:
{
// TODO:implement get audio track.
break;
}
case TrackSelectionType.text:
{
// TODO:implement get text track.
break;
}
}
}
}

return trackSelections;
}

@override
Future<void> setTrackSelection(int playerId, TrackSelection trackSelection) {
final List<Map<Object?, Object?>?> list = <Map<Object?, Object?>?>[
<Object?, Object?>{
'trackId': trackSelection.trackId,
'trackType': _intTrackSelectionTypeMap.keys.firstWhere(
(int key) =>
_intTrackSelectionTypeMap[key] == trackSelection.trackType,
orElse: () => -1),
}
];

return _api.setTrackSelection(TrackSelectionsMessage(
playerId: playerId,
trackSelections: list,
));
}

@override
Future<Duration> getPosition(int playerId) async {
final PositionMessage response =
Expand Down Expand Up @@ -174,4 +245,11 @@ class VideoPlayerTizen extends VideoPlayerPlatform {
VideoFormat.dash: 'dash',
VideoFormat.other: 'other',
};

static const Map<int, TrackSelectionType> _intTrackSelectionTypeMap =
<int, TrackSelectionType>{
1: TrackSelectionType.audio,
2: TrackSelectionType.video,
3: TrackSelectionType.text,
};
}
23 changes: 23 additions & 0 deletions packages/video_player_videohole/lib/video_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class VideoPlayerValue {
this.position = Duration.zero,
this.caption = Caption.none,
this.captionOffset = Duration.zero,
this.trackSelections = const <TrackSelection>[],
swift-kim marked this conversation as resolved.
Show resolved Hide resolved
this.buffered = 0,
this.isInitialized = false,
this.isPlaying = false,
Expand Down Expand Up @@ -106,6 +107,9 @@ class VideoPlayerValue {
/// The current speed of the playback.
final double playbackSpeed;

/// The current playback track selections.
final List<TrackSelection> trackSelections;

/// A description of the error if present.
///
/// If [hasError] is false this is `null`.
Expand Down Expand Up @@ -146,6 +150,7 @@ class VideoPlayerValue {
Duration? position,
Caption? caption,
Duration? captionOffset,
List<TrackSelection>? trackSelections,
int? buffered,
bool? isInitialized,
bool? isPlaying,
Expand All @@ -161,6 +166,7 @@ class VideoPlayerValue {
position: position ?? this.position,
caption: caption ?? this.caption,
captionOffset: captionOffset ?? this.captionOffset,
trackSelections: trackSelections ?? this.trackSelections,
buffered: buffered ?? this.buffered,
isInitialized: isInitialized ?? this.isInitialized,
isPlaying: isPlaying ?? this.isPlaying,
Expand All @@ -182,6 +188,7 @@ class VideoPlayerValue {
'position: $position, '
'caption: $caption, '
'captionOffset: $captionOffset, '
'trackSelections: $trackSelections, '
'buffered: $buffered, '
'isInitialized: $isInitialized, '
'isPlaying: $isPlaying, '
Expand Down Expand Up @@ -577,6 +584,22 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
_updatePosition(position);
}

/// The track selections in the current video.
Future<List<TrackSelection>?> get trackSelections async {
if (!value.isInitialized || _isDisposed) {
return null;
}
return _videoPlayerPlatform.getTrackSelections(_playerId);
}

/// Sets the selected video track selection.
Future<void> setTrackSelection(TrackSelection trackSelection) async {
if (!value.isInitialized || _isDisposed) {
return;
}
await _videoPlayerPlatform.setTrackSelection(_playerId, trackSelection);
}

/// Sets the audio volume of [this].
///
/// [volume] indicates a value between 0.0 (silent) and 1.0 (full volume) on a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ abstract class VideoPlayerPlatform extends PlatformInterface {
throw UnimplementedError('seekTo() has not been implemented.');
}

/// Gets the video [TrackSelection]s. For convenience if the video file has at
/// least one [TrackSelection] for a specific type, the auto track selection will
/// be added to this list with that type.
Future<List<TrackSelection>> getTrackSelections(int playerId) {
throw UnimplementedError('getTrackSelection() has not been implemented.');
}

/// Sets the selected video track selection.
Future<void> setTrackSelection(int playerId, TrackSelection trackSelection) {
throw UnimplementedError('setTrackSelection() has not been implemented.');
}

/// Sets the playback speed to a [speed] value indicating the playback rate.
Future<void> setPlaybackSpeed(int playerId, double speed) {
throw UnimplementedError('setPlaybackSpeed() has not been implemented.');
Expand Down Expand Up @@ -390,3 +402,88 @@ class VideoPlayerOptions {
/// currently no way to implement this feature in this platform).
final bool mixWithOthers;
}

/// A representation of a single track selection.
///
/// A typical video file will include several [TrackSelection]s. For convenience
/// the auto track selection will be added to this list of [getTrackSelections].
@immutable
class TrackSelection {
/// Creates an instance of [VideoEvent].
///
/// The [trackId] and [trackType] argument is required.
///
const TrackSelection({
required this.trackId,
required this.trackType,
this.width,
this.height,
this.bitrate,
});

/// The track id of track selection that uses to determine track selection.
final int trackId;

/// The type of the track selection.
final TrackSelectionType trackType;

/// The width of video track selection. This will be null if the [trackType]
/// is not [TrackSelectionType.video] or an unknowntrack selection.
///
/// If the track selection doesn't specify the width this may be null.
final int? width;

/// The height of video track selection. This will be null if the [trackType]
/// is not [TrackSelectionType.video] or an unknown track selection.
///
/// If the track selection doesn't specify the height this may be null.
final int? height;

/// The label of track selection. This will be null if the [trackType]
/// is not [TrackSelectionType.video] and [TrackSelectionType.audio] or an unknown
/// track selection.
///
/// If the track selection doesn't specify the bitrate this may be null.
final int? bitrate;

@override
String toString() {
return '${objectRuntimeType(this, 'TrackSelection')}('
'trackId: $trackId, '
'trackType: $trackType, '
'width: $width, '
'height: $height, '
'bitrate: $bitrate)';
}

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is TrackSelection &&
runtimeType == other.runtimeType &&
trackId == other.trackId &&
trackType == other.trackType &&
width == other.width &&
height == other.height &&
bitrate == other.bitrate;

@override
int get hashCode =>
trackId.hashCode ^
trackType.hashCode ^
width.hashCode ^
height.hashCode ^
bitrate.hashCode;
}

/// Type of the track selection.
enum TrackSelectionType {
/// The video track selection.
video,

/// The audio track selection.
audio,

/// The text track selection.
text,
}
8 changes: 8 additions & 0 deletions packages/video_player_videohole/pigeons/messages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ class PlaybackSpeedMessage {
double speed;
}

class TrackSelectionsMessage {
TrackSelectionsMessage(this.playerId, this.trackSelections);
int playerId;
List<Map<Object?, Object?>?> trackSelections;
}

class PositionMessage {
PositionMessage(this.playerId, this.position);
int playerId;
Expand Down Expand Up @@ -74,6 +80,8 @@ abstract class VideoPlayerVideoholeApi {
PositionMessage position(PlayerMessage msg);
@async
void seekTo(PositionMessage msg);
TrackSelectionsMessage trackSelections(PlayerMessage msg);
void setTrackSelection(TrackSelectionsMessage msg);
hyue7 marked this conversation as resolved.
Show resolved Hide resolved
void pause(PlayerMessage msg);
void setMixWithOthers(MixWithOthersMessage msg);
void setDisplayGeometry(GeometryMessage msg);
Expand Down
Loading