[video_player] Add support GstEGLImage to improve playback performance (#67)
Signed-off-by: Makoto Sato <[email protected]>
This commit is contained in:
@@ -6,3 +6,4 @@
|
|||||||
|
|
||||||
Sony Group Corporation
|
Sony Group Corporation
|
||||||
Hidenori Matsubayashi ([email protected])
|
Hidenori Matsubayashi ([email protected])
|
||||||
|
Makoto Sato ([email protected])
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
## 0.9.7
|
||||||
|
* Improve playback performance if GstEGLImage is avalable.
|
||||||
|
|
||||||
## 0.9.6
|
## 0.9.6
|
||||||
* Update for video_player_platform_interface v5.1.1 / video_player v2.4.7 / flutter 3.3.0
|
* Update for video_player_platform_interface v5.1.1 / video_player v2.4.7 / flutter 3.3.0
|
||||||
|
|
||||||
|
|||||||
@@ -44,3 +44,10 @@ playbin uri=<file> video-sink="videoconvert ! video/x-raw,format=RGBA ! fakesink
|
|||||||
|
|
||||||
#### e.g. customization for i.MX 8M platforms:
|
#### e.g. customization for i.MX 8M platforms:
|
||||||
playbin uri=<file> video-sink="imxvideoconvert_g2d ! video/x-raw,format=RGBA ! fakesink"
|
playbin uri=<file> video-sink="imxvideoconvert_g2d ! video/x-raw,format=RGBA ! fakesink"
|
||||||
|
|
||||||
|
### Enable GstEGLImage
|
||||||
|
If GstEGLImage is enabled on your target device, adding the following code to `<user's project>/elinux/CMakeLists.txt` may improve playback performance.
|
||||||
|
```
|
||||||
|
add_definitions(-DUSE_EGL_IMAGE_DMABUF)
|
||||||
|
set(USE_EGL_IMAGE_DMABUF "on")
|
||||||
|
```
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ set(PLUGIN_NAME "video_player_elinux_plugin")
|
|||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
pkg_check_modules(GLIB REQUIRED glib-2.0)
|
pkg_check_modules(GLIB REQUIRED glib-2.0)
|
||||||
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
|
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
|
||||||
|
if(USE_EGL_IMAGE_DMABUF)
|
||||||
|
pkg_check_modules(GSTREAMER_GL REQUIRED gstreamer-gl-1.0)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(${PLUGIN_NAME} SHARED
|
add_library(${PLUGIN_NAME} SHARED
|
||||||
"video_player_elinux_plugin.cc"
|
"video_player_elinux_plugin.cc"
|
||||||
@@ -27,12 +30,24 @@ target_include_directories(${PLUGIN_NAME}
|
|||||||
${GLIB_INCLUDE_DIRS}
|
${GLIB_INCLUDE_DIRS}
|
||||||
${GSTREAMER_INCLUDE_DIRS}
|
${GSTREAMER_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
if(USE_EGL_IMAGE_DMABUF)
|
||||||
|
target_include_directories(${PLUGIN_NAME}
|
||||||
|
PRIVATE
|
||||||
|
${GSTREAMER_GL_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(${PLUGIN_NAME}
|
target_link_libraries(${PLUGIN_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${GLIB_LIBRARIES}
|
${GLIB_LIBRARIES}
|
||||||
${GSTREAMER_LIBRARIES}
|
${GSTREAMER_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
if(USE_EGL_IMAGE_DMABUF)
|
||||||
|
target_link_libraries(${PLUGIN_NAME}
|
||||||
|
PRIVATE
|
||||||
|
${GSTREAMER_GL_LIBRARIES}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
# List of absolute paths to libraries that should be bundled with the plugin
|
# List of absolute paths to libraries that should be bundled with the plugin
|
||||||
set(video_player_elinux_bundled_libraries
|
set(video_player_elinux_bundled_libraries
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ GstVideoPlayer::GstVideoPlayer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
GstVideoPlayer::~GstVideoPlayer() {
|
GstVideoPlayer::~GstVideoPlayer() {
|
||||||
|
#ifdef USE_EGL_IMAGE_DMABUF
|
||||||
|
UnrefEGLImage();
|
||||||
|
#endif // USE_EGL_IMAGE_DMABUF
|
||||||
Stop();
|
Stop();
|
||||||
DestroyPipeline();
|
DestroyPipeline();
|
||||||
}
|
}
|
||||||
@@ -167,6 +170,45 @@ int64_t GstVideoPlayer::GetCurrentPosition() {
|
|||||||
return position / GST_MSECOND;
|
return position / GST_MSECOND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_EGL_IMAGE_DMABUF
|
||||||
|
void* GstVideoPlayer::GetEGLImage(void* egl_display, void* egl_context) {
|
||||||
|
std::shared_lock<std::shared_mutex> lock(mutex_buffer_);
|
||||||
|
if (!gst_.buffer) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstMemory* memory = gst_buffer_peek_memory(gst_.buffer, 0);
|
||||||
|
if (gst_is_dmabuf_memory(memory)) {
|
||||||
|
UnrefEGLImage();
|
||||||
|
|
||||||
|
gint fd = gst_dmabuf_memory_get_fd(memory);
|
||||||
|
gst_gl_display_egl_ =
|
||||||
|
gst_gl_display_egl_new_with_egl_display(reinterpret_cast<gpointer>(egl_display));
|
||||||
|
gst_gl_ctx_ = gst_gl_context_new_wrapped(
|
||||||
|
GST_GL_DISPLAY_CAST(gst_gl_display_egl_), reinterpret_cast<guintptr>(egl_context),
|
||||||
|
GST_GL_PLATFORM_EGL, GST_GL_API_GLES2);
|
||||||
|
|
||||||
|
gst_gl_context_activate(gst_gl_ctx_, TRUE);
|
||||||
|
|
||||||
|
gst_egl_image_ =
|
||||||
|
gst_egl_image_from_dmabuf(gst_gl_ctx_, fd, &gst_video_info_, 0, 0);
|
||||||
|
return reinterpret_cast<void*>(gst_egl_image_get_image(gst_egl_image_));
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GstVideoPlayer::UnrefEGLImage() {
|
||||||
|
if (gst_egl_image_) {
|
||||||
|
gst_egl_image_unref(gst_egl_image_);
|
||||||
|
gst_object_unref(gst_gl_ctx_);
|
||||||
|
gst_object_unref(gst_gl_display_egl_);
|
||||||
|
gst_egl_image_ = NULL;
|
||||||
|
gst_gl_ctx_ = NULL;
|
||||||
|
gst_gl_display_egl_ = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // USE_EGL_IMAGE_DMABUF
|
||||||
|
|
||||||
const uint8_t* GstVideoPlayer::GetFrameBuffer() {
|
const uint8_t* GstVideoPlayer::GetFrameBuffer() {
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_buffer_);
|
std::shared_lock<std::shared_mutex> lock(mutex_buffer_);
|
||||||
if (!gst_.buffer) {
|
if (!gst_.buffer) {
|
||||||
@@ -346,6 +388,14 @@ void GstVideoPlayer::GetVideoSize(int32_t& width, int32_t& height) {
|
|||||||
|
|
||||||
gst_structure_get_int(structure, "width", &width);
|
gst_structure_get_int(structure, "width", &width);
|
||||||
gst_structure_get_int(structure, "height", &height);
|
gst_structure_get_int(structure, "height", &height);
|
||||||
|
|
||||||
|
#ifdef USE_EGL_IMAGE_DMABUF
|
||||||
|
gboolean res = gst_video_info_from_caps(&gst_video_info_, caps);
|
||||||
|
if (!res) {
|
||||||
|
std::cerr << "Failed to get a gst_video_info" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif // USE_EGL_IMAGE_DMABUF
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|||||||
@@ -7,6 +7,13 @@
|
|||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
#ifdef USE_EGL_IMAGE_DMABUF
|
||||||
|
#include <gst/allocators/gstdmabuf.h>
|
||||||
|
#include <gst/gl/egl/egl.h>
|
||||||
|
#include <gst/gl/gl.h>
|
||||||
|
#include <gst/video/video.h>
|
||||||
|
#endif // USE_EGL_IMAGE_DMABUF
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
@@ -33,6 +40,9 @@ class GstVideoPlayer {
|
|||||||
int64_t GetDuration();
|
int64_t GetDuration();
|
||||||
int64_t GetCurrentPosition();
|
int64_t GetCurrentPosition();
|
||||||
const uint8_t* GetFrameBuffer();
|
const uint8_t* GetFrameBuffer();
|
||||||
|
#ifdef USE_EGL_IMAGE_DMABUF
|
||||||
|
void* GetEGLImage(void* egl_display, void* egl_context);
|
||||||
|
#endif // USE_EGL_IMAGE_DMABUF
|
||||||
int32_t GetWidth() const { return width_; };
|
int32_t GetWidth() const { return width_; };
|
||||||
int32_t GetHeight() const { return height_; };
|
int32_t GetHeight() const { return height_; };
|
||||||
|
|
||||||
@@ -56,6 +66,9 @@ class GstVideoPlayer {
|
|||||||
void DestroyPipeline();
|
void DestroyPipeline();
|
||||||
void Preroll();
|
void Preroll();
|
||||||
void GetVideoSize(int32_t& width, int32_t& height);
|
void GetVideoSize(int32_t& width, int32_t& height);
|
||||||
|
#ifdef USE_EGL_IMAGE_DMABUF
|
||||||
|
void UnrefEGLImage();
|
||||||
|
#endif // USE_EGL_IMAGE_DMABUF
|
||||||
|
|
||||||
GstVideoElements gst_;
|
GstVideoElements gst_;
|
||||||
std::string uri_;
|
std::string uri_;
|
||||||
@@ -70,6 +83,13 @@ class GstVideoPlayer {
|
|||||||
std::mutex mutex_event_completed_;
|
std::mutex mutex_event_completed_;
|
||||||
std::shared_mutex mutex_buffer_;
|
std::shared_mutex mutex_buffer_;
|
||||||
std::unique_ptr<VideoPlayerStreamHandler> stream_handler_;
|
std::unique_ptr<VideoPlayerStreamHandler> stream_handler_;
|
||||||
|
|
||||||
|
#ifdef USE_EGL_IMAGE_DMABUF
|
||||||
|
GstVideoInfo gst_video_info_;
|
||||||
|
GstEGLImage* gst_egl_image_ = NULL;
|
||||||
|
GstGLContext* gst_gl_ctx_ = NULL;
|
||||||
|
GstGLDisplayEGL* gst_gl_display_egl_ = NULL;
|
||||||
|
#endif // USE_EGL_IMAGE_DMABUF
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PACKAGES_VIDEO_PLAYER_VIDEO_PLAYER_ELINUX_GST_VIDEO_PLAYER_H_
|
#endif // PACKAGES_VIDEO_PLAYER_VIDEO_PLAYER_ELINUX_GST_VIDEO_PLAYER_H_
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ class VideoPlayerPlugin : public flutter::Plugin {
|
|||||||
std::unique_ptr<GstVideoPlayer> player;
|
std::unique_ptr<GstVideoPlayer> player;
|
||||||
std::unique_ptr<flutter::TextureVariant> texture;
|
std::unique_ptr<flutter::TextureVariant> texture;
|
||||||
std::unique_ptr<FlutterDesktopPixelBuffer> buffer;
|
std::unique_ptr<FlutterDesktopPixelBuffer> buffer;
|
||||||
|
#ifdef USE_EGL_IMAGE_DMABUF
|
||||||
|
std::unique_ptr<FlutterDesktopEGLImage> egl_image;
|
||||||
|
#endif // USE_EGL_IMAGE_DMABUF
|
||||||
std::unique_ptr<flutter::EventChannel<flutter::EncodableValue>>
|
std::unique_ptr<flutter::EventChannel<flutter::EncodableValue>>
|
||||||
event_channel;
|
event_channel;
|
||||||
std::unique_ptr<flutter::EventSink<flutter::EncodableValue>> event_sink;
|
std::unique_ptr<flutter::EventSink<flutter::EncodableValue>> event_sink;
|
||||||
@@ -293,6 +296,20 @@ void VideoPlayerPlugin::HandleCreateMethodCall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto instance = std::make_unique<FlutterVideoPlayer>();
|
auto instance = std::make_unique<FlutterVideoPlayer>();
|
||||||
|
#ifdef USE_EGL_IMAGE_DMABUF
|
||||||
|
instance->egl_image = std::make_unique<FlutterDesktopEGLImage>();
|
||||||
|
instance->texture =
|
||||||
|
std::make_unique<flutter::TextureVariant>(flutter::EGLImageTexture(
|
||||||
|
[instance = instance.get()](
|
||||||
|
size_t width, size_t height, void* egl_display,
|
||||||
|
void* egl_context) -> const FlutterDesktopEGLImage* {
|
||||||
|
instance->egl_image->width = instance->player->GetWidth();
|
||||||
|
instance->egl_image->height = instance->player->GetHeight();
|
||||||
|
instance->egl_image->egl_image =
|
||||||
|
instance->player->GetEGLImage(egl_display, egl_context);
|
||||||
|
return instance->egl_image.get();
|
||||||
|
}));
|
||||||
|
#else
|
||||||
instance->buffer = std::make_unique<FlutterDesktopPixelBuffer>();
|
instance->buffer = std::make_unique<FlutterDesktopPixelBuffer>();
|
||||||
instance->texture =
|
instance->texture =
|
||||||
std::make_unique<flutter::TextureVariant>(flutter::PixelBufferTexture(
|
std::make_unique<flutter::TextureVariant>(flutter::PixelBufferTexture(
|
||||||
@@ -303,6 +320,7 @@ void VideoPlayerPlugin::HandleCreateMethodCall(
|
|||||||
instance->buffer->buffer = instance->player->GetFrameBuffer();
|
instance->buffer->buffer = instance->player->GetFrameBuffer();
|
||||||
return instance->buffer.get();
|
return instance->buffer.get();
|
||||||
}));
|
}));
|
||||||
|
#endif // USE_EGL_IMAGE_DMABUF
|
||||||
const auto texture_id =
|
const auto texture_id =
|
||||||
texture_registrar_->RegisterTexture(instance->texture.get());
|
texture_registrar_->RegisterTexture(instance->texture.get());
|
||||||
instance->texture_id = texture_id;
|
instance->texture_id = texture_id;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: video_player_elinux
|
name: video_player_elinux
|
||||||
description: Flutter plugin for displaying inline video with other Flutter widgets on Embedded Linux.
|
description: Flutter plugin for displaying inline video with other Flutter widgets on Embedded Linux.
|
||||||
version: 0.9.6
|
version: 0.9.7
|
||||||
homepage: https://github.com/sony/flutter-elinux-plugins
|
homepage: https://github.com/sony/flutter-elinux-plugins
|
||||||
repository: https://github.com/sony/flutter-elinux-plugins/tree/main/packages/video_player
|
repository: https://github.com/sony/flutter-elinux-plugins/tree/main/packages/video_player
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user