Skip to content

Commit e4834fe

Browse files
authored
[video_player_avplay] Add subtitle attributes which include type,startTime, stopTime and value to subtitle callback (#848)
1 parent f376a5f commit e4834fe

20 files changed

+463
-25
lines changed

packages/video_player_avplay/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 0.5.21
2+
3+
* Upgrade native player.
4+
1.[PLAYER]Add definitions of the subtitle attributes.
5+
2.[PLAYER]Receive and pass subtitle attributes of streaming to video player in subtitle callback.
6+
* Handle the subtitle attributes which include type, startTime, stopTime and value.
7+
* Pass subtitle attributes to VideoPlayerController.
8+
19
## 0.5.20
210

311
* Add suspend and restore interface.

packages/video_player_avplay/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ To use this package, add `video_player_avplay` as a dependency in your `pubspec.
1212

1313
```yaml
1414
dependencies:
15-
video_player_avplay: ^0.5.20
15+
video_player_avplay: ^0.5.21
1616
```
1717
1818
Then you can import `video_player_avplay` in your Dart code:

packages/video_player_avplay/lib/src/closed_caption_file.dart

Lines changed: 247 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class Caption {
4343
required this.start,
4444
required this.end,
4545
required this.text,
46+
this.subtitleAttributes,
4647
});
4748

4849
/// The number that this caption was assigned.
@@ -58,13 +59,17 @@ class Caption {
5859
/// and [end].
5960
final String text;
6061

62+
/// The subtitile attributes associated with this caption.
63+
final List<SubtitleAttribute?>? subtitleAttributes;
64+
6165
/// A no caption object. This is a caption with [start] and [end] durations of zero,
6266
/// and an empty [text] string.
6367
static const Caption none = Caption(
6468
number: 0,
6569
start: Duration.zero,
6670
end: Duration.zero,
6771
text: '',
72+
subtitleAttributes: <SubtitleAttribute?>[],
6873
);
6974

7075
@override
@@ -73,7 +78,8 @@ class Caption {
7378
'number: $number, '
7479
'start: $start, '
7580
'end: $end, '
76-
'text: $text)';
81+
'text: $text, '
82+
'subtitleAttributes: $subtitleAttributes)';
7783
}
7884

7985
@override
@@ -84,8 +90,246 @@ class Caption {
8490
number == other.number &&
8591
start == other.start &&
8692
end == other.end &&
87-
text == other.text;
93+
text == other.text &&
94+
subtitleAttributes == other.subtitleAttributes;
95+
96+
@override
97+
int get hashCode => Object.hash(number, start, end, text, subtitleAttributes);
98+
}
99+
100+
/// The different types of subtitle attributes that can be set on the player.
101+
enum SubtitleAttrType {
102+
/// Subtitle attribute type region x position
103+
subAttrRegionXPos(SubtitleAttrValueType.double),
104+
105+
/// Subtitle attribute type region y position
106+
subAttrRegionYPos(SubtitleAttrValueType.double),
107+
108+
/// Subtitle attribute type region width
109+
subAttrRegionWidth(SubtitleAttrValueType.double),
110+
111+
/// Subtitle attribute type region height
112+
subAttrRegionHeight(SubtitleAttrValueType.double),
113+
114+
/// Subtitle attribute type window x padding
115+
subAttrWindowXPadding(SubtitleAttrValueType.double),
116+
117+
/// Subtitle attribute type window y padding
118+
subAttrWindowYPadding(SubtitleAttrValueType.double),
119+
120+
/// Subtitle attribute type window left margin
121+
subAttrWindowLeftMargin(SubtitleAttrValueType.int),
122+
123+
/// Subtitle attribute type window right margin
124+
subAttrWindowRightMargin(SubtitleAttrValueType.int),
125+
126+
/// Subtitle attribute type window top margin
127+
subAttrWindowTopMargin(SubtitleAttrValueType.int),
128+
129+
/// Subtitle attribute type window bottom margin
130+
subAttrWindowBottomMargin(SubtitleAttrValueType.int),
131+
132+
/// Subtitle attribute type window opacity
133+
subAttrWindowBgColor(SubtitleAttrValueType.int),
134+
135+
/// Subtitle attribute type window opacity
136+
subAttrWindowOpacity(SubtitleAttrValueType.double),
137+
138+
/// Subtitle attribute type window show background
139+
subAttrWindowShowBg(SubtitleAttrValueType.int),
140+
141+
/// Subtitle attribute type font family
142+
subAttrFontFamily(SubtitleAttrValueType.string),
143+
144+
/// Subtitle attribute type font size
145+
subAttrFontSize(SubtitleAttrValueType.double),
146+
147+
/// Subtitle attribute type font color
148+
subAttrFontWeight(SubtitleAttrValueType.int),
149+
150+
/// Subtitle attribute type font style
151+
subAttrFontStyle(SubtitleAttrValueType.int),
152+
153+
/// Subtitle attribute type font color
154+
subAttrFontColor(SubtitleAttrValueType.int),
155+
156+
/// Subtitle attribute type font bg color
157+
subAttrFontBgColor(SubtitleAttrValueType.int),
158+
159+
/// Subtitle attribute type font opacity
160+
subAttrFontOpacity(SubtitleAttrValueType.double),
161+
162+
/// Subtitle attribute type font bg opacity
163+
subAttrFontBgOpacity(SubtitleAttrValueType.double),
164+
165+
/// Subtitle attribute type font text outline color
166+
subAttrFontTextOutlineColor(SubtitleAttrValueType.int),
167+
168+
/// Subtitle attribute type font text outline thickness
169+
subAttrFontTextOutlineThickness(SubtitleAttrValueType.int),
170+
171+
/// Subtitle attribute type font text outline blur radius
172+
subAttrFontTextOutlineBlurRadius(SubtitleAttrValueType.int),
173+
174+
/// Subtitle attribute type font vertical align
175+
subAttrFontVerticalAlign(SubtitleAttrValueType.int),
176+
177+
/// Subtitle attribute type font horizontal align
178+
subAttrFontHorizontalAlign(SubtitleAttrValueType.int),
179+
180+
/// Subtitle attribute type raw subtitle
181+
subAttrRawSubtitle(SubtitleAttrValueType.string),
182+
183+
/// Subtitle attribute type webvtt cue line num type
184+
subAttrWebvttCueLine(SubtitleAttrValueType.double),
185+
186+
/// Subtitle attribute type webvtt cue line align
187+
subAttrWebvttCueLineNum(SubtitleAttrValueType.int),
188+
189+
/// Subtitle attribute type webvtt cue line align
190+
subAttrWebvttCueLineAlign(SubtitleAttrValueType.int),
191+
192+
/// Subtitle attribute type webvtt cue line align
193+
subAttrWebvttCueAlign(SubtitleAttrValueType.int),
194+
195+
/// Subtitle attribute type webvtt cue size
196+
subAttrWebvttCueSize(SubtitleAttrValueType.double),
197+
198+
/// Subtitle attribute type webvtt cue position
199+
subAttrWebvttCuePosition(SubtitleAttrValueType.double),
200+
201+
/// Subtitle attribute type webvtt cue position align
202+
subAttrWebvttCuePositionAlign(SubtitleAttrValueType.int),
203+
204+
/// Subtitle attribute type webvtt cue vertical
205+
subAttrWebvttCueVertical(SubtitleAttrValueType.int),
206+
207+
/// Subtitle attribute type timestamp
208+
subAttrTimestamp(SubtitleAttrValueType.int),
209+
210+
/// File index of external subtitle
211+
subAttrExtsubInde(SubtitleAttrValueType.none),
212+
213+
/// Default type
214+
subAttrTypeNone(SubtitleAttrValueType.none);
215+
216+
const SubtitleAttrType(this.valueType);
217+
218+
/// The type of the subtitle attribute value. Do not modify.
219+
final SubtitleAttrValueType valueType;
220+
221+
/// Returns the subtitle attribute value type based on the index.
222+
static SubtitleAttrValueType getValueType(int idx) {
223+
return SubtitleAttrType.values[idx].valueType;
224+
}
225+
}
226+
227+
/// The different types of subtitle attribute values that can be set on the player.
228+
enum SubtitleAttrValueType {
229+
/// Subtitle attribute value type integer or uint32_t
230+
int,
231+
232+
/// Subtitle attribute value type float or double
233+
double,
234+
235+
/// Subtitle attribute value type string or char*
236+
string,
237+
238+
/// Subtitle attribute value type none
239+
none,
240+
}
241+
242+
/// A representation of a single attribute.
243+
///
244+
/// The subtitle attributes of the video.
245+
@immutable
246+
class SubtitleAttribute {
247+
/// Creates a new instance of [SubtitleAttribute].
248+
const SubtitleAttribute({
249+
required this.attrType,
250+
required this.startTime,
251+
required this.stopTime,
252+
required this.attrValue,
253+
});
254+
255+
/// Subtitle attribute type of the video.
256+
///
257+
/// Only used if [eventType] is [VideoEventType.subtitleAttrUpdate].
258+
final SubtitleAttrType attrType;
259+
260+
/// Subtitle start time of the video.
261+
///
262+
/// Only used if [eventType] is [VideoEventType.subtitleAttrUpdate].
263+
final int startTime;
264+
265+
/// Subtitle stop time of the video.
266+
///
267+
/// Only used if [eventType] is [VideoEventType.subtitleAttrUpdate].
268+
final int stopTime;
269+
270+
/// Subtitle attribute value of the video.
271+
///
272+
/// Only used if [eventType] is [VideoEventType.subtitleAttrUpdate].
273+
final Object attrValue;
274+
275+
/// Parse a subtitle attribute list from the subtitle attribute list which given by eventListener.
276+
static List<SubtitleAttribute> fromEventSubtitleAttrList(
277+
List<dynamic>? eventSubtitleAttrList,
278+
) {
279+
final List<SubtitleAttribute> subtitleAttributes = <SubtitleAttribute>[];
280+
final List<Map<Object?, Object?>?> subtitleAttrList =
281+
eventSubtitleAttrList!.cast<Map<Object?, Object?>?>();
282+
283+
for (final Map<Object?, Object?>? attr in subtitleAttrList) {
284+
final int attrTypeNum = attr!['attrType']! as int;
285+
final int startTime = attr['startTime']! as int;
286+
final int stopTime = attr['stopTime']! as int;
287+
288+
Object attrValue;
289+
if (SubtitleAttrType.getValueType(attrTypeNum) ==
290+
SubtitleAttrValueType.double) {
291+
attrValue = attr['attrValue']! as double;
292+
} else if (SubtitleAttrType.getValueType(attrTypeNum) ==
293+
SubtitleAttrValueType.int) {
294+
attrValue = attr['attrValue']! as int;
295+
} else if (SubtitleAttrType.getValueType(attrTypeNum) ==
296+
SubtitleAttrValueType.string) {
297+
attrValue = attr['attrValue']! as String;
298+
} else {
299+
attrValue = 'failed';
300+
}
301+
302+
subtitleAttributes.add(
303+
SubtitleAttribute(
304+
attrType: SubtitleAttrType.values[attrTypeNum],
305+
startTime: startTime,
306+
stopTime: stopTime,
307+
attrValue: attrValue,
308+
),
309+
);
310+
}
311+
return subtitleAttributes;
312+
}
313+
314+
@override
315+
String toString() {
316+
return '${objectRuntimeType(this, 'SubtitleAttribute')}('
317+
'attrType: $attrType, '
318+
'startTime: $startTime, '
319+
'stopTime: $stopTime, '
320+
'attrValue: $attrValue)';
321+
}
322+
323+
@override
324+
bool operator ==(Object other) =>
325+
identical(this, other) ||
326+
other is SubtitleAttribute &&
327+
runtimeType == other.runtimeType &&
328+
attrType == other.attrType &&
329+
startTime == other.startTime &&
330+
stopTime == other.stopTime &&
331+
attrValue == other.attrValue;
88332

89333
@override
90-
int get hashCode => Object.hash(number, start, end, text);
334+
int get hashCode => Object.hash(attrType, startTime, stopTime, attrValue);
91335
}

packages/video_player_avplay/lib/src/video_player_tizen.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ class VideoPlayerTizen extends VideoPlayerPlatform {
436436
return VideoEvent(
437437
eventType: VideoEventType.subtitleUpdate,
438438
text: map['text']! as String,
439+
subtitleAttributes: map['attributes']! as List<dynamic>,
439440
);
440441
case 'isPlayingStateUpdate':
441442
return VideoEvent(

packages/video_player_avplay/lib/video_player.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,14 +566,18 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
566566
case VideoEventType.bufferingEnd:
567567
value = value.copyWith(isBuffering: false);
568568
case VideoEventType.subtitleUpdate:
569+
final List<SubtitleAttribute> subtitleAttributes =
570+
SubtitleAttribute.fromEventSubtitleAttrList(
571+
event.subtitleAttributes,
572+
);
569573
final Caption caption = Caption(
570574
number: 0,
571575
start: value.position,
572576
end: value.position + (event.duration?.end ?? Duration.zero),
573577
text: event.text ?? '',
578+
subtitleAttributes: subtitleAttributes,
574579
);
575580
value = value.copyWith(caption: caption);
576-
577581
case VideoEventType.isPlayingStateUpdate:
578582
if (event.isPlaying ?? false) {
579583
value = value.copyWith(

packages/video_player_avplay/lib/video_player_platform_interface.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ class VideoEvent {
473473
this.buffered,
474474
this.text,
475475
this.isPlaying,
476+
this.subtitleAttributes,
476477
});
477478

478479
/// The type of the event.
@@ -503,6 +504,9 @@ class VideoEvent {
503504
/// Only used if [eventType] is [VideoEventType.isPlayingStateUpdate].
504505
final bool? isPlaying;
505506

507+
/// Attributes of the video subtitle.
508+
final List<dynamic>? subtitleAttributes;
509+
506510
@override
507511
bool operator ==(Object other) {
508512
return identical(this, other) ||

packages/video_player_avplay/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: video_player_avplay
22
description: Flutter plugin for displaying inline video on Tizen TV devices.
33
homepage: https://github.com/flutter-tizen/plugins
44
repository: https://github.com/flutter-tizen/plugins/tree/master/packages/video_player_avplay
5-
version: 0.5.20
5+
version: 0.5.21
66

77
environment:
88
sdk: ">=3.1.0 <4.0.0"

0 commit comments

Comments
 (0)