Compare commits

...

17 Commits

Author SHA1 Message Date
Vitaliy Zarubin ec4b86573c [texture] Add OrientationChanged event and method 1 year ago
Vitaliy Zarubin 32a481b213 Merge branch 'flutter-aurora-current' into embedder_texture 1 year ago
Vitaliy Zarubin 4db615def4 [texture] Add camera width and height 1 year ago
Vitaliy Zarubin 0ccba5006e [texture] Add camera and helpers 1 year ago
Vitaliy Zarubin c4556091dc [texture] Add CameraPixelBuffer class 1 year ago
Vitaliy Zarubin 4d898d36a5 [texture] Texture with pixel buffer stream camera 1 year ago
Vitaliy Zarubin e6e3352e7f [texture] Add stream camera 1 year ago
Vitaliy Zarubin f79d080cf3 [texture] Add start interface register 1 year ago
Vitaliy Zarubin 96795f33f0 [example] Clear aurora plugin 1 year ago
Vitaliy Zarubin 1761211ba1 [example] Update linux texture 1 year ago
Vitaliy Zarubin 4e6ff5e419 [example] Update TextureRegister 1 year ago
Vitaliy Zarubin edfa81bca0 [example] Get texture ID 1 year ago
Vitaliy Zarubin 013245d9bb [plugin] Add embedder_texture glesv2 1 year ago
Vitaliy Zarubin fed1031ab4 [plugin] Add embedder_texture plugin for aurora 1 year ago
Vitaliy Zarubin 80e1758cc8 [plugin] Add embedder_texture plugin for linux 1 year ago
Vitaliy Zarubin 3413ecd9a3 [example] Add catch sqflite 1 year ago
Vitaliy Zarubin 4b7268cee0 [example] Add linux 1 year ago
  1. 2
      example/aurora/desktop/ru.auroraos.flutter_example_packages.desktop
  2. 1
      example/aurora/rpm/ru.auroraos.flutter_example_packages.spec
  3. 22
      example/lib/packages/embedder_texture/model.dart
  4. 25
      example/lib/packages/embedder_texture/package.dart
  5. 53
      example/lib/packages/embedder_texture/page.dart
  6. 2
      example/lib/packages/packages.dart
  7. 37
      example/lib/packages/sqflite/model.dart
  8. 1
      example/linux/.gitignore
  9. 139
      example/linux/CMakeLists.txt
  10. 88
      example/linux/flutter/CMakeLists.txt
  11. 19
      example/linux/flutter/generated_plugin_registrant.cc
  12. 15
      example/linux/flutter/generated_plugin_registrant.h
  13. 25
      example/linux/flutter/generated_plugins.cmake
  14. 6
      example/linux/main.cc
  15. 104
      example/linux/my_application.cc
  16. 18
      example/linux/my_application.h
  17. 4
      example/pubspec.yaml
  18. 30
      packages/embedder_texture/.gitignore
  19. 1
      packages/embedder_texture/analysis_options.yaml
  20. 36
      packages/embedder_texture/aurora/CMakeLists.txt
  21. 114
      packages/embedder_texture/aurora/camera.cpp
  22. 42
      packages/embedder_texture/aurora/camera_egl_helper.cpp
  23. 106
      packages/embedder_texture/aurora/camera_helper.cpp
  24. 77
      packages/embedder_texture/aurora/camera_pixels_helper.cpp
  25. 87
      packages/embedder_texture/aurora/embedder_texture_plugin.cpp
  26. 47
      packages/embedder_texture/aurora/include/embedder_texture/camera.h
  27. 21
      packages/embedder_texture/aurora/include/embedder_texture/camera_egl_helper.h
  28. 33
      packages/embedder_texture/aurora/include/embedder_texture/camera_pixels_helper.h
  29. 35
      packages/embedder_texture/aurora/include/embedder_texture/embedder_texture_plugin.h
  30. 162
      packages/embedder_texture/lib/embedder_texture.dart
  31. 54
      packages/embedder_texture/lib/embedder_texture_method_channel.dart
  32. 38
      packages/embedder_texture/lib/embedder_texture_platform_interface.dart
  33. 24
      packages/embedder_texture/linux/CMakeLists.txt
  34. 173
      packages/embedder_texture/linux/embedder_texture_plugin.cc
  35. 7
      packages/embedder_texture/linux/embedder_texture_plugin_private.h
  36. 44
      packages/embedder_texture/linux/fl_my_texture_gl.cc
  37. 26
      packages/embedder_texture/linux/include/embedder_texture/embedder_texture_plugin.h
  38. 28
      packages/embedder_texture/linux/include/fl_my_texture_gl.h
  39. 25
      packages/embedder_texture/pubspec.yaml

2
example/aurora/desktop/ru.auroraos.flutter_example_packages.desktop

@ -7,6 +7,6 @@ Exec=/usr/bin/ru.auroraos.flutter_example_packages
X-Nemo-Application-Type=silica-qt5
[X-Application]
Permissions=DeviceInfo;UserDirs;Sensors
Permissions=DeviceInfo;UserDirs;Sensors;Camera
OrganizationName=ru.auroraos
ApplicationName=flutter_example_packages

1
example/aurora/rpm/ru.auroraos.flutter_example_packages.spec

@ -12,6 +12,7 @@ BuildRequires: cmake
BuildRequires: pkgconfig(sqlite3)
BuildRequires: pkgconfig(flutter-embedder)
BuildRequires: pkgconfig(sensord-qt5)
BuildRequires: pkgconfig(streamcamera)
%description
%{summary}.

22
example/lib/packages/embedder_texture/model.dart

@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/widgets.dart';
import 'package:scoped_model/scoped_model.dart';
import 'package:xdga_directories/xdga_directories.dart' as xdga;
/// Model for [EmbedderTexturePage]
class EmbedderTextureModel extends Model {
/// Get [ScopedModel]
static EmbedderTextureModel of(BuildContext context) =>
ScopedModel.of<EmbedderTextureModel>(context);
/// Error
String? _error;
/// Public error
String? get error => _error;
/// Public is error
bool get isError => _error != null;
}

25
example/lib/packages/embedder_texture/package.dart

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter_example_packages/base/package/package_page.dart';
import 'package:flutter_example_packages/packages/embedder_texture/page.dart';
import 'package:get_it/get_it.dart';
import 'model.dart';
/// Package values
final packageEmbedderTexture = PackagePage(
key: 'Embedder Texture',
descEN: '''
Test Embedder texture plugin
''',
descRU: '''
Тестирование текстур Embedder
''',
version: '0.0.1',
isPlatformDependent: true,
page: () => EmbedderTexturePage(),
init: () {
GetIt.instance
.registerFactory<EmbedderTextureModel>(() => EmbedderTextureModel());
},
);

53
example/lib/packages/embedder_texture/page.dart

@ -0,0 +1,53 @@
// SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import 'package:flutter_example_packages/base/di/app_di.dart';
import 'package:flutter_example_packages/base/package/package.dart';
import 'package:flutter_example_packages/packages/embedder_texture/model.dart';
import 'package:flutter_example_packages/packages/embedder_texture/package.dart';
import 'package:flutter_example_packages/widgets/base/export.dart';
import 'package:flutter_example_packages/widgets/blocks/block_alert.dart';
import 'package:flutter_example_packages/widgets/blocks/block_info_package.dart';
import 'package:flutter_example_packages/widgets/blocks/block_item.dart';
import 'package:flutter_example_packages/widgets/layouts/block_layout.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:embedder_texture/embedder_texture.dart';
class EmbedderTexturePage extends AppStatefulWidget {
EmbedderTexturePage({
super.key,
});
final Package package = packageEmbedderTexture;
@override
State<EmbedderTexturePage> createState() => _EmbedderTexturePageState();
}
class _EmbedderTexturePageState extends AppState<EmbedderTexturePage> {
@override
Widget buildWide(
BuildContext context,
MediaQueryData media,
AppLocalizations l10n,
) {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
return BlockLayout<EmbedderTextureModel>(
model: getIt<EmbedderTextureModel>(),
title: widget.package.key,
builder: (context, child, model) {
return Padding(
padding: const EdgeInsets.all(20),
child: Center(
child: EmbedderTexture(
width: width,
height: height,
),
),
);
},
);
}
}

2
example/lib/packages/packages.dart

@ -35,9 +35,11 @@ import 'package:flutter_example_packages/packages/sqflite/package.dart';
import 'package:flutter_example_packages/packages/universal_io/package.dart';
import 'package:flutter_example_packages/packages/wakelock_plus/package.dart';
import 'package:flutter_example_packages/packages/xdga_directories/package.dart';
import 'package:flutter_example_packages/packages/embedder_texture/package.dart';
/// List app packages
final packages = <Package>[
packageEmbedderTexture,
packageBatteryPlus,
packageBuildRunner,
packageCachedNetworkImage,

37
example/lib/packages/sqflite/model.dart

@ -31,26 +31,31 @@ class SqfliteModel extends Model {
/// Init database
Future<void> init() async {
// Get a location using getDatabasesPath
var databasesPath = await getDatabasesPath();
String path = p.join(databasesPath, 'demo.db');
// Delete the database
await deleteDatabase(path);
// open the database
_db = await openDatabase(
path,
version: 1,
onCreate: (Database db, int version) async {
// When creating the db, create the table
await db.execute('''CREATE TABLE Test (
try {
// Get a location using getDatabasesPath
var databasesPath = await getDatabasesPath();
String path = p.join(databasesPath, 'demo.db');
// Delete the database
await deleteDatabase(path);
// open the database
_db = await openDatabase(
path,
version: 1,
onCreate: (Database db, int version) async {
// When creating the db, create the table
await db.execute('''CREATE TABLE Test (
name TEXT,
value INTEGER,
num REAL
)''');
},
);
},
);
} catch (e) {
_error = e.toString();
}
notifyListeners();
}
/// Close database

1
example/linux/.gitignore vendored

@ -0,0 +1 @@
flutter/ephemeral

139
example/linux/CMakeLists.txt

@ -0,0 +1,139 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "flutter_example_packages")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "ru.auroraos.flutter_example_packages")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(SET CMP0063 NEW)
# Load bundled libraries from the lib/ directory relative to the binary.
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()
# Define build configuration options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14)
# target_compile_options(${TARGET} PRIVATE -Wall -Werror)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()
# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
# Define the application target. To change its name, change BINARY_NAME above,
# not the value here, or `flutter run` will no longer work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME}
"main.cc"
"my_application.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)
# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})
# Add dependency libraries. Add any application-specific dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)
# Only the install-generated bundle's copy of the executable will launch
# correctly, since the resources must in the right relative locations. To avoid
# people trying to run the unbundled copy, put it in a subdirectory instead of
# the default top-level location.
set_target_properties(${BINARY_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
)
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# By default, "installing" just makes a relocatable bundle in the build
# directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
# Start with a clean build bundle directory every time.
install(CODE "
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
" COMPONENT Runtime)
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
install(FILES "${bundled_library}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endforeach(bundled_library)
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()

88
example/linux/flutter/CMakeLists.txt

@ -0,0 +1,88 @@
# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.10)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
# which isn't available in 3.10.
function(list_prepend LIST_NAME PREFIX)
set(NEW_LIST "")
foreach(element ${${LIST_NAME}})
list(APPEND NEW_LIST "${PREFIX}${element}")
endforeach(element)
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
endfunction()
# === Flutter Library ===
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"fl_basic_message_channel.h"
"fl_binary_codec.h"
"fl_binary_messenger.h"
"fl_dart_project.h"
"fl_engine.h"
"fl_json_message_codec.h"
"fl_json_method_codec.h"
"fl_message_codec.h"
"fl_method_call.h"
"fl_method_channel.h"
"fl_method_codec.h"
"fl_method_response.h"
"fl_plugin_registrar.h"
"fl_plugin_registry.h"
"fl_standard_message_codec.h"
"fl_standard_method_codec.h"
"fl_string_codec.h"
"fl_value.h"
"fl_view.h"
"flutter_linux.h"
)
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
target_link_libraries(flutter INTERFACE
PkgConfig::GTK
PkgConfig::GLIB
PkgConfig::GIO
)
add_dependencies(flutter flutter_assemble)
# === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the
# flutter tool.
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/_phony_
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
)

19
example/linux/flutter/generated_plugin_registrant.cc

@ -0,0 +1,19 @@
//
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
#include <embedder_texture/embedder_texture_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) embedder_texture_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "EmbedderTexturePlugin");
embedder_texture_plugin_register_with_registrar(embedder_texture_registrar);
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
}

15
example/linux/flutter/generated_plugin_registrant.h

@ -0,0 +1,15 @@
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter_linux/flutter_linux.h>
// Registers Flutter plugins.
void fl_register_plugins(FlPluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_

25
example/linux/flutter/generated_plugins.cmake

@ -0,0 +1,25 @@
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
embedder_texture
flutter_secure_storage_linux
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)

6
example/linux/main.cc

@ -0,0 +1,6 @@
#include "my_application.h"
int main(int argc, char** argv) {
g_autoptr(MyApplication) app = my_application_new();
return g_application_run(G_APPLICATION(app), argc, argv);
}

104
example/linux/my_application.cc

@ -0,0 +1,104 @@
#include "my_application.h"
#include <flutter_linux/flutter_linux.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
#include "flutter/generated_plugin_registrant.h"
struct _MyApplication {
GtkApplication parent_instance;
char** dart_entrypoint_arguments;
};
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
// Implements GApplication::activate.
static void my_application_activate(GApplication* application) {
MyApplication* self = MY_APPLICATION(application);
GtkWindow* window =
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
// Use a header bar when running in GNOME as this is the common style used
// by applications and is the setup most users will be using (e.g. Ubuntu
// desktop).
// If running on X and not using GNOME then just use a traditional title bar
// in case the window manager does more exotic layout, e.g. tiling.
// If running on Wayland assume the header bar will work (may need changing
// if future cases occur).
gboolean use_header_bar = TRUE;
#ifdef GDK_WINDOWING_X11
GdkScreen* screen = gtk_window_get_screen(window);
if (GDK_IS_X11_SCREEN(screen)) {
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
use_header_bar = FALSE;
}
}
#endif
if (use_header_bar) {
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "flutter_example_packages");
gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
} else {
gtk_window_set_title(window, "flutter_example_packages");
}
gtk_window_set_default_size(window, 1280, 720);
gtk_widget_show(GTK_WIDGET(window));
g_autoptr(FlDartProject) project = fl_dart_project_new();
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
FlView* view = fl_view_new(project);
gtk_widget_show(GTK_WIDGET(view));
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
gtk_widget_grab_focus(GTK_WIDGET(view));
}
// Implements GApplication::local_command_line.
static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
MyApplication* self = MY_APPLICATION(application);
// Strip out the first argument as it is the binary name.
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
g_autoptr(GError) error = nullptr;
if (!g_application_register(application, nullptr, &error)) {
g_warning("Failed to register: %s", error->message);
*exit_status = 1;
return TRUE;
}
g_application_activate(application);
*exit_status = 0;
return TRUE;
}
// Implements GObject::dispose.
static void my_application_dispose(GObject* object) {
MyApplication* self = MY_APPLICATION(object);
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
}
static void my_application_class_init(MyApplicationClass* klass) {
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
}
static void my_application_init(MyApplication* self) {}
MyApplication* my_application_new() {
return MY_APPLICATION(g_object_new(my_application_get_type(),
"application-id", APPLICATION_ID,
"flags", G_APPLICATION_NON_UNIQUE,
nullptr));
}

18
example/linux/my_application.h

@ -0,0 +1,18 @@
#ifndef FLUTTER_MY_APPLICATION_H_
#define FLUTTER_MY_APPLICATION_H_
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
GtkApplication)
/**
* my_application_new:
*
* Creates a new Flutter-based application.
*
* Returns: a new #MyApplication.
*/
MyApplication* my_application_new();
#endif // FLUTTER_MY_APPLICATION_H_

4
example/pubspec.yaml

@ -173,6 +173,10 @@ dependencies:
# ref: master
# path: packages/sensors_plus/sensors_plus_aurora
## Test embedder texture plugin
embedder_texture:
path: ../packages/embedder_texture
dev_dependencies:
flutter_test:
sdk:

30
packages/embedder_texture/.gitignore vendored

@ -0,0 +1,30 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/

1
packages/embedder_texture/analysis_options.yaml

@ -0,0 +1 @@
include: package:flutter_lints/flutter.yaml

36
packages/embedder_texture/aurora/CMakeLists.txt

@ -0,0 +1,36 @@
# SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.10)
set(PROJECT_NAME embedder_texture)
set(PLUGIN_NAME embedder_texture_platform_plugin)
project(${PROJECT_NAME} LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-psabi")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
find_package(PkgConfig REQUIRED)
find_package(Qt5 COMPONENTS Core Multimedia REQUIRED)
pkg_check_modules(FlutterEmbedder REQUIRED IMPORTED_TARGET flutter-embedder)
pkg_check_modules(GLES REQUIRED IMPORTED_TARGET glesv2)
pkg_check_modules(SC REQUIRED IMPORTED_TARGET streamcamera)
add_library(${PLUGIN_NAME} SHARED
embedder_texture_plugin.cpp
camera_pixels_helper.cpp
camera_egl_helper.cpp
camera.cpp
)
set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden)
target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::FlutterEmbedder PkgConfig::GLES PkgConfig::SC)
target_link_libraries(${PLUGIN_NAME} PUBLIC Qt5::Core Qt5::Multimedia)
target_include_directories(${PLUGIN_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_definitions(${PLUGIN_NAME} PRIVATE PLUGIN_IMPL)

114
packages/embedder_texture/aurora/camera.cpp

@ -0,0 +1,114 @@
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <embedder_texture/camera.h>
#include <embedder_texture/camera_egl_helper.h>
#include <embedder_texture/camera_pixels_helper.h>
Camera::Camera(TextureRegistrar *plugin)
: m_plugin(plugin)
, m_manager(StreamCameraManager())
{
CameraEGLHelper::EGLInit();
}
void Camera::InitializeCamera(int cameraID)
{
if (m_cameraId != cameraID && m_manager->getNumberOfCameras()) {
Aurora::StreamCamera::CameraInfo info;
if (m_manager->getCameraInfo(cameraID, info)) {
m_cameraId = cameraID;
m_camera = m_manager->openCamera(info.id);
m_camera->setListener(this);
}
}
}
Aurora::StreamCamera::CameraCapability Camera::StartCapture()
{
if (m_camera) {
Aurora::StreamCamera::CameraInfo info;
if (m_camera->getInfo(info)) {
std::vector<Aurora::StreamCamera::CameraCapability> caps;
if (m_manager->queryCapabilities(info.id, caps)) {
for(Aurora::StreamCamera::CameraCapability cap : caps) {
if (m_widthTexture + m_heightTexture < cap.width + cap.height) {
m_camera->startCapture(cap);
return cap;
}
}
}
}
}
return Aurora::StreamCamera::CameraCapability{};
}
void Camera::StopCapture()
{
if (m_camera) {
m_cameraId = -1;
m_buffer = nullptr;
m_camera->stopCapture();
}
}
std::map<Encodable, Encodable> Camera::Register(int cameraID, int width, int height)
{
m_widthTexture = width;
m_heightTexture = height;
m_textureId = m_plugin->RegisterTexture(
[this](size_t width, size_t height) { return this->m_buffer; });
InitializeCamera(cameraID);
auto cab = StartCapture();
return std::map<Encodable, Encodable>{
{"textureId", m_textureId},
{"width", cab.width},
{"height", cab.height},
};
}
void Camera::Unregister()
{
StopCapture();
m_plugin->UnregisterTexture(m_textureId);
}
void Camera::onCameraFrame(std::shared_ptr<Aurora::StreamCamera::GraphicBuffer> buffer)
{
if (buffer->handleType == Aurora::StreamCamera::HandleType::EGL) {
// @todo Not tested. The device needs to be completed.
auto eglImage = CameraEGLHelper::EGLCreateImage(buffer);
this->m_buffer = new TextureVariant(FlutterEGLImage{
eglImage,
buffer->width,
buffer->height,
});
} else {
auto pixels = CameraPixelsHelper::YUVtoARGB(buffer->mapYCbCr());
this->m_buffer = new TextureVariant(FlutterPixelBuffer{
pixels,
buffer->width,
buffer->height,
});
}
m_plugin->MarkTextureAvailable(m_textureId);
}
void Camera::onCameraError(const std::string &errorDescription)
{
this->Unregister();
std::cout << errorDescription << std::endl;
}
void Camera::onCameraParameterChanged(Aurora::StreamCamera::CameraParameter parameter,
const std::string &value)
{
std::cout << "onCameraParameterChanged" << std::endl;
}

42
packages/embedder_texture/aurora/camera_egl_helper.cpp

@ -0,0 +1,42 @@
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <embedder_texture/camera_egl_helper.h>
#include <flutter/platform-methods.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
void CameraEGLHelper::EGLInit()
{
eglCreateImageKHR = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(
eglGetProcAddress("eglCreateImageKHR"));
eglDestroyImageKHR = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(
eglGetProcAddress("eglDestroyImageKHR"));
}
EGLImageKHR CameraEGLHelper::EGLCreateImage(
std::shared_ptr<Aurora::StreamCamera::GraphicBuffer> buffer)
{
auto display = PlatformMethods::GetEGLDisplay();
auto context = PlatformMethods::GetEGLContext();
const void *handle = buffer->handle;
GLint eglImgAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE};
return eglCreateImageKHR(display,
context,
EGL_NATIVE_BUFFER_ANDROID,
(EGLClientBuffer) handle,
eglImgAttrs);
}
void CameraEGLHelper::EGLDestroyImage(EGLImageKHR image)
{
auto display = PlatformMethods::GetEGLDisplay();
eglDestroyImageKHR(display, image);
}

106
packages/embedder_texture/aurora/camera_helper.cpp

@ -0,0 +1,106 @@
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <embedder_texture/camera_helper.h>
static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
void CameraHelper::EGLInit()
{
eglCreateImageKHR = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(
eglGetProcAddress("eglCreateImageKHR"));
eglDestroyImageKHR = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(
eglGetProcAddress("eglDestroyImageKHR"));
}
EGLImageKHR CameraHelper::EGLCreateImage(
std::shared_ptr<const Aurora::StreamCamera::YCbCrFrame> frame)
{
auto eglDisplay = PlatformMethods::GetEGLDisplay();
auto eglContext = PlatformMethods::GetEGLContext();
const void *handle = buffer->handle;
GLint eglImgAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE};
return s_eglCreateImageKHR(eglDisplay,
eglContext,
EGL_NATIVE_BUFFER_ANDROID,
(EGLClientBuffer) handle,
eglImgAttrs);
}
void CameraHelper::EGLDestroyImage(EGLImageKHR eglImage, EGLDisplay eglDisplay)
{
return eglDestroyImageKHR(eglDisplay, eglImage);
}
uint8_t *CameraHelper::YUVtoARGB(std::shared_ptr<const Aurora::StreamCamera::YCbCrFrame> frame)
{
QSize size(frame->width, frame->height);
QImage *image = new QImage(size, QImage::Format_ARGB32);
planarYuv420ToArgb(frame->y,
frame->cb,
frame->cr,
frame->yStride,
frame->cStride,
frame->cStride,
frame->chromaStep,
reinterpret_cast<quint32 *>(image->bits()),
frame->width,
frame->height);
return static_cast<uint8_t *>(image->bits());
}
quint32 CameraHelper::yuvToArgb(qint32 y, qint32 rv, qint32 guv, qint32 bu, qint32 a = 255)
{
qint32 yy = (y - 16) * 298;
return (a << 24) | qBound(0, (yy + rv) >> 8, 255) << 16 | qBound(0, (yy - guv) >> 8, 255) << 8
| qBound(0, (yy + bu) >> 8, 255);
}
void CameraHelper::planarYuv420ToArgb(const uchar *y,
const uchar *u,
const uchar *v,
qint32 yStride,
qint32 uStride,
qint32 vStride,
qint32 uvPixelStride,
quint32 *rgb,
qint32 width,
qint32 height)
{
quint32 *rgb0 = rgb;
quint32 *rgb1 = rgb + width;
for (qint32 j = 0; j < height; j += 2) {
const uchar *lineY0 = y;
const uchar *lineY1 = y + yStride;
const uchar *lineU = u;
const uchar *lineV = v;
for (qint32 i = 0; i < width; i += 2) {
const qint32 uu = *lineU - 128;
const qint32 vv = *lineV - 128;
const qint32 rv = 409 * vv + 128;
const qint32 guv = 100 * uu + 208 * vv + 128;
const qint32 bu = 516 * uu + 128;
lineU += uvPixelStride;
lineV += uvPixelStride;
*rgb0++ = yuvToArgb(*lineY0++, rv, guv, bu);
*rgb0++ = yuvToArgb(*lineY0++, rv, guv, bu);
*rgb1++ = yuvToArgb(*lineY1++, rv, guv, bu);
*rgb1++ = yuvToArgb(*lineY1++, rv, guv, bu);
}
y += yStride << 1;
u += uStride;
v += vStride;
rgb0 += width;
rgb1 += width;
}
}

77
packages/embedder_texture/aurora/camera_pixels_helper.cpp

@ -0,0 +1,77 @@
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <embedder_texture/camera_pixels_helper.h>
uint8_t *CameraPixelsHelper::YUVtoARGB(std::shared_ptr<const Aurora::StreamCamera::YCbCrFrame> frame)
{
QSize size(frame->width, frame->height);
QImage *image = new QImage(size, QImage::Format_ARGB32);
planarYuv420ToArgb(frame->y,
frame->cr,
frame->cb,
frame->yStride,
frame->cStride,
frame->cStride,
frame->chromaStep,
reinterpret_cast<quint32 *>(image->bits()),
frame->width,
frame->height);
return static_cast<uint8_t *>(image->bits());
}
quint32 CameraPixelsHelper::yuvToArgb(qint32 y, qint32 rv, qint32 guv, qint32 bu, qint32 a = 255)
{
qint32 yy = (y - 16) * 298;
return (a << 24)
| qBound(0, (yy + rv) >> 8, 255) << 16
| qBound(0, (yy - guv) >> 8, 255) << 8
| qBound(0, (yy + bu) >> 8, 255);
}
void CameraPixelsHelper::planarYuv420ToArgb(const uchar *y,
const uchar *u,
const uchar *v,
qint32 yStride,
qint32 uStride,
qint32 vStride,
qint32 uvPixelStride,
quint32 *rgb,
qint32 width,
qint32 height)
{
quint32 *rgb0 = rgb;
quint32 *rgb1 = rgb + width;
for (qint32 j = 0; j < height; j += 2) {
const uchar *lineY0 = y;
const uchar *lineY1 = y + yStride;
const uchar *lineU = u;
const uchar *lineV = v;
for (qint32 i = 0; i < width; i += 2) {
const qint32 uu = *lineU - 128;
const qint32 vv = *lineV - 128;
const qint32 rv = 409 * vv + 128;
const qint32 guv = 100 * uu + 208 * vv + 128;
const qint32 bu = 516 * uu + 128;
lineU += uvPixelStride;
lineV += uvPixelStride;
*rgb0++ = yuvToArgb(*lineY0++, rv, guv, bu);
*rgb0++ = yuvToArgb(*lineY0++, rv, guv, bu);
*rgb1++ = yuvToArgb(*lineY1++, rv, guv, bu);
*rgb1++ = yuvToArgb(*lineY1++, rv, guv, bu);
}
y += yStride << 1;
u += uStride;
v += vStride;
rgb0 += width;
rgb1 += width;
}
}

87
packages/embedder_texture/aurora/embedder_texture_plugin.cpp

@ -0,0 +1,87 @@
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <embedder_texture/embedder_texture_plugin.h>
#include <flutter/method-channel.h>
#include <flutter/platform-data.h>
#include <flutter/platform-events.h>
#include <flutter/platform-methods.h>
EmbedderTexturePlugin::EmbedderTexturePlugin()
{
PlatformEvents::SubscribeOrientationChanged([this](DisplayRotation orientation) {
if (this->m_isEnableOrientationChanged) {
EventChannel("embedder_texture_orientation", MethodCodecType::Standard)
.SendEvent(static_cast<int>(orientation));
}
});
}
void EmbedderTexturePlugin::RegisterWithRegistrar(PluginRegistrar &registrar)
{
TextureRegistrar *plugin = registrar.GetRegisterTexture();
m_camera = new Camera(plugin);
registrar.RegisterMethodChannel("embedder_texture",
MethodCodecType::Standard,
[this](const MethodCall &call) { this->onMethodCall(call); });
registrar.RegisterEventChannel(
"embedder_texture_orientation",
MethodCodecType::Standard,
[this](const Encodable &) {
this->m_isEnableOrientationChanged = true;
return EventResponse();
},
[this](const Encodable &) {
this->m_isEnableOrientationChanged = false;
return EventResponse();
});
}
void EmbedderTexturePlugin::onMethodCall(const MethodCall &call)
{
const auto &method = call.GetMethod();
if (method == "create") {
onCreate(call);
return;
}
if (method == "remove") {
onRemove(call);
return;
}
unimplemented(call);
}
void EmbedderTexturePlugin::onCreate(const MethodCall &call)
{
auto cameraId = 0;
auto width = call.GetArgument<Encodable::Int>("width");
auto height = call.GetArgument<Encodable::Int>("height");
auto result = m_camera->Register(cameraId, width, height);
result["orientation"] = static_cast<int>(PlatformMethods::GetOrientation());
call.SendSuccessResponse(result);
}
void EmbedderTexturePlugin::onRemove(const MethodCall &call)
{
auto textureId = call.GetArgument<Encodable::Int>("textureId");
m_camera->Unregister();
call.SendSuccessResponse(true);
}
void EmbedderTexturePlugin::unimplemented(const MethodCall &call)
{
call.SendSuccessResponse(nullptr);
}

47
packages/embedder_texture/aurora/include/embedder_texture/camera.h

@ -0,0 +1,47 @@
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef CAMERA_BUFFER_H
#define CAMERA_BUFFER_H
#include <flutter/plugin-interface.h>
#include <streamcamera/streamcamera.h>
#include <QImage>
#include <QtCore>
class Camera : public Aurora::StreamCamera::CameraListener
{
public:
Camera(TextureRegistrar *plugin);
void onCameraError(const std::string &errorDescription) override;
void onCameraFrame(std::shared_ptr<Aurora::StreamCamera::GraphicBuffer> buffer) override;
void onCameraParameterChanged(Aurora::StreamCamera::CameraParameter,
const std::string &value) override;
std::map<Encodable, Encodable> Register(int cameraID, int width, int height);
void Unregister();
private:
void InitializeCamera(int cameraID);
Aurora::StreamCamera::CameraCapability StartCapture();
void StopCapture();
private:
TextureRegistrar *m_plugin;
Aurora::StreamCamera::CameraManager *m_manager;
std::shared_ptr<Aurora::StreamCamera::Camera> m_camera;
int m_cameraId = -1;
int64_t m_textureId;
int m_widthTexture;
int m_heightTexture;
TextureVariant *m_buffer;
};
#endif /* CAMERA_BUFFER_H */

21
packages/embedder_texture/aurora/include/embedder_texture/camera_egl_helper.h

@ -0,0 +1,21 @@
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef CAMERA_EGL_HELPER_H
#define CAMERA_EGL_HELPER_H
#include <streamcamera/streamcamera.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
class CameraEGLHelper
{
public:
static void EGLInit();
static EGLImageKHR EGLCreateImage(std::shared_ptr<Aurora::StreamCamera::GraphicBuffer> buffer);
static void EGLDestroyImage(EGLImageKHR image);
};
#endif /* CAMERA_EGL_HELPER_H */

33
packages/embedder_texture/aurora/include/embedder_texture/camera_pixels_helper.h

@ -0,0 +1,33 @@
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef CAMERA_PIXELS_HELPER_H
#define CAMERA_PIXELS_HELPER_H
#include <flutter/plugin-interface.h>
#include <streamcamera/streamcamera.h>
#include <QImage>
#include <QtCore>
class CameraPixelsHelper
{
public:
static uint8_t *YUVtoARGB(std::shared_ptr<const Aurora::StreamCamera::YCbCrFrame> frame);
private:
static quint32 yuvToArgb(qint32 y, qint32 rv, qint32 guv, qint32 bu, qint32 a);
static void planarYuv420ToArgb(const uchar *y,
const uchar *u,
const uchar *v,
qint32 yStride,
qint32 uStride,
qint32 vStride,
qint32 uvPixelStride,
quint32 *rgb,
qint32 width,
qint32 height);
};
#endif /* CAMERA_PIXELS_HELPER_H */

35
packages/embedder_texture/aurora/include/embedder_texture/embedder_texture_plugin.h

@ -0,0 +1,35 @@
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef EMBEDDER_TEXTURE_PLUGIN_H
#define EMBEDDER_TEXTURE_PLUGIN_H
#include <flutter/plugin-interface.h>
#include <embedder_texture/camera.h>
#ifdef PLUGIN_IMPL
#define PLUGIN_EXPORT __attribute__((visibility("default")))
#else
#define PLUGIN_EXPORT
#endif
class PLUGIN_EXPORT EmbedderTexturePlugin final : public PluginInterface
{
public:
EmbedderTexturePlugin();
void RegisterWithRegistrar(PluginRegistrar &registrar) override;
private:
void onMethodCall(const MethodCall &call);
void onCreate(const MethodCall &call);
void onRemove(const MethodCall &call);
void unimplemented(const MethodCall &call);
private:
Camera *m_camera;
bool m_isEnableOrientationChanged = false;
};
#endif /* EMBEDDER_TEXTURE_PLUGIN_H */

162
packages/embedder_texture/lib/embedder_texture.dart

@ -0,0 +1,162 @@
import 'package:flutter/material.dart';
import 'embedder_texture_platform_interface.dart';
enum OrientationEvent {
undefined,
portrait,
landscape,
portraitFlipped,
landscapeFlipped,
}
class EmbedderTexture extends StatefulWidget {
const EmbedderTexture({
super.key,
required this.width,
required this.height,
});
final double width;
final double height;
@override
State<EmbedderTexture> createState() => _EmbedderTextureState();
}
class _EmbedderTextureState extends State<EmbedderTexture> {
int _textureID = 0;
int _cameraWidth = 0;
int _cameraHeight = 0;
OrientationEvent _orientation = OrientationEvent.undefined;
@override
initState() {
super.initState();
EmbedderTexturePlatform.instance
.create(widget.width, widget.height)
.then((data) => setState(() {
if (mounted) {
_textureID = data['textureId']!;
_cameraWidth = data['width']!;
_cameraHeight = data['height']!;
switch (data['orientation']!) {
case 0:
_orientation = OrientationEvent.portrait;
break;
case 90:
_orientation = OrientationEvent.landscape;
break;
case 180:
_orientation = OrientationEvent.portraitFlipped;
break;
case 270:
_orientation = OrientationEvent.landscapeFlipped;
break;
default:
_orientation = OrientationEvent.undefined;
}
debugPrint(data.toString());
}
}));
EmbedderTexturePlatform.instance.onChangeOrientation().listen((event) {
setState(() {
if (mounted) {
_orientation = event;
}
});
});
}
@override
void dispose() {
super.dispose();
EmbedderTexturePlatform.instance.remove(_textureID);
}
// @override
// Widget build(BuildContext context) {
// if (_textureID != 0) {
// double w = 0;
// double h = 0;
// if (MediaQuery.of(context).orientation == Orientation.portrait) {
// w = _cameraWidth * widget.height / (widget.width - 40);
// h = widget.width - 40;
// } else {
// w = _cameraHeight.toDouble();
// h = widget.height - 40 - 56;
// }
// return Container(
// color: Colors.black,
// width: widget.width,
// height: widget.height,
// child: RotationTransition(
// turns: AlwaysStoppedAnimation(
// _orientation == OrientationEvent.portrait ? 90 / 360 : 0,
// ),
// child: SizedBox(
// width: w,
// height: h,
// child: Texture(textureId: _textureID),
// ),
// ),
// );
// }
// return const SizedBox.shrink();
// }
@override
Widget build(BuildContext context) {
if (_textureID != 0) {
double w = 0;
double h = 0;
if (_orientation == OrientationEvent.portrait ||
_orientation == OrientationEvent.portraitFlipped) {
w = _cameraWidth * widget.height / (widget.width - 40);
h = widget.width - 40;
} else {
w = _cameraHeight.toDouble();
h = widget.height - 40 - 56;
}
AlwaysStoppedAnimation<double>? turns;
switch (_orientation) {
case OrientationEvent.portrait:
turns = const AlwaysStoppedAnimation(90 / 360);
break;
case OrientationEvent.portraitFlipped:
turns = const AlwaysStoppedAnimation(270 / 360);
break;
case OrientationEvent.landscapeFlipped:
turns = const AlwaysStoppedAnimation(180 / 360);
break;
default:
turns = const AlwaysStoppedAnimation(0);
}
return Container(
color: Colors.black,
width: widget.width,
height: widget.height,
child: Center(
child: RotationTransition(
turns: turns,
child: SizedBox(
width: w,
height: h,
child: Texture(textureId: _textureID),
),
),
),
);
}
return const SizedBox.shrink();
}
}

54
packages/embedder_texture/lib/embedder_texture_method_channel.dart

@ -0,0 +1,54 @@
import 'package:embedder_texture/embedder_texture.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'embedder_texture_platform_interface.dart';
/// An implementation of [LinuxOpenglPlatform] that uses method channels.
class MethodChannelEmbedderTexture extends EmbedderTexturePlatform {
/// The method channel used to interact with the native platform.
@visibleForTesting
final methodChannel = const MethodChannel('embedder_texture');
@override
Future<Map<dynamic, dynamic>> create(double width, double height) async {
final data =
await methodChannel.invokeMethod<Map<dynamic, dynamic>?>('create', {
'width': width.round(),
'height': height.round(),
});
return data ?? {};
}
@override
Future<bool> remove(int textureId) async {
return await methodChannel.invokeMethod<bool>('remove', {
'textureId': textureId,
}) ??
false;
}
@override
Stream<OrientationEvent> onChangeOrientation() async* {
await for (final orientation
in const EventChannel('embedder_texture_orientation')
.receiveBroadcastStream()) {
switch (orientation) {
case 0:
yield OrientationEvent.portrait;
break;
case 90:
yield OrientationEvent.landscape;
break;
case 180:
yield OrientationEvent.portraitFlipped;
break;
case 270:
yield OrientationEvent.landscapeFlipped;
break;
default:
yield OrientationEvent.undefined;
}
}
}
}

38
packages/embedder_texture/lib/embedder_texture_platform_interface.dart

@ -0,0 +1,38 @@
import 'package:embedder_texture/embedder_texture.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'embedder_texture_method_channel.dart';
abstract class EmbedderTexturePlatform extends PlatformInterface {
/// Constructs a LinuxOpenglPlatform.
EmbedderTexturePlatform() : super(token: _token);
static final Object _token = Object();
static EmbedderTexturePlatform _instance = MethodChannelEmbedderTexture();
/// The default instance of [LinuxOpenglPlatform] to use.
///
/// Defaults to [MethodChannelLinuxOpengl].
static EmbedderTexturePlatform get instance => _instance;
/// Platform-specific implementations should set this with their own
/// platform-specific class that extends [LinuxOpenglPlatform] when
/// they register themselves.
static set instance(EmbedderTexturePlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
Stream<OrientationEvent> onChangeOrientation() {
throw UnimplementedError('onChangeOrientation() has not been implemented.');
}
Future<Map<dynamic, dynamic>> create(double width, double height) {
throw UnimplementedError('create() has not been implemented.');
}
Future<bool> remove(int textureId) {
throw UnimplementedError('remove() has not been implemented.');
}
}

24
packages/embedder_texture/linux/CMakeLists.txt

@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.10)
set(PROJECT_NAME "embedder_texture")
project(${PROJECT_NAME} LANGUAGES CXX)
set(PLUGIN_NAME "embedder_texture_plugin")
list(APPEND PLUGIN_SOURCES
"fl_my_texture_gl.cc"
"embedder_texture_plugin.cc"
)
add_library(${PLUGIN_NAME} SHARED
${PLUGIN_SOURCES}
)
apply_standard_settings(${PLUGIN_NAME})
set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden)
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter)
target_link_libraries(${PLUGIN_NAME} PUBLIC GL)

173
packages/embedder_texture/linux/embedder_texture_plugin.cc

@ -0,0 +1,173 @@
#include "include/embedder_texture/embedder_texture_plugin.h"
#include "include/fl_my_texture_gl.h"
#include <flutter_linux/flutter_linux.h>
#include <flutter_linux/fl_view.h>
#include <GLES2/gl2.h>
#include "embedder_texture_plugin_private.h"
#define EMBEDDER_TEXTURE_PLUGIN(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), embedder_texture_plugin_get_type(), \
LinuxOpenglPlugin))
struct _LinuxOpenglPlugin
{
GObject parent_instance;
unsigned int width = 0;
unsigned int height = 0;
unsigned int texture_id = 0;
FlTexture *texture = nullptr;
FlTextureRegistrar *texture_registrar = nullptr;
FlMyTextureGL *myTexture = nullptr;
FlView *fl_view = nullptr;
};
G_DEFINE_TYPE(LinuxOpenglPlugin, embedder_texture_plugin, g_object_get_type())
// Called when a method call is received from Flutter.
static void embedder_texture_plugin_handle_method_call(
LinuxOpenglPlugin *self,
FlMethodCall *method_call)
{
g_autoptr(FlMethodResponse) response = nullptr;
const gchar *method = fl_method_call_get_name(method_call);
if (strcmp(method, "create") == 0)
{
response = create(self, method_call);
}
else if (strcmp(method, "remove") == 0)
{
response = remove(self, method_call);
}
else
{
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
}
fl_method_call_respond(method_call, response, nullptr);
}
FlMethodResponse *create(
LinuxOpenglPlugin *self,
FlMethodCall *method_call)
{
GError *error = NULL;
FlValue *args = fl_method_call_get_args(method_call);
FlValue *w = fl_value_lookup_string(args, "width");
FlValue *h = fl_value_lookup_string(args, "height");
if (w != nullptr)
{
self->width = fl_value_get_float(w);
}
if (h != nullptr)
{
self->height = fl_value_get_float(h);
}
if (self->width != 0 && self->height != 0)
{
static GLfloat pixels[] =
{
1, 0, 0,
0, 1, 0,
0, 0, 1,
1, 1, 1
};
// create in open gl
glGenTextures(1, &self->texture_id);
glBindTexture(GL_TEXTURE_2D, self->texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// create
self->myTexture = fl_my_texture_gl_new(GL_TEXTURE_2D, self->texture_id, self->width, self->height);
self->texture = FL_TEXTURE(self->myTexture);
// reg
fl_texture_registrar_register_texture(self->texture_registrar, self->texture);
// draw
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_FLOAT, pixels);
// send id
g_autoptr(FlValue) result = fl_value_new_int(reinterpret_cast<int64_t>(self->texture));
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
}
return FL_METHOD_RESPONSE(fl_method_error_response_new(
"500",
"Method create() called without passing width or height parameters!",
nullptr));
}
FlMethodResponse *remove(
LinuxOpenglPlugin *self,
FlMethodCall *method_call)
{
FlValue *args = fl_method_call_get_args(method_call);
FlValue *id = fl_value_lookup_string(args, "textureId");
if (id != nullptr)
{
int textureId = fl_value_get_int(id);
fl_texture_registrar_unregister_texture(self->texture_registrar, self->texture);
g_autoptr(FlValue) result = fl_value_new_null();
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
}
return FL_METHOD_RESPONSE(fl_method_error_response_new(
"500",
"Method remove() called without passing textureId parameters!",
nullptr));
}
static void embedder_texture_plugin_dispose(GObject *object)
{
G_OBJECT_CLASS(embedder_texture_plugin_parent_class)->dispose(object);
}
static void embedder_texture_plugin_class_init(LinuxOpenglPluginClass *klass)
{
G_OBJECT_CLASS(klass)->dispose = embedder_texture_plugin_dispose;
}
static void embedder_texture_plugin_init(LinuxOpenglPlugin *self) {}
static void method_call_cb(FlMethodChannel *channel, FlMethodCall *method_call,
gpointer user_data)
{
LinuxOpenglPlugin *plugin = EMBEDDER_TEXTURE_PLUGIN(user_data);
embedder_texture_plugin_handle_method_call(plugin, method_call);
}
void embedder_texture_plugin_register_with_registrar(FlPluginRegistrar *registrar)
{
LinuxOpenglPlugin *plugin = EMBEDDER_TEXTURE_PLUGIN(
g_object_new(embedder_texture_plugin_get_type(), nullptr));
plugin->fl_view = fl_plugin_registrar_get_view(registrar);
plugin->texture_registrar = fl_plugin_registrar_get_texture_registrar(registrar);
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
g_autoptr(FlMethodChannel) channel =
fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar),
"embedder_texture",
FL_METHOD_CODEC(codec));
fl_method_channel_set_method_call_handler(channel, method_call_cb,
g_object_ref(plugin),
g_object_unref);
g_object_unref(plugin);
}

7
packages/embedder_texture/linux/embedder_texture_plugin_private.h

@ -0,0 +1,7 @@
#include <flutter_linux/flutter_linux.h>
#include "include/embedder_texture/embedder_texture_plugin.h"
FlMethodResponse *create(LinuxOpenglPlugin *self, FlMethodCall *method_call);
FlMethodResponse *remove(LinuxOpenglPlugin *self, FlMethodCall *method_call);

44
packages/embedder_texture/linux/fl_my_texture_gl.cc

@ -0,0 +1,44 @@
#include "include/fl_my_texture_gl.h"
G_DEFINE_TYPE(FlMyTextureGL,
fl_my_texture_gl,
fl_texture_gl_get_type())
static gboolean fl_my_texture_gl_populate(FlTextureGL *texture,
uint32_t *target,
uint32_t *name,
uint32_t *width,
uint32_t *height,
GError **error)
{
FlMyTextureGL* f = (FlMyTextureGL*) texture;
*target = f->target;
*name = f->name;
*width = f->width;
*height = f->height;
return true;
}
FlMyTextureGL *fl_my_texture_gl_new(uint32_t target,
uint32_t name,
uint32_t width,
uint32_t height)
{
auto r = FL_MY_TEXTURE_GL(g_object_new(fl_my_texture_gl_get_type(), nullptr));
r->target = target;
r->name = name;
r->width = width;
r->height = height;
return r;
}
static void fl_my_texture_gl_class_init(
FlMyTextureGLClass *klass)
{
FL_TEXTURE_GL_CLASS(klass)->populate =
fl_my_texture_gl_populate;
}
static void fl_my_texture_gl_init(FlMyTextureGL *self)
{
}

26
packages/embedder_texture/linux/include/embedder_texture/embedder_texture_plugin.h

@ -0,0 +1,26 @@
#ifndef FLUTTER_PLUGIN_EMBEDDER_TEXTURE_PLUGIN_H_
#define FLUTTER_PLUGIN_EMBEDDER_TEXTURE_PLUGIN_H_
#include <flutter_linux/flutter_linux.h>
G_BEGIN_DECLS
#ifdef FLUTTER_PLUGIN_IMPL
#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default")))
#else
#define FLUTTER_PLUGIN_EXPORT
#endif
typedef struct _LinuxOpenglPlugin LinuxOpenglPlugin;
typedef struct {
GObjectClass parent_class;
} LinuxOpenglPluginClass;
FLUTTER_PLUGIN_EXPORT GType embedder_texture_plugin_get_type();
FLUTTER_PLUGIN_EXPORT void embedder_texture_plugin_register_with_registrar(
FlPluginRegistrar* registrar);
G_END_DECLS
#endif // FLUTTER_PLUGIN_EMBEDDER_TEXTURE_PLUGIN_H_

28
packages/embedder_texture/linux/include/fl_my_texture_gl.h

@ -0,0 +1,28 @@
#ifndef FLUTTER_MY_TEXTURE_H
#define FLUTTER_MY_TEXTURE_H
#include <gtk/gtk.h>
#include <glib-object.h>
#include "embedder_texture/embedder_texture_plugin.h"
#include <flutter_linux/flutter_linux.h>
G_DECLARE_FINAL_TYPE(FlMyTextureGL,
fl_my_texture_gl,
FL,
MY_TEXTURE_GL,
FlTextureGL)
struct _FlMyTextureGL
{
FlTextureGL parent_instance;
uint32_t target;
uint32_t name;
uint32_t width;
uint32_t height;
};
FlMyTextureGL *fl_my_texture_gl_new(uint32_t target,
uint32_t name,
uint32_t width,
uint32_t height);
#endif // FLUTTER_MY_TEXTURE_H

25
packages/embedder_texture/pubspec.yaml

@ -0,0 +1,25 @@
name: embedder_texture
description: Example create texture.
version: 0.0.1
environment:
sdk: '>=3.0.6 <4.0.0'
flutter: ">=3.3.0"
dependencies:
flutter:
sdk: flutter
plugin_platform_interface: ^2.0.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
flutter:
plugin:
platforms:
linux:
pluginClass: EmbedderTexturePlugin
aurora:
pluginClass: EmbedderTexturePlugin
Loading…
Cancel
Save