Skip to content

Commit 4a94775

Browse files
committed
[ffi] Add Player.videoDimensionsStream
1 parent 304a302 commit 4a94775

File tree

7 files changed

+103
-98
lines changed

7 files changed

+103
-98
lines changed

ffi/lib/src/internal/ffi.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,16 @@ final ReceivePort receiver = new ReceivePort()
289289
.add(players[playerId]!.general);
290290
break;
291291
}
292+
case 'videoDimensionEvent':
293+
{
294+
players[playerId]!.videoDimensions =
295+
VideoDimensions(int.parse(event[2]), int.parse(event[3]));
296+
if (!players[playerId]!.videoDimensionsController.isClosed)
297+
players[playerId]!
298+
.videoDimensionsController
299+
.add(players[playerId]!.videoDimensions);
300+
break;
301+
}
292302
}
293303
} else {
294304
videoFrameCallback(event[0], event[1]);

ffi/lib/src/player.dart

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,19 @@ import 'package:dart_vlc_ffi/src/mediaSource/media.dart';
88
import 'package:dart_vlc_ffi/src/mediaSource/mediaSource.dart';
99
import 'package:dart_vlc_ffi/src/device.dart';
1010

11+
/// Represents dimensions of a video.
12+
class VideoDimensions {
13+
/// Width of the video.
14+
final int width;
15+
16+
/// Height of the video.
17+
final int height;
18+
const VideoDimensions(this.width, this.height);
19+
20+
@override
21+
String toString() => '($width, $height)';
22+
}
23+
1124
/// Keeps various [Player] instances to manage event callbacks.
1225
Map<int, Player> players = {};
1326

@@ -20,31 +33,12 @@ Map<int, Player> players = {};
2033
/// Player player = new Player(id: 0);
2134
/// ```
2235
///
23-
/// If you wish to use this instance for [Video] playback, then provide [videoWidth] & [videoHeight] optional parameters.
24-
/// Higher value may lead to degraded performance.
25-
///
26-
/// ```dart
27-
/// Player player = new Player(
28-
/// id: 0,
29-
/// videoWidth: 1920,
30-
/// videoHeight: 1080,
31-
/// );
32-
/// ```
33-
///
34-
/// Do not provide [videoWidth] & [videoHeight], if you wish to use the [Player] for only audio playback.
35-
///
3636
/// Use various methods & event streams available to control & listen to events of the playback.
3737
///
3838
class Player {
3939
/// Id associated with the [Player] instance.
4040
int id;
4141

42-
/// Width of the [Video] frames to be extracted. Higher value may lead to degraded performance.
43-
late int videoWidth;
44-
45-
/// Height of the [Video] frames to be extracted. Higher value may lead to degraded performance.
46-
late int videoHeight;
47-
4842
/// Commandline arguments passed to this instance of [Player].
4943
List<String> commandlineArguments = <String>[];
5044

@@ -72,6 +66,12 @@ class Player {
7266
/// Stream to listen to volume & rate state of the [Player] instance.
7367
late Stream<GeneralState> generalStream;
7468

69+
/// Dimensions of the currently playing video.
70+
VideoDimensions videoDimensions = new VideoDimensions(0, 0);
71+
72+
/// Stream to listen to dimensions of currently playing video.
73+
late Stream<VideoDimensions> videoDimensionsStream;
74+
7575
/// Creates a new [Player] instance.
7676
///
7777
/// Takes unique id as parameter.
@@ -82,13 +82,10 @@ class Player {
8282
///
8383
Player(
8484
{required this.id,
85-
int videoWidth: 0,
86-
int videoHeight: 0,
85+
VideoDimensions? videoDimensions,
8786
List<String>? commandlineArguments}) {
8887
if (commandlineArguments != null)
8988
this.commandlineArguments = commandlineArguments;
90-
this.videoWidth = videoWidth;
91-
this.videoHeight = videoHeight;
9289
this.currentController = StreamController<CurrentState>.broadcast();
9390
this.currentStream = this.currentController.stream;
9491
this.positionController = StreamController<PositionState>.broadcast();
@@ -97,11 +94,17 @@ class Player {
9794
this.playbackStream = this.playbackController.stream;
9895
this.generalController = StreamController<GeneralState>.broadcast();
9996
this.generalStream = this.generalController.stream;
97+
if (videoDimensions != null) {
98+
this.videoDimensions = videoDimensions;
99+
}
100+
this.videoDimensionsController =
101+
StreamController<VideoDimensions>.broadcast();
102+
this.videoDimensionsStream = this.videoDimensionsController.stream;
100103
players[this.id] = this;
101104
PlayerFFI.create(
102105
this.id,
103-
this.videoWidth,
104-
this.videoHeight,
106+
this.videoDimensions.width,
107+
this.videoDimensions.width,
105108
this.commandlineArguments.length,
106109
this.commandlineArguments.toNativeUtf8Array(),
107110
);
@@ -272,6 +275,7 @@ class Player {
272275
this.positionController.close();
273276
this.playbackController.close();
274277
this.generalController.close();
278+
this.videoDimensionsController.close();
275279
PlayerFFI.dispose(this.id);
276280
}
277281

@@ -280,4 +284,5 @@ class Player {
280284
late StreamController<PositionState> positionController;
281285
late StreamController<PlaybackState> playbackController;
282286
late StreamController<GeneralState> generalController;
287+
late StreamController<VideoDimensions> videoDimensionsController;
283288
}

ffi/native/callbackmanager.hpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,10 @@ void CallbackInt32(int32_t value) {
115115
}
116116

117117
void CallbackStringArray(int32_t length, char** values) {
118-
auto value_objects = std::unique_ptr<Dart_CObject[]>(new Dart_CObject[length]);
118+
auto value_objects =
119+
std::unique_ptr<Dart_CObject[]>(new Dart_CObject[length]);
119120
auto value_object_refs =
120-
std::unique_ptr<Dart_CObject*[]>(new Dart_CObject*[length]);
121+
std::unique_ptr<Dart_CObject* []>(new Dart_CObject*[length]);
121122

122123
for (int32_t i = 0; i < length; i++) {
123124
Dart_CObject* value_object = &value_objects[i];
@@ -134,9 +135,10 @@ void CallbackStringArray(int32_t length, char** values) {
134135

135136
void CallbackStringArray(const std::vector<std::string>& values) {
136137
auto length = values.size();
137-
auto value_objects = std::unique_ptr<Dart_CObject[]>(new Dart_CObject[length]);
138+
auto value_objects =
139+
std::unique_ptr<Dart_CObject[]>(new Dart_CObject[length]);
138140
auto value_object_refs =
139-
std::unique_ptr<Dart_CObject*[]>(new Dart_CObject*[length]);
141+
std::unique_ptr<Dart_CObject* []>(new Dart_CObject*[length]);
140142

141143
for (int32_t i = 0; i < length; i++) {
142144
Dart_CObject* value_object = &value_objects[i];
@@ -149,7 +151,6 @@ void CallbackStringArray(const std::vector<std::string>& values) {
149151
dart_object.value.as_array.length = length;
150152
dart_object.value.as_array.values = value_object_refs.get();
151153
g_dart_post_C_object(g_callback_port, &dart_object);
152-
153154
}
154155

155156
void CallbackFrame(int32_t id, int32_t length, uint8_t* frame) {

ffi/native/dart_vlc.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ DLLEXPORT void PlayerCreate(int32_t id, int32_t video_width,
4343
for (int32_t index = 0; index < commandLineArgumentsCount; index++)
4444
args.emplace_back(commandLineArguments[index]);
4545
Player* player = g_players->Get(id, args);
46-
player->SetVideoWidth(video_width);
47-
player->SetVideoHeight(video_height);
46+
if (video_width > 0 && video_height > 0) {
47+
player->SetVideoWidth(video_width);
48+
player->SetVideoHeight(video_height);
49+
}
4850
player->OnPlay([=]() -> void { OnPlayPauseStop(id, player->state()); });
4951
player->OnPause([=]() -> void { OnPlayPauseStop(id, player->state()); });
5052
player->OnStop([=]() -> void {
@@ -57,12 +59,16 @@ DLLEXPORT void PlayerCreate(int32_t id, int32_t video_width,
5759
player->OnPosition([=](int32_t) -> void { OnPosition(id, player->state()); });
5860
player->OnOpen([=](VLC::Media) -> void { OnOpen(id, player->state()); });
5961
player->OnPlaylist([=]() -> void { OnOpen(id, player->state()); });
62+
player->OnVideoDimension(
63+
[=](int32_t video_width, int32_t video_height) -> void {
64+
OnVideoDimension(id, video_width, video_height);
65+
});
6066
#ifdef _WIN32
6167
/* Windows: Texture & flutter::TextureRegistrar */
6268
#else
6369
/* Linux: decodeImageFromPixels & NativePorts */
6470
if (player->video_width() > 0 && player->video_height() > 0) {
65-
player->OnVideo([=](uint8_t* frame) -> void {
71+
player->OnVideo([=](uint8_t* frame, int32_t width, int32_t height) -> void {
6672
OnVideo(id, player->video_width() * player->video_height() * 4,
6773
player->state(), frame);
6874
});
@@ -214,7 +220,7 @@ DLLEXPORT char** MediaParse(const char* type, const char* resource,
214220
g_metas_ptr = new char*[media->metas().size()];
215221
g_metas_size = media->metas().size();
216222
int32_t index = 0;
217-
for (const auto& [key, value] : media->metas()) {
223+
for (const auto & [ key, value ] : media->metas()) {
218224
g_metas_ptr[index] = new char[200];
219225
strncpy(g_metas_ptr[index], value.data(), 200);
220226
index++;
@@ -317,7 +323,7 @@ DLLEXPORT char** EqualizerCreateEmpty() {
317323
g_equalizer_ptr[1] = new char[200];
318324
strncpy(g_equalizer_ptr[1], std::to_string(equalizer->pre_amp()).data(), 200);
319325
int32_t index = 0;
320-
for (const auto& [band, amp] : equalizer->band_amps()) {
326+
for (const auto & [ band, amp ] : equalizer->band_amps()) {
321327
g_equalizer_ptr[index + 2] = new char[200];
322328
strncpy(g_equalizer_ptr[index + 2], std::to_string(band).data(), 200);
323329
g_equalizer_ptr[index + 3] = new char[200];
@@ -337,7 +343,7 @@ DLLEXPORT char** EqualizerCreateMode(int32_t mode) {
337343
g_equalizer_ptr[1] = new char[200];
338344
strncpy(g_equalizer_ptr[1], std::to_string(equalizer->pre_amp()).data(), 200);
339345
int32_t index = 0;
340-
for (const auto& [band, amp] : equalizer->band_amps()) {
346+
for (const auto & [ band, amp ] : equalizer->band_amps()) {
341347
g_equalizer_ptr[index + 2] = new char[200];
342348
strncpy(g_equalizer_ptr[index + 2], std::to_string(band).data(), 200);
343349
g_equalizer_ptr[index + 3] = new char[200];

ffi/native/eventmanager.hpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ inline void OnPosition(int32_t id, PlayerState* state) {
3333

3434
inline void OnComplete(int32_t id, PlayerState* state) {
3535
std::vector<std::string> event{
36-
std::to_string(id),
37-
"completeEvent",
36+
std::to_string(id), "completeEvent",
3837
std::to_string(state->is_completed()),
3938
};
4039
CallbackStringArray(event);
@@ -54,20 +53,24 @@ inline void OnRate(int32_t id, PlayerState* state) {
5453

5554
inline void OnOpen(int32_t id, PlayerState* state) {
5655
const auto& media_items = state->medias()->medias();
57-
5856
std::vector<std::string> event;
5957
event.reserve(4 + media_items.size() * 2);
60-
6158
event.emplace_back(std::to_string(id));
6259
event.emplace_back("openEvent");
6360
event.emplace_back(std::to_string(state->index()));
6461
event.emplace_back(std::to_string(state->is_playlist()));
65-
6662
for (const auto& media : media_items) {
6763
event.emplace_back(media->media_type());
6864
event.emplace_back(media->resource());
6965
}
66+
CallbackStringArray(event);
67+
}
7068

69+
inline void OnVideoDimension(int32_t id, int32_t video_width,
70+
int32_t video_height) {
71+
std::vector<std::string> event{std::to_string(id), "videoDimensionEvent",
72+
std::to_string(video_width),
73+
std::to_string(video_height)};
7174
CallbackStringArray(event);
7275
}
7376

lib/dart_vlc.dart

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -32,43 +32,23 @@ final MethodChannel _channel = MethodChannel('dart_vlc');
3232
/// Player player = new Player(id: 0);
3333
/// ```
3434
///
35-
/// If you wish to use this instance for [Video] playback, then provide [videoWidth] & [videoHeight] optional parameters.
36-
/// Higher value may lead to degraded performance.
37-
///
38-
/// ```dart
39-
/// Player player = new Player(
40-
/// id: 0,
41-
/// videoWidth: 1920,
42-
/// videoHeight: 1080,
43-
/// );
44-
/// ```
45-
///
46-
/// Do not provide [videoWidth] & [videoHeight], if you wish to use the [Player] for only audio playback.
47-
///
4835
/// Use various methods & event streams available to control & listen to events of the playback.
4936
///
5037
class Player extends FFI.Player {
5138
final ValueNotifier<int?> textureId = ValueNotifier<int?>(null);
5239

5340
Player(
5441
{required int id,
55-
int videoWidth: 0,
56-
int videoHeight: 0,
42+
FFI.VideoDimensions? videoDimensions,
5743
List<String>? commandlineArguments})
5844
: super(
5945
id: id,
60-
videoWidth: videoWidth,
61-
videoHeight: videoHeight,
46+
videoDimensions: videoDimensions,
6247
commandlineArguments: commandlineArguments) {
63-
if (videoHeight > 0 && videoWidth > 0 && Platform.isWindows) {
64-
() async {
65-
textureId.value = await _channel.invokeMethod('PlayerRegisterTexture', {
66-
'playerId': id,
67-
'videoWidth': videoWidth,
68-
'videoHeight': videoHeight
69-
});
70-
}();
71-
}
48+
() async {
49+
textureId.value = await _channel
50+
.invokeMethod('PlayerRegisterTexture', {'playerId': id});
51+
}();
7252
}
7353

7454
@override
@@ -99,8 +79,8 @@ abstract class DartVLC {
9979
if (!videoStreamControllers[playerId]!.isClosed) {
10080
videoStreamControllers[playerId]!.add(new VideoFrame(
10181
playerId: playerId,
102-
videoWidth: FFI.players[playerId]!.videoWidth,
103-
videoHeight: FFI.players[playerId]!.videoHeight,
82+
videoWidth: FFI.players[playerId]!.videoDimensions.width,
83+
videoHeight: FFI.players[playerId]!.videoDimensions.height,
10484
byteArray: videoFrame));
10585
}
10686
}

windows/dart_vlc.cc

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -111,35 +111,35 @@ void DartVlcPlugin::HandleMethodCall(
111111
// Player::OnVideo callbacks for Texture.
112112

113113
if (methodCall.method_name() == "PlayerRegisterTexture") {
114-
flutter::EncodableMap arguments =
115-
std::get<flutter::EncodableMap>(*methodCall.arguments());
116-
int player_id =
117-
std::get<int>(arguments[flutter::EncodableValue("playerId")]);
118-
119-
auto[it, added] =
120-
outlets.try_emplace(player_id, std::make_pair(0, nullptr));
121-
if (added) {
122-
auto player = g_players->Get(player_id);
123-
auto outlet = std::make_shared<VideoOutlet>(player->video_width(),
124-
player->video_height());
125-
auto texture_id = textureRegistrar->RegisterTexture(outlet->texture());
126-
127-
it->second = std::make_pair(texture_id, std::move(outlet));
128-
// TODO: The weak_ptr might not be needed anymore once callbacks can be
129-
// unregistered.
130-
player->OnVideo(
131-
[ =, weak_outlet = std::weak_ptr<VideoOutlet>(it->second.second) ](
132-
uint8_t * frame)
133-
->void {
134-
if (auto outlet = weak_outlet.lock()) {
135-
outlet->OnFrame(frame);
136-
textureRegistrar->MarkTextureFrameAvailable(texture_id);
137-
}
138-
});
139-
textureRegistrar->MarkTextureFrameAvailable(texture_id);
140-
return result->Success(flutter::EncodableValue(texture_id));
141-
}
142-
result->Error("-1", "Texture was already registered.");
114+
// TODO: Resize frame buffer.
115+
// flutter::EncodableMap arguments =
116+
// std::get<flutter::EncodableMap>(*methodCall.arguments());
117+
// int player_id =
118+
// std::get<int>(arguments[flutter::EncodableValue("playerId")]);
119+
// auto[it, added] =
120+
// outlets.try_emplace(player_id, std::make_pair(0, nullptr));
121+
// if (added) {
122+
// auto player = g_players->Get(player_id);
123+
// auto outlet = std::make_shared<VideoOutlet>(player->video_width(),
124+
// player->video_height());
125+
// auto texture_id = textureRegistrar->RegisterTexture(outlet->texture());
126+
127+
// it->second = std::make_pair(texture_id, std::move(outlet));
128+
// // TODO: The weak_ptr might not be needed anymore once callbacks can be
129+
// // unregistered.
130+
// player->OnVideo(
131+
// [ =, weak_outlet = std::weak_ptr<VideoOutlet>(it->second.second) ](
132+
// uint8_t * frame, int32_t, int32_t)
133+
// ->void {
134+
// if (auto outlet = weak_outlet.lock()) {
135+
// outlet->OnFrame(frame);
136+
// textureRegistrar->MarkTextureFrameAvailable(texture_id);
137+
// }
138+
// });
139+
// textureRegistrar->MarkTextureFrameAvailable(texture_id);
140+
return result->Success(flutter::EncodableValue(0));
141+
// }
142+
// result->Error("-1", "Texture was already registered.");
143143
} else if (methodCall.method_name() == "PlayerUnregisterTexture") {
144144
flutter::EncodableMap arguments =
145145
std::get<flutter::EncodableMap>(*methodCall.arguments());

0 commit comments

Comments
 (0)