Skip to content

Commit

Permalink
Merge pull request #96 from alexmercerind/windows-texture-migration
Browse files Browse the repository at this point in the history
Using flutter::TextureRegistrar for Video on Windows.
  • Loading branch information
alexmercerind authored Aug 10, 2021
2 parents cfc8f0d + 5ae9dc2 commit dae0f19
Show file tree
Hide file tree
Showing 22 changed files with 363 additions and 183 deletions.
1 change: 0 additions & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
ko_fi: 'alexmercerind'
custom: ['https://www.buymeacoffee.com/alexmercerind']
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 0.1.2

- Now using `flutter::TextureRegistrar` for performant `Video` on Windows. (#54).
- Fixed `autoStart` in `Player.open`.
- Fixed other crashes for Windows.
- Improved stability.

## 0.1.1

- Fixed setState being called after dispose (#75) (Finally)
Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,16 +320,16 @@ sudo dnf install vlc-devel

You can see an example project [here](https://github.com/alexmercerind/dart_vlc/blob/master/example/lib/main.dart).

Windows

![](https://github.com/alexmercerind/dart_vlc/blob/assets/dart_vlc_6.png?raw=true)

dart_vlc running on Ubuntu Linux.

## Workings

The repository contains a [C++ wrapper](https://github.com/alexmercerind/dart_vlc/tree/master/dartvlc) based on libVLC++. This makes handling of events and controls a lot easier & has additional features in it.
I preferred to do majority of handling in C++ itself, thus Dart code is minimal & very slight mapping to it.

This project might seem like a Flutter plugin, but it is based on FFI instead. [Here](https://github.com/alexmercerind/dart_vlc/tree/master/ffi) are the FFI bindings to [C++ wrapper](https://github.com/alexmercerind/dart_vlc/tree/master/dartvlc), which are shared by all platforms & same can be used in Dart CLI apps aswell.
This project might seem like a Flutter plugin, but it is based on FFI instead. [Here](https://github.com/alexmercerind/dart_vlc/tree/master/ffi) are the FFI bindings to [C++ wrapper](https://github.com/alexmercerind/dart_vlc/tree/master/dartvlc), which are shared by all platforms & same can be used in Dart CLI apps aswell. Platform channel interface is only used for [flutter]

## Progress

Expand Down Expand Up @@ -379,6 +379,8 @@ Done
Under progress or planned features (irrespective of order)...

- Removing [libVLC++](https://github.com/videolan/libvlcpp) dependency. (Maybe).
- Subtitle control.
- Audio track control.
- Writing metadata tags.
- Making things more efficient.
- Supporting native volume control/lock screen notifications (Maybe).
Expand All @@ -389,9 +391,9 @@ Under progress or planned features (irrespective of order)...

First of all, thanks to the [VideoLAN](https://www.videolan.org) team for creating [libVLC](https://github.com/videolan/vlc) & [libVLC++](https://github.com/videolan/libvlcpp). Really great guys really great at their work.

Massive thanks to [@stuartmorgan](https://github.com/stuartmorgan) from [Flutter](https://flutter.dev) team to my review code & help me fix the loopholes.
[@jnschulze](https://github.com/jnschulze) for his awesome contributions to Flutter engine like adding texture support.

Thanks to following members of libVLC community to give me bit of look & advice about how things work:
Thanks to following members of libVLC community (irrespective of the order) to give me bit of look & advice about how things work:

- [@jeremyVignelles](https://github.com/jeremyVignelles)
- [@chouquette](https://github.com/chouquette)
Expand Down
4 changes: 2 additions & 2 deletions dartvlc/internal/events.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class PlayerEvents : public PlayerGetters {
);
this->mediaPlayer.setVideoFormatCallbacks(
[=](char* chroma, uint32_t* w, uint32_t* h, uint32_t* p, uint32_t* l) -> int {
strcpy(chroma, "RV32");
strcpy(chroma, "RGBA");
*w = this->videoWidth;
*h = this->videoHeight;
*p = pitch;
Expand All @@ -95,7 +95,7 @@ class PlayerEvents : public PlayerGetters {
},
nullptr
);
this->mediaPlayer.setVideoFormat("RV32", this->videoWidth, this->videoHeight, pitch);
this->mediaPlayer.setVideoFormat("RGBA", this->videoWidth, this->videoHeight, pitch);
}

protected:
Expand Down
21 changes: 17 additions & 4 deletions dartvlc/internal/setters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ class PlayerSetters: public PlayerEvents {
public:
void open(MediaSource* mediaSource, bool autoStart = true) {
/* Freed the previous `Media` objects when a new `Playlist` or `Media` is opened. */
this->state->isStarted = false;
this->stop();
for (Media* media: this->state->medias->medias) {
delete media;
}
this->stop();
this->state->medias->medias = {};
this->mediaList = VLC::MediaList(this->instance);
if (mediaSource->mediaSourceType() == "MediaSourceType.media") {
Expand All @@ -46,14 +47,20 @@ class PlayerSetters: public PlayerEvents {
this->state->isPlaylist = true;
}
this->_onOpenCallback(this->mediaList.itemAtIndex(0));
this->mediaListPlayer.playItemAtIndex(0);
this->state->index = 0;
this->state->isPlaying = this->mediaListPlayer.isPlaying();
this->state->isValid = this->mediaListPlayer.isValid();
if (autoStart) this->play();
}

void play() {
this->mediaListPlayer.play();
if (!this->state->isStarted) {
this->mediaListPlayer.playItemAtIndex(0);
this->state->isStarted = true;
}
else {
this->mediaListPlayer.play();
}
}

void pause() {
Expand All @@ -63,7 +70,13 @@ class PlayerSetters: public PlayerEvents {
}

void playOrPause() {
this->mediaListPlayer.pause();
if (!this->state->isStarted) {
this->mediaListPlayer.playItemAtIndex(0);
this->state->isStarted = true;
}
else {
this->mediaListPlayer.pause();
}
}

void stop() {
Expand Down
2 changes: 2 additions & 0 deletions dartvlc/internal/state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class PlayerState {
float rate = 1.0;
bool isPlaylist = false;
Device* device = nullptr;
/* NOTE: Used for autoStart. */
bool isStarted = false;
/* TODO: Not used yet.
Equalizer* equalizer = nullptr;
*/
Expand Down
2 changes: 1 addition & 1 deletion dartvlc/player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ class Player: public PlayerSetters {
this->mediaPlayer.stop();
delete this->state;
delete this->_videoFrameBuffer;
for (size_t i = 0; i < argsSize; i++) delete this->args[i];
delete[] this->args;
}

Expand All @@ -81,6 +80,7 @@ class Players {

void dispose(int id, std::function<void()> callback = []() -> void {}) {
delete this->players[id];
this->players.erase(id);
callback();
}

Expand Down
4 changes: 4 additions & 0 deletions ffi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.1.1

- Removed `Player::onVideo` callbacks for win32.

## 0.1.0

- Added new native methods for handling with memory leaks.
Expand Down
2 changes: 1 addition & 1 deletion ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<h5 align="center">Written in C++ using libVLC & libVLC++.</h5>


FFI bindings & NativePort event callback handling for `dart_vlc.so`.
FFI bindings & NativePort event callback handling for `dart_vlc.dll`.

Dependency package for [dart_vlc](https:///github.com/alexmercerind/dart_vlc).

Expand Down
2 changes: 1 addition & 1 deletion ffi/lib/src/player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Map<int, Player> players = {};
///
class Player {
/// Id associated with the [Player] instance.
final int id;
int id;

/// Width of the [Video] frames to be extracted. Higher value may lead to degraded performance.
late int videoWidth;
Expand Down
10 changes: 5 additions & 5 deletions ffi/native/callbackmanager.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#ifndef EXPORT
#ifdef __WIN32
#define EXPORT declspec(__dllexport)
#ifdef _WIN32
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
Expand Down Expand Up @@ -109,14 +109,14 @@ EXPORT void RegisterDart_CallbackPort(Dart_Port _callbackPort) {
callbackPort = _callbackPort;
}

EXPORT void callbackInt32(int32_t value) {
void callbackInt32(int32_t value) {
Dart_CObject dart_object;
dart_object.type = Dart_CObject_kInt32;
dart_object.value.as_int32 = value;
dartPostCObject(callbackPort, &dart_object);
}

EXPORT void callbackStringArray(int length, char** values) {
void callbackStringArray(int length, char** values) {
Dart_CObject** valueObjects = new Dart_CObject*[length];
for (int i = 0; i < length; i++) {
Dart_CObject* valueObject = new Dart_CObject;
Expand All @@ -135,7 +135,7 @@ EXPORT void callbackStringArray(int length, char** values) {
delete[] valueObjects;
}

EXPORT void callbackFrame(int length, int playerId, uint8_t* frame) {
void callbackFrame(int length, int playerId, uint8_t* frame) {
Dart_CObject idObject;
idObject.type = Dart_CObject_kInt32;
idObject.value.as_int32 = playerId;
Expand Down
5 changes: 5 additions & 0 deletions ffi/native/dart_vlc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,16 @@ EXPORT void Player_create(int id, int videoWidth, int videoHeight, int commandLi
player->onPlaylist([=]() -> void {
Player_onOpen(player->state);
});
#ifdef _WIN32
/* Using Texture & flutter::TextureRegistrar for Windows. */
#else
/* Using decodeImageFromPixels & NativePorts for Linux. */
if (player->videoHeight > 0 && player->videoWidth > 0) {
player->onVideo([=](uint8_t* frame) -> void {
Player_onVideo(player->videoHeight * player->videoWidth * 4, player->state, frame);
});
}
#endif
}

EXPORT void Player_dispose(int id) {
Expand Down
38 changes: 19 additions & 19 deletions ffi/native/eventmanager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,95 +15,95 @@
extern "C" {
#endif

void Player_onPlayPauseStop(PlayerState* state) {
inline void Player_onPlayPauseStop(PlayerState* state) {
std::vector<std::string> event;
event.emplace_back(std::to_string(state->id));
event.emplace_back("playbackEvent");
event.emplace_back(std::to_string(state->isPlaying));
event.emplace_back(std::to_string(state->isSeekable));
int _size = event.size();
size_t _size = event.size();
char** _event = new char*[_size];
for (int index = 0; index < _size; index++)
_event[index] = const_cast<char*>(event[index].c_str());
callbackStringArray(
_size,
static_cast<int>(_size),
_event
);

delete[] _event;
}

void Player_onPosition(PlayerState* state) {
inline void Player_onPosition(PlayerState* state) {
std::vector<std::string> event;
event.emplace_back(std::to_string(state->id));
event.emplace_back("positionEvent");
event.emplace_back(std::to_string(state->index));
event.emplace_back(std::to_string(state->position));
event.emplace_back(std::to_string(state->duration));
int _size = event.size();
size_t _size = event.size();
char** _event = new char*[_size];
for (int index = 0; index < _size; index++)
_event[index] = const_cast<char*>(event[index].c_str());
callbackStringArray(
_size,
static_cast<int>(_size),
_event
);

delete[] _event;
}

void Player_onComplete(PlayerState* state) {
inline void Player_onComplete(PlayerState* state) {
std::vector<std::string> event;
event.emplace_back(std::to_string(state->id));
event.emplace_back("completeEvent");
event.emplace_back(std::to_string(state->isCompleted));
int _size = event.size();
size_t _size = event.size();
char** _event = new char*[_size];
for (int index = 0; index < _size; index++)
_event[index] = const_cast<char*>(event[index].c_str());
callbackStringArray(
_size,
static_cast<int>(_size),
_event
);

delete[] _event;
}

void Player_onVolume(PlayerState* state) {
inline void Player_onVolume(PlayerState* state) {
std::vector<std::string> event;
event.emplace_back(std::to_string(state->id));
event.emplace_back("volumeEvent");
event.emplace_back(std::to_string(state->volume));
int _size = event.size();
size_t _size = event.size();
char** _event = new char*[_size];
for (int index = 0; index < _size; index++)
_event[index] = const_cast<char*>(event[index].c_str());
callbackStringArray(
_size,
static_cast<int>(_size),
_event
);

delete[] _event;
}

void Player_onRate(PlayerState* state) {
inline void Player_onRate(PlayerState* state) {
std::vector<std::string> event;
event.emplace_back(std::to_string(state->id));
event.emplace_back("rateEvent");
event.emplace_back(std::to_string(state->rate));
int _size = event.size();
size_t _size = event.size();
char** _event = new char*[_size];
for (int index = 0; index < _size; index++)
_event[index] = const_cast<char*>(event[index].c_str());
callbackStringArray(
_size,
static_cast<int>(_size),
_event
);

delete[] _event;
}

void Player_onOpen(PlayerState* state) {
inline void Player_onOpen(PlayerState* state) {
std::vector<std::string> event;
event.emplace_back(std::to_string(state->id));
event.emplace_back("openEvent");
Expand All @@ -113,19 +113,19 @@ void Player_onOpen(PlayerState* state) {
event.emplace_back(media->mediaType);
event.emplace_back(media->resource);
}
int _size = event.size();
size_t _size = event.size();
char** _event = new char*[_size];
for (int index = 0; index < _size; index++)
_event[index] = const_cast<char*>(event[index].c_str());
callbackStringArray(
_size,
static_cast<int>(_size),
_event
);

delete[] _event;
}

void Player_onVideo(int size, PlayerState* state, uint8_t* frame) {
inline void Player_onVideo(int size, PlayerState* state, uint8_t* frame) {
callbackFrame(
size,
state->id,
Expand Down
2 changes: 1 addition & 1 deletion ffi/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: dart_vlc_ffi
description: FFI based binding to dart_vlc wrapper (Based on libVLC & libVLC++).
version: 0.1.0
version: 0.1.1
homepage: https://github.com/alexmercerind/dart_vlc
repository: https://github.com/alexmercerind/dart_vlc
documentation: https://github.com/alexmercerind/dart_vlc/blob/master/README.md
Expand Down
Loading

0 comments on commit dae0f19

Please sign in to comment.