[0.3.144] Add PLAYER_DISPLAY_OVERLAY_SYNC_UI type for sync UI and video 31/258231/16 accepted/tizen/unified/20210730.130033 submit/tizen/20210723.051302 submit/tizen/20210729.005533
authorHyunil <hyunil46.park@samsung.com>
Wed, 12 May 2021 11:19:47 +0000 (20:19 +0900)
committerHyunil <hyunil46.park@samsung.com>
Fri, 23 Jul 2021 01:48:08 +0000 (10:48 +0900)
- player_set_display could get wayland tizen exported shell handle with new type
- Display related function set as PLAYER_DISPLAY_OVERLAY cannot be used except for visible
  and PLAYER_ERROR_NOT_AVAILABLE is returned if they are used
- Add sample function to player_test with move, resize and transform
- Video is always rendered at full scale inside tizen exported shell

Change-Id: I61c20cb7e124d16a86b0a11dbd941f6ae693b7d8
Signed-off-by: Hyunil <hyunil46.park@samsung.com>
include/player.h
packaging/capi-media-player.spec
src/player.c
test/CMakeLists.txt
test/player_test.c

index 9dd3bde..815bf36 100644 (file)
@@ -110,11 +110,22 @@ typedef enum {
 /**
  * @brief Enumeration for display type.
  * @since_tizen @if WEARABLE 2.3.1 @else 2.3 @endif
+ * @details In case of using #PLAYER_DISPLAY_TYPE_OVERLAY_SYNC_UI, the video is rendering in full scale in the rendering area.\n
+ *          To change the video rendering position, use UI API functions like ecore_wl2_subsurface_exported_surface_move(),
+ *          ecore_wl2_subsurface_exported_surface_resize(), ecore_wl2_subsurface_exported_surface_transform_set(),
+ *          ecore_wl2_subsurface_exported_surface_show() and ecore_wl2_subsurface_exported_surface_commit().\n
+ *          player_set_display_mode(), player_set_display_rotation() and player_set_display_roi_area() cannot be used and
+ *          #PLAYER_ERROR_NOT_AVAILABLE is returned if they are used.\n
+ *          Exported shell handle must be obtained by ecore_wl2_subsurface_exported_surface_handle_get() from Ecore_Wl2_Subsurface.\n
+ *          Then the exported shell handle should be set with player_set_display().\n
+ *          To render the first video buffer, commit by ecore_wl2_window_commit() after player_prepare() of Ecore_Wl2_Subsurface.\n
+ *          Always commit with ecore_wl2_window_commit() with parent surface when the UI changes and the video needs to be synchronized.
  */
 typedef enum {
        PLAYER_DISPLAY_TYPE_OVERLAY = 0,        /**< Overlay surface display */
        PLAYER_DISPLAY_TYPE_EVAS = 3,           /**< Evas image object surface display (Since 4.0) */
        PLAYER_DISPLAY_TYPE_NONE = 4,           /**< This disposes of buffers (Since 4.0) */
+       PLAYER_DISPLAY_TYPE_OVERLAY_SYNC_UI = 5 /**< Overlay surface display for synchronization between UI and video (Since 6.5) */
 } player_display_type_e;
 
 /**
@@ -1398,6 +1409,7 @@ int player_get_media_stream_buffer_min_threshold(player_h player, player_stream_
  * @retval #PLAYER_ERROR_NONE Successful
  * @retval #PLAYER_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PLAYER_ERROR_INVALID_OPERATION Invalid operation
+ * @retval #PLAYER_ERROR_NOT_AVAILABLE Not available (Since 6.5)
  * @see #player_display_mode_e
  * @see player_set_display()
  * @see player_get_display_mode()
@@ -1415,6 +1427,7 @@ int player_set_display_mode(player_h player, player_display_mode_e mode);
  * @retval  #PLAYER_ERROR_NONE Successful
  * @retval  #PLAYER_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval  #PLAYER_ERROR_INVALID_OPERATION Invalid operation
+ * @retval  #PLAYER_ERROR_NOT_AVAILABLE Not available (Since 6.5)
  * @see #player_display_mode_e
  * @see player_set_display_mode()
  */
@@ -1437,6 +1450,7 @@ int player_get_display_mode(player_h player, player_display_mode_e *mode);
  * @retval  #PLAYER_ERROR_NONE Successful
  * @retval  #PLAYER_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval  #PLAYER_ERROR_INVALID_OPERATION Invalid operation
+ * @retval  #PLAYER_ERROR_NOT_AVAILABLE Not available (Since 6.5)
  * @see player_set_display()
  * @see player_set_display_mode()
  */
@@ -1486,6 +1500,7 @@ int player_is_display_visible(player_h player, bool *visible);
  * @retval #PLAYER_ERROR_NONE Successful
  * @retval #PLAYER_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PLAYER_ERROR_INVALID_OPERATION Invalid operation
+ * @retval #PLAYER_ERROR_NOT_AVAILABLE Not available (Since 6.5)
  * @see #player_display_rotation_e
  * @see  player_set_display()
  * @see  player_get_display_rotation()
@@ -1502,6 +1517,7 @@ int player_set_display_rotation(player_h player, player_display_rotation_e rotat
  * @retval  #PLAYER_ERROR_NONE Successful
  * @retval  #PLAYER_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval  #PLAYER_ERROR_INVALID_OPERATION Invalid operation
+ * @retval  #PLAYER_ERROR_NOT_AVAILABLE Not available (Since 6.5)
  * @see     #player_display_rotation_e
  * @see     player_set_display_rotation()
  */
index 1d5880a..bad51bf 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-player
 Summary:    A Media Player API
-Version:    0.3.143
+Version:    0.3.144
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
@@ -18,6 +18,7 @@ BuildRequires:  pkgconfig(tizen-extension-client)
 BuildRequires:  pkgconfig(appcore-efl)
 BuildRequires:  pkgconfig(elementary)
 BuildRequires:  pkgconfig(ecore)
+BuildRequires:  pkgconfig(ecore-wl2)
 BuildRequires:  pkgconfig(evas)
 BuildRequires:  pkgconfig(capi-media-tool)
 BuildRequires:  pkgconfig(mmsvc-player)
index 90686b2..461f6bb 100644 (file)
@@ -176,8 +176,6 @@ static bool _player_get_param_value(char *buf, ...)
        char *param_name = NULL;
        void *value = NULL;
 
-       LOGE("ENTER");
-
        void *jobj = muse_core_msg_object_new(buf, NULL, &err);
 
        if (!jobj) {
@@ -3027,6 +3025,9 @@ int _player_convert_display_type(player_display_type_e type, mm_display_type_e *
        case PLAYER_DISPLAY_TYPE_OVERLAY:
                *out_type = MM_DISPLAY_TYPE_OVERLAY;
                break;
+       case PLAYER_DISPLAY_TYPE_OVERLAY_SYNC_UI:
+               *out_type = MM_DISPLAY_TYPE_OVERLAY_SYNC_UI;
+               break;
        case PLAYER_DISPLAY_TYPE_EVAS:
                *out_type = MM_DISPLAY_TYPE_EVAS;
                break;
@@ -3094,7 +3095,9 @@ int player_set_display(player_h player, player_display_type_e type, player_displ
                        return PLAYER_ERROR_INVALID_OPERATION;
                }
 
-               if (conv_type == MM_DISPLAY_TYPE_EVAS) {
+               if (conv_type == MM_DISPLAY_TYPE_OVERLAY_SYNC_UI) {
+                       g_strlcpy(wl_win.exported_shell_handle, (char *)display, MAX_EXPORTED_SHELL_HANDLE_LEN);
+               } else if (conv_type == MM_DISPLAY_TYPE_EVAS) {
                        /* before evas handle is created, user could set display information */
                        player_display_mode_e mode = PLAYER_DISPLAY_MODE_LETTER_BOX;
                        player_display_rotation_e rotation = PLAYER_DISPLAY_ROTATION_NONE;
@@ -3168,6 +3171,11 @@ int player_set_display_mode(player_h player, player_display_mode_e mode)
 
        PLAYER_GET_DISPLAY_TYPE(pc, display_type);
 
+       if (display_type == MM_DISPLAY_TYPE_OVERLAY_SYNC_UI) {
+               LOGE("Function is not available in MM_DISPLAY_TYPE_OVERLAY_SYNC_UI type");
+               return PLAYER_ERROR_NOT_AVAILABLE;
+       }
+
        if (display_type == MM_DISPLAY_TYPE_EVAS) {
                mm_ret = mm_display_interface_evas_set_mode(DP_INTERFACE(pc), mode);
                if (mm_ret != MM_ERROR_NONE) {
@@ -3190,12 +3198,20 @@ int player_get_display_mode(player_h player, player_display_mode_e *pmode)
        player_cli_s *pc = (player_cli_s *)player;
        char *ret_buf = NULL;
        int mode = -1;
+       mm_display_type_e display_type = MM_DISPLAY_TYPE_NONE;
 
        PLAYER_INSTANCE_CHECK(player);
        PLAYER_NULL_ARG_CHECK(pmode);
 
        LOGD("ENTER");
 
+       PLAYER_GET_DISPLAY_TYPE(pc, display_type);
+
+       if (display_type == MM_DISPLAY_TYPE_OVERLAY_SYNC_UI) {
+               LOGE("Function is not available in MM_DISPLAY_TYPE_OVERLAY_SYNC_UI type");
+               return PLAYER_ERROR_NOT_AVAILABLE;
+       }
+
        PLAYER_SEND_MSG(api, pc, ret_buf, ret);
 
        if (ret == PLAYER_ERROR_NONE) {
@@ -3223,6 +3239,11 @@ int player_set_video_roi_area(player_h player, double x_scale, double y_scale,
 
        PLAYER_GET_DISPLAY_TYPE(pc, display_type);
 
+       if (display_type == MM_DISPLAY_TYPE_OVERLAY_SYNC_UI) {
+               LOGE("Function is not available in MM_DISPLAY_TYPE_OVERLAY_SYNC_UI type");
+               return PLAYER_ERROR_NOT_AVAILABLE;
+       }
+
        if (display_type == MM_DISPLAY_TYPE_EVAS) {
                LOGE("Display type is EVAS, video display interface is not supported");
                return PLAYER_ERROR_INVALID_OPERATION;
@@ -3251,8 +3272,16 @@ int player_get_video_roi_area(player_h player, double *x_scale, double *y_scale,
        player_cli_s *pc = (player_cli_s *)player;
        char *ret_buf = NULL;
        double scale_x = 0, scale_y = 0, scale_w = 0, scale_h = 0;
+       mm_display_type_e display_type = MM_DISPLAY_TYPE_NONE;
 
        PLAYER_INSTANCE_CHECK(player);
+       PLAYER_GET_DISPLAY_TYPE(pc, display_type);
+
+       if (display_type == MM_DISPLAY_TYPE_OVERLAY_SYNC_UI) {
+               LOGE("Function is not available in MM_DISPLAY_TYPE_OVERLAY_SYNC_UI type");
+               return PLAYER_ERROR_NOT_AVAILABLE;
+       }
+
        PLAYER_NULL_ARG_CHECK(x_scale && y_scale && w_scale && h_scale);
 
        PLAYER_SEND_MSG(api, pc, ret_buf, ret);
@@ -3365,6 +3394,11 @@ int player_set_display_rotation(player_h player, player_display_rotation_e rotat
 
        PLAYER_GET_DISPLAY_TYPE(pc, display_type);
 
+       if (display_type == MM_DISPLAY_TYPE_OVERLAY_SYNC_UI) {
+               LOGE("Function is not available in MM_DISPLAY_TYPE_OVERLAY_SYNC_UI type");
+               return PLAYER_ERROR_NOT_AVAILABLE;
+       }
+
        if (display_type == MM_DISPLAY_TYPE_EVAS) {
                mm_ret = mm_display_interface_evas_set_rotation(DP_INTERFACE(pc), rotation);
                if (mm_ret != MM_ERROR_NONE) {
@@ -3387,8 +3421,16 @@ int player_get_display_rotation(player_h player, player_display_rotation_e *prot
        muse_player_api_e api = MUSE_PLAYER_API_GET_DISPLAY_ROTATION;
        char *ret_buf = NULL;
        int rotation = -1;
+       mm_display_type_e display_type = MM_DISPLAY_TYPE_NONE;
 
        PLAYER_INSTANCE_CHECK(player);
+       PLAYER_GET_DISPLAY_TYPE(pc, display_type);
+
+       if (display_type == MM_DISPLAY_TYPE_OVERLAY_SYNC_UI) {
+               LOGE("Function is not available in MM_DISPLAY_TYPE_OVERLAY_SYNC_UI type");
+               return PLAYER_ERROR_NOT_AVAILABLE;
+       }
+
        PLAYER_NULL_ARG_CHECK(protation);
 
        LOGD("ENTER");
index f805e0b..e0f2570 100644 (file)
@@ -11,7 +11,7 @@ INCLUDE_DIRECTORIES(event-handler/include)
 link_directories(${CMAKE_SOURCE_DIR}/../)
 
 INCLUDE(FindPkgConfig)
-pkg_check_modules(${fw_test} REQUIRED libudev libinput capi-system-info appcore-efl elementary ecore evas capi-media-sound-manager)
+pkg_check_modules(${fw_test} REQUIRED libudev libinput capi-system-info appcore-efl elementary ecore ecore-wl2 evas capi-media-sound-manager)
 FOREACH(flag ${${fw_test}_CFLAGS})
     SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
 ENDFOREACH(flag)
index 2ba5f3e..1543532 100644 (file)
@@ -24,6 +24,7 @@
 #include <appcore-efl.h>
 #include <Elementary.h>
 #include <Ecore.h>
+#include <Ecore_Wl2.h>
 #include <stdio.h>
 #include <string.h>
 #ifdef _ACTIVATE_EOM_
@@ -196,6 +197,8 @@ static Evas_Object *g_external_win_id;
 static Evas_Object *selected_win_id;
 static Evas_Object *g_eo[MAX_HANDLE] = { 0, };
 
+static Ecore_Wl2_Subsurface *g_ecore_wl2_subsurface = NULL;
+static Ecore_Wl2_Window *g_ecore_wl2_window = NULL;
 static int g_current_surface_type = -1;
 
 typedef struct {
@@ -554,6 +557,16 @@ static int app_create(void *data)
        return 0;
 }
 
+static void __ecore_wl2_subsurface_del(Ecore_Wl2_Subsurface *ecore_wl2_subsurface)
+{
+       if (!ecore_wl2_subsurface) {
+               g_print("ecore_wl2_subsurface is NULL\n");
+               return;
+       }
+       ecore_wl2_subsurface_del(ecore_wl2_subsurface);
+       ecore_wl2_subsurface = NULL;
+}
+
 static int app_terminate(void *data)
 {
        appdata *ad = data;
@@ -569,6 +582,9 @@ static int app_terminate(void *data)
                        g_eo[i] = NULL;
                }
        }
+
+       __ecore_wl2_subsurface_del(g_ecore_wl2_subsurface);
+
        if (g_win_id) {
                evas_object_del(g_win_id);
                g_win_id = NULL;
@@ -1087,6 +1103,11 @@ static void _player_prepare(bool async)
        if (is_es_push_mode)
                pthread_create(&g_feed_video_thread_id, NULL, (void *)feed_video_data_thread_func, NULL);
 
+       if (g_current_surface_type == PLAYER_DISPLAY_TYPE_OVERLAY_SYNC_UI &&
+                               g_ecore_wl2_subsurface && g_ecore_wl2_window) {
+               ecore_wl2_window_commit(g_ecore_wl2_window, EINA_TRUE);
+       }
+
 #ifdef USE_EVENT_HANDLER
        event_handler_set_dov_fov();
 #endif
@@ -1213,6 +1234,7 @@ static void _player_play()
 {
        int bRet = FALSE;
        int i = 0;
+
        if (g_current_surface_type == PLAYER_DISPLAY_TYPE_OVERLAY) {
 #ifdef _ACTIVATE_EOM_
                /* for checking external display.... */
@@ -1782,6 +1804,8 @@ static void change_surface(int option)
 {
        player_display_type_e surface_type = 0;
        int ret = PLAYER_ERROR_NONE;
+       Eina_Bool res = EINA_FALSE;
+       const char *exported_shell_handle = NULL;
 #ifdef _ACTIVATE_EOM_
        int hdmi_output_id;
        eom_output_mode_e output_mode;
@@ -1790,7 +1814,7 @@ static void change_surface(int option)
        case 0:
                /* X surface */
                surface_type = PLAYER_DISPLAY_TYPE_OVERLAY;
-               g_print("change surface type to X\n");
+               g_print("change surface type to OVERLAY\n");
                break;
        case 1:
                /* EVAS surface */
@@ -1802,11 +1826,43 @@ static void change_surface(int option)
                surface_type = g_current_surface_type = PLAYER_DISPLAY_TYPE_NONE;
                player_set_display(g_player[0], PLAYER_DISPLAY_TYPE_NONE, NULL);
                break;
+       case 3:
+               g_print("change surface type to OVERLAY_SYNC_UI\n");
+               surface_type = g_current_surface_type = PLAYER_DISPLAY_TYPE_OVERLAY_SYNC_UI;
+               Ecore_Wl2_Window *ecore_wl2_win = (Ecore_Wl2_Window *)elm_win_wl_window_get(g_win_id);
+               Ecore_Wl2_Subsurface *ecore_wl2_subsurface = ecore_wl2_subsurface_new(ecore_wl2_win);
+               g_ecore_wl2_window = ecore_wl2_win;
+
+               res = ecore_wl2_subsurface_export(ecore_wl2_subsurface);
+               if (res != EINA_TRUE) {
+                       g_print("failed to export foreign shell");
+                       return;
+               }
+               exported_shell_handle = ecore_wl2_subsurface_exported_surface_handle_get(ecore_wl2_subsurface);
+               if (!exported_shell_handle) {
+                       g_print("failed to get exported foreign shell handle");
+                       return;
+               }
+               // Enables or disables exported surface synchronization for a given subsurface (default: EINA_TRUE)
+               ecore_wl2_subsurface_exported_surface_sync_set(ecore_wl2_subsurface, EINA_TRUE);
+               // If NULL is used, exported subsurface is placed under exported surface
+               ecore_wl2_subsurface_exported_surface_place_below(ecore_wl2_subsurface, NULL);
+               ecore_wl2_subsurface_exported_surface_move(ecore_wl2_subsurface, 200, 200);
+               ecore_wl2_subsurface_exported_surface_resize(ecore_wl2_subsurface, 500, 500);
+               ecore_wl2_subsurface_exported_surface_show(ecore_wl2_subsurface);
+               ecore_wl2_subsurface_exported_surface_commit(ecore_wl2_subsurface);
+               g_ecore_wl2_subsurface = ecore_wl2_subsurface;
+               player_set_display(g_player[0], PLAYER_DISPLAY_TYPE_OVERLAY_SYNC_UI, GET_DISPLAY(exported_shell_handle));
+
+               return;
        default:
                g_print("invalid surface type\n");
                return;
        }
 
+       if (surface_type != PLAYER_DISPLAY_TYPE_OVERLAY_SYNC_UI && g_ecore_wl2_subsurface)
+               __ecore_wl2_subsurface_del(g_ecore_wl2_subsurface);
+
        player_state_e player_state = PLAYER_STATE_NONE;
        ret = player_get_state(g_player[0], &player_state);
        if (ret)
@@ -1898,6 +1954,15 @@ static void set_display_roi_area(int x, int y, int width, int height)
 
 static void set_display_rotation(int rotation)
 {
+       if (g_ecore_wl2_subsurface) {
+               g_print("set_display_rotation (%d)\n", rotation);
+               ecore_wl2_subsurface_exported_surface_transform_set(g_ecore_wl2_subsurface, rotation);
+               ecore_wl2_subsurface_exported_surface_show(g_ecore_wl2_subsurface);
+               ecore_wl2_subsurface_exported_surface_commit(g_ecore_wl2_subsurface);
+               ecore_wl2_window_commit(g_ecore_wl2_window, EINA_TRUE);
+               return;
+       }
+
        if (player_set_display_rotation(g_player[0], rotation) != PLAYER_ERROR_NONE)
                g_print("failed to set_display_rotation\n");
 #ifdef USE_EVENT_HANDLER
@@ -1909,6 +1974,9 @@ static void set_display_rotation(int rotation)
 static void get_display_rotation()
 {
        player_display_rotation_e rotation = 0;
+       if (g_ecore_wl2_subsurface)
+               return;
+
        player_get_display_rotation(g_player[0], &rotation);
 #ifdef USE_EVENT_HANDLER
        g_rotation = (player_display_rotation_e) rotation;
@@ -2584,7 +2652,7 @@ static void displaymenu()
        } else if (g_menu_state == CURRENT_STATUS_LOOPING) {
                g_print("*** input looping value.(0: Not Looping, 1: Looping) \n");
        } else if (g_menu_state == CURRENT_STATUS_DISPLAY_SURFACE_CHANGE) {
-               g_print("*** input display surface type.(0: Wayland surface, 1: EVAS surface, 2: No use surface (e.g: audio playback)) \n");
+               g_print("*** input display surface type.(0: Wayland surface, 1: EVAS surface, 2: No use surface (e.g: audio playback)) 3: Wayland surface(foreign shell)\n");
        } else if (g_menu_state == CURRENT_STATUS_EXPORT_VIDEO_FRAME) {
                g_print("*** set video_decoded_cb (0: none, 1: set cb) \n");
        } else if (g_menu_state == CURRENT_STATUS_DISPLAY_MODE) {