From 3e0816ba6e10505268902b3146e9e3cb86a9a888 Mon Sep 17 00:00:00 2001 From: jiangyuwei Date: Sun, 7 Apr 2024 14:46:19 +0800 Subject: [PATCH 01/16] [M120 Migration] Add guard code to avoid crash during webview clean In low memory case, browser will clean webview and create new one, driver will release and cause autofill crash. References: - https://review.tizen.org/gerrit/300788/ Change-Id: Iedd4a8a2a7005fc472ee00bb4e26599c8507e642 Signed-off-by: jiangyuwei --- components/password_manager/core/browser/password_form_filling.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/password_manager/core/browser/password_form_filling.cc b/components/password_manager/core/browser/password_form_filling.cc index ca45a25..16a62c3 100644 --- a/components/password_manager/core/browser/password_form_filling.cc +++ b/components/password_manager/core/browser/password_form_filling.cc @@ -129,7 +129,10 @@ LikelyFormFilling SendFillInformationToRenderer( bool webauthn_suggestions_available) { DCHECK(driver); DCHECK_EQ(PasswordForm::Scheme::kHtml, observed_form.scheme); - + if (!driver) { + LOG(ERROR) << "driver already released, fill will not work"; + return LikelyFormFilling::kNoFilling; + } if (autofill::IsShowAutofillSignaturesEnabled()) { driver->AnnotateFieldsWithParsingResult( {.username_renderer_id = observed_form.username_element_renderer_id, -- 2.7.4 From 29ad5a946f64ca23da19e716089adf5659f49505 Mon Sep 17 00:00:00 2001 From: jiangyuwei Date: Sun, 7 Apr 2024 14:04:59 +0800 Subject: [PATCH 02/16] [M120 Migration][VD][Accessibility] Add smart callbacks for spatial navigation This patch is for changing focus from web view in Tizen TV to browser when cannot move focus any more by press arrow keys in spatial navigation. References: - https://review.tizen.org/gerrit/291208/ Change-Id: I3c7d860b9f42e6f863c0174ce918490b6fcf0202 Signed-off-by: jiangyuwei --- components/plugins/renderer/webview_plugin.h | 1 + .../renderer_host/render_widget_host_impl.cc | 7 +++++ .../renderer_host/render_widget_host_impl.h | 1 + .../renderer_host/render_widget_host_view_aura.cc | 6 ++++ .../renderer_host/render_widget_host_view_aura.h | 1 + .../renderer_host/render_widget_host_view_base.h | 2 ++ content/public/browser/web_contents_delegate.h | 1 + .../public/mojom/widget/platform_widget.mojom | 3 ++ .../renderer/core/frame/web_frame_widget_impl.cc | 4 +++ .../renderer/core/frame/web_frame_widget_impl.h | 1 + .../blink/renderer/core/page/spatial_navigation.h | 12 ++++++++ .../core/page/spatial_navigation_controller.cc | 32 ++++++++++++++++++++++ .../core/page/spatial_navigation_controller.h | 1 + .../blink/renderer/platform/widget/widget_base.cc | 4 +++ .../blink/renderer/platform/widget/widget_base.h | 1 + .../renderer_host/rwhv_aura_common_helper_efl.cc | 5 ++++ .../renderer_host/rwhv_aura_common_helper_efl.h | 1 + .../ewk/efl_integration/eweb_view_callbacks.h | 4 +++ .../efl_integration/web_contents_delegate_efl.cc | 7 +++++ .../efl_integration/web_contents_delegate_efl.h | 1 + 20 files changed, 95 insertions(+) diff --git a/components/plugins/renderer/webview_plugin.h b/components/plugins/renderer/webview_plugin.h index 4d9c310..1ce8690 100644 --- a/components/plugins/renderer/webview_plugin.h +++ b/components/plugins/renderer/webview_plugin.h @@ -197,6 +197,7 @@ class WebViewPlugin : public blink::WebPlugin, public blink::WebViewObserver { void SetCursor(const ui::Cursor& cursor) override; #if BUILDFLAG(IS_TIZEN_TV) void DidEdgeScrollBy(const gfx::Point& point, bool handled) override {} + void MoveFocusToBrowser(int direction) override {} void NotifyTrackInfoToBrowser(int active_track_id, const std::string& url, const std::string& lang) override {} diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 474dd2d..e19024b 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -2902,6 +2902,13 @@ void RenderWidgetHostImpl::DidEdgeScrollBy(const gfx::Point& offset, bool handle view_->DidEdgeScrollBy(offset, handled); } +void RenderWidgetHostImpl::MoveFocusToBrowser(int direction) { + if (!GetView()) + return; + + view_->MoveFocusToBrowser(direction); +} + void RenderWidgetHostImpl::SetTranslatedURL(const std::string& url) { if (!blink_widget_) return; diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index d9abcd9..c542a51 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h @@ -322,6 +322,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl #if BUILDFLAG(IS_TIZEN_TV) //Browser edge scroll void DidEdgeScrollBy(const gfx::Point& point, bool handled) override; + void MoveFocusToBrowser(int direction) override; void NotifyTrackInfoToBrowser(int active_track_id, const std::string& url, const std::string& lang) override; diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index a3d24c3..8dc88b6 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -2364,6 +2364,12 @@ void RenderWidgetHostViewAura::DidEdgeScrollBy(const gfx::Point& offset, efl_helper_->DidEdgeScrollBy(offset, handled); } +void RenderWidgetHostViewAura::MoveFocusToBrowser(int direction) { + if (aura_efl_helper()) { + aura_efl_helper()->MoveFocusToBrowser(direction); + } +} + void RenderWidgetHostViewAura::NotifyTrackInfoToBrowser( int active_track_id, const std::string& url, diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 80bb89f..fa133fa 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h @@ -235,6 +235,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura #if BUILDFLAG(IS_TIZEN_TV) //Browser edge scroll void DidEdgeScrollBy(const gfx::Point& offset, bool handled) override ; + void MoveFocusToBrowser(int direction) override; void NotifyTrackInfoToBrowser(int active_track_id, const std::string& url, const std::string& lang) override; diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index 2b55acf..5076dde 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h @@ -507,6 +507,8 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView { #if BUILDFLAG(IS_TIZEN_TV) //Browser edge scroll virtual void DidEdgeScrollBy(const gfx::Point& offset, bool handled) {} + virtual void MoveFocusToBrowser(int direction) {} + // notify web browser video playing status virtual void VideoPlayingStatusReceived(bool is_playing, int callback_id) {} diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h index d2d66ab..57d3318 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h @@ -409,6 +409,7 @@ class CONTENT_EXPORT WebContentsDelegate { #if BUILDFLAG(IS_TIZEN_TV) virtual void DidEdgeScrollBy(const gfx::Point& offset, bool handled) {} + virtual void MoveFocusToBrowser(int direction) {} virtual void ShowMicOpenedNotification(bool show) {} #endif diff --git a/third_party/blink/public/mojom/widget/platform_widget.mojom b/third_party/blink/public/mojom/widget/platform_widget.mojom index 0f8367e..9c2cd90c 100644 --- a/third_party/blink/public/mojom/widget/platform_widget.mojom +++ b/third_party/blink/public/mojom/widget/platform_widget.mojom @@ -41,6 +41,9 @@ interface WidgetHost { //Browser edge scroll DidEdgeScrollBy(gfx.mojom.Point offset, bool handled); + [EnableIf=is_tizen_tv] + MoveFocusToBrowser(int32 direction); + // Sent by a widget to the browser to set the tooltip text for the current // cursor position. An empty |tooltip_text| will hide the tooltip view. UpdateTooltipUnderCursor(mojo_base.mojom.String16 tooltip_text, diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index beb29d0..153089a 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc @@ -5189,6 +5189,10 @@ void WebFrameWidgetImpl::NotifyTrackInfoToBrowser(int active_track_id, << " url:" << url << " lang:" << lang; widget_base_->NotifyTrackInfoToBrowser(active_track_id, url, lang); } + +void WebFrameWidgetImpl::MoveFocusToBrowser(int direction) { + widget_base_->MoveFocusToBrowser(direction); +} #endif #if BUILDFLAG(IS_TIZEN) diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h index c327506..64d8a9b 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h @@ -713,6 +713,7 @@ class CORE_EXPORT WebFrameWidgetImpl void NotifyTrackInfoToBrowser(int active_track_id, const std::string& url, const std::string& lang); + void MoveFocusToBrowser(int direction); #endif protected: diff --git a/third_party/blink/renderer/core/page/spatial_navigation.h b/third_party/blink/renderer/core/page/spatial_navigation.h index 5963970..c7de3c5 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation.h +++ b/third_party/blink/renderer/core/page/spatial_navigation.h @@ -35,6 +35,18 @@ class HTMLFrameOwnerElement; enum class SpatialNavigationDirection { kNone, kUp, kRight, kDown, kLeft }; +// The direction value in WebFocusType (before Tizen 5.5) is different from +// SpatialNavigationDirection. While ewk callback is using the int value of +// them, if can not change ewk interface then we need compatible adaptation +enum CompatibilityFocusType { + kFocusTypeNone = 0, + // Spatial navigation. + kFocusTypeUp = 3, + kFocusTypeDown, + kFocusTypeLeft, + kFocusTypeRight +}; + constexpr double kMaxDistance = std::numeric_limits::max(); CORE_EXPORT bool IsSpatialNavigationEnabled(const LocalFrame*); diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc index 47f16c4..fb654f4 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc @@ -37,6 +37,7 @@ #include "third_party/blink/renderer/core/css/style_change_reason.h" #if BUILDFLAG(IS_TIZEN_TV) +#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h" #include "third_party/blink/renderer/platform/keyboard_codes.h" #endif @@ -309,6 +310,25 @@ void SpatialNavigationController::Trace(Visitor* visitor) const { visitor->Trace(page_); } +int SpatialNavigationController::ToCompatibilityFocusType( + SpatialNavigationDirection direction) { + switch (direction) { + case SpatialNavigationDirection::kUp: + return CompatibilityFocusType::kFocusTypeUp; + case SpatialNavigationDirection::kDown: + return CompatibilityFocusType::kFocusTypeDown; + case SpatialNavigationDirection::kLeft: + return CompatibilityFocusType::kFocusTypeLeft; + case SpatialNavigationDirection::kRight: + return CompatibilityFocusType::kFocusTypeRight; + case SpatialNavigationDirection::kNone: + return CompatibilityFocusType::kFocusTypeNone; + default: + NOTREACHED(); + return CompatibilityFocusType::kFocusTypeNone; + } +} + bool SpatialNavigationController::Advance( SpatialNavigationDirection direction) { Node* interest_node = StartingNode(); @@ -357,6 +377,18 @@ bool SpatialNavigationController::Advance( document->UpdateStyleAndLayout(DocumentUpdateReason::kSpatialNavigation); } +#if BUILDFLAG(IS_TIZEN_TV) + Frame* frame = page_->GetFocusController().FocusedOrMainFrame(); + auto* local_frame = DynamicTo(frame); + if (!local_frame) + return false; + WebFrameWidgetImpl* wfwgt = + static_cast(local_frame->GetWidgetForLocalRoot()); + if (!wfwgt) + return false; + wfwgt->MoveFocusToBrowser(ToCompatibilityFocusType(direction)); +#endif + return false; } diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.h b/third_party/blink/renderer/core/page/spatial_navigation_controller.h index 5ec3087..922c340 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation_controller.h +++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.h @@ -55,6 +55,7 @@ class CORE_EXPORT SpatialNavigationController final #endif private: + int ToCompatibilityFocusType(SpatialNavigationDirection direction); // Entry-point into SpatialNavigation advancement. Will return true if an // action (moving interest or scrolling), false otherwise. bool Advance(SpatialNavigationDirection direction); diff --git a/third_party/blink/renderer/platform/widget/widget_base.cc b/third_party/blink/renderer/platform/widget/widget_base.cc index 5cd531a..d1446fe 100644 --- a/third_party/blink/renderer/platform/widget/widget_base.cc +++ b/third_party/blink/renderer/platform/widget/widget_base.cc @@ -1169,6 +1169,10 @@ void WidgetBase::DidEdgeScrollBy(const gfx::Point& offset, bool handled) { widget_host_->DidEdgeScrollBy(offset, handled); } +void WidgetBase::MoveFocusToBrowser(int direction) { + widget_host_->MoveFocusToBrowser(direction); +} + void WidgetBase::NotifyTrackInfoToBrowser(int active_track_id, const std::string& url, const std::string& lang) { diff --git a/third_party/blink/renderer/platform/widget/widget_base.h b/third_party/blink/renderer/platform/widget/widget_base.h index d385fc7..b260337 100644 --- a/third_party/blink/renderer/platform/widget/widget_base.h +++ b/third_party/blink/renderer/platform/widget/widget_base.h @@ -266,6 +266,7 @@ class PLATFORM_EXPORT WidgetBase : public mojom::blink::Widget, #if BUILDFLAG(IS_TIZEN_TV) //Browser edge scroll void DidEdgeScrollBy(const gfx::Point& offset, bool handled); + void MoveFocusToBrowser(int direction); void NotifyTrackInfoToBrowser(int active_track_id, const std::string& url, const std::string& lang); diff --git a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc index c9ad3a8..e9192bc 100644 --- a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc +++ b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc @@ -451,6 +451,11 @@ void RWHVAuraCommonHelperEfl::DidEdgeScrollBy(const gfx::Point& offset, web_contents_->GetDelegate()->DidEdgeScrollBy(offset, handled); } +void RWHVAuraCommonHelperEfl::MoveFocusToBrowser(int direction) { + if (web_contents_) + web_contents_->GetDelegate()->MoveFocusToBrowser(direction); +} + void RWHVAuraCommonHelperEfl::SetParentalRatingResult(const std::string& url, bool is_pass) { if (rwhv_aura_) diff --git a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h index d79c7c2..1c1ad6b 100644 --- a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h +++ b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h @@ -137,6 +137,7 @@ class CONTENT_EXPORT RWHVAuraCommonHelperEfl { #if BUILDFLAG(IS_TIZEN_TV) //Browser edge scroll void DidEdgeScrollBy(const gfx::Point& offset, bool handled); + void MoveFocusToBrowser(int direction); void SetPopupMenuVisible(const bool visible); void SetPopupMenuBounds(const gfx::Rect& popup_bounds); void SetCursorByClient(bool enable) { cursor_set_by_client_ = enable; } diff --git a/tizen_src/ewk/efl_integration/eweb_view_callbacks.h b/tizen_src/ewk/efl_integration/eweb_view_callbacks.h index 9a0ac17..06ed6a5 100644 --- a/tizen_src/ewk/efl_integration/eweb_view_callbacks.h +++ b/tizen_src/ewk/efl_integration/eweb_view_callbacks.h @@ -170,6 +170,7 @@ enum CallbackType { NewWindowNavigationPolicyDecision, #endif // IS_TIZEN #if BUILDFLAG(IS_TIZEN_TV) + AtkKeyEventNotHandled, HoverOverLink, HoverOutLink, ParentalRatingInfo, @@ -369,6 +370,9 @@ DECLARE_EWK_VIEW_CALLBACK(NewWindowNavigationPolicyDecision, "policy,decision,ne #if BUILDFLAG(IS_TIZEN_TV) DECLARE_EWK_VIEW_CALLBACK(ParentalRatingInfo, "on,parentalrating,info", void*); +DECLARE_EWK_VIEW_CALLBACK(AtkKeyEventNotHandled, + "atk,keyevent,nothandled", + int*); DECLARE_EWK_VIEW_CALLBACK(HoverOverLink, "hover,over,link", const char*); DECLARE_EWK_VIEW_CALLBACK(HoverOutLink, "hover,out,link", const char*); DECLARE_EWK_VIEW_CALLBACK(LoginFormSubmitted, diff --git a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc index 6c4c6e3..7eb7f0f 100644 --- a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc +++ b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc @@ -823,6 +823,13 @@ void WebContentsDelegateEfl::DidEdgeScrollBy(const gfx::Point& offset, web_view_->InvokeEdgeScrollByCallback(offset, handled); } +void WebContentsDelegateEfl::MoveFocusToBrowser(int direction) { + if (web_view_) { + web_view_->SmartCallback().call( + &direction); + } +} + void WebContentsDelegateEfl::WillDraw(int new_rotation, gfx::Size frame_data_output_size) { if (web_view_) { diff --git a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h index 5dc1bd5..4e1b834 100644 --- a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h +++ b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h @@ -77,6 +77,7 @@ class WebContentsDelegateEfl : public WebContentsDelegate { #if BUILDFLAG(IS_TIZEN_TV) //Browser edge scroll void DidEdgeScrollBy(const gfx::Point& offset, bool handled) override; + void MoveFocusToBrowser(int direction) override; void NotifyDownloadableFontInfo(const std::string& scheme_id_uri, const std::string& value, const std::string& data, -- 2.7.4 From da3845600fe150c21eb1a53399b3fd7e324a3dfa Mon Sep 17 00:00:00 2001 From: "peng.yin" Date: Thu, 13 Oct 2022 13:58:23 +0800 Subject: [PATCH 03/16] [M120 Migration][MM][WebRTC] Base implementation for webrtc video hole stream migrate the TizenEsPlusPlayerRenderer class from M108 who roles same as MmVideodecoder before, but it creates a self owned EsPlusPlayer by mojo renderer, and update the latest geometry change info to EsPlusPlayer. refer to: https://review.tizen.org/gerrit/#/c/291285/ Change-Id: I0743eb1202dfa261501a9fdf12b2d5d73c34fa39 Signed-off-by: peng.yin --- cc/layers/layer_impl.h | 4 + cc/layers/video_layer.cc | 36 +- cc/layers/video_layer.h | 21 +- cc/layers/video_layer_impl.cc | 41 +- cc/layers/video_layer_impl.h | 21 +- .../playback_command_forwarding_renderer.cc | 8 + media/base/pipeline_impl.cc | 2 +- media/base/renderer.h | 18 +- media/base/video_decoder_config.h | 22 +- media/base/video_frame.cc | 13 +- media/base/video_frame.h | 3 +- media/base/video_frame_metadata.cc | 3 + media/base/video_frame_metadata.h | 4 + media/filters/chunk_demuxer.cc | 2 + media/mojo/clients/mojo_demuxer_stream_impl.cc | 10 +- media/mojo/clients/mojo_renderer.cc | 44 +- media/mojo/clients/mojo_renderer.h | 10 +- media/mojo/clients/mojo_renderer_wrapper.cc | 10 +- media/mojo/clients/mojo_renderer_wrapper.h | 5 +- media/mojo/mojom/media_types.mojom | 1 + media/mojo/mojom/renderer.mojom | 29 +- media/mojo/mojom/renderer_extensions.mojom | 6 + .../mojom/video_decoder_config_mojom_traits.cc | 2 + .../mojo/mojom/video_decoder_config_mojom_traits.h | 4 + media/mojo/services/mojo_renderer_service.cc | 36 +- media/mojo/services/mojo_renderer_service.h | 11 +- .../modules/mediastream/web_media_stream_sink.h | 1 + .../web/modules/mediastream/webmediaplayer_ms.h | 7 + .../mediastream/local_video_capturer_source.cc | 14 +- .../modules/mediastream/webmediaplayer_ms.cc | 96 ++- .../mediastream/webmediaplayer_ms_compositor.cc | 36 + .../mediastream/webmediaplayer_ms_compositor.h | 2 +- third_party/blink/renderer/platform/media/BUILD.gn | 9 + .../platform/media/web_media_player_impl.cc | 7 +- .../peerconnection/webrtc_video_track_source.cc | 21 + .../platform/video_capture/video_capture_impl.cc | 65 ++ .../platform/video_capture/video_capture_impl.h | 15 + .../webrtc/convert_to_webrtc_video_frame_buffer.cc | 5 +- .../content/browser/media/tizen_renderer_impl.cc | 141 +++- .../content/browser/media/tizen_renderer_impl.h | 26 +- .../media/tizen/media_player_renderer_client.cc | 6 +- .../media/tizen/media_player_renderer_client.h | 3 +- .../audio/tizen/capi_usb_audio_input_stream.cc | 2 +- .../blink/renderer/tizen_esplusplayer_renderer.cc | 883 +++++++++++++++++++++ .../blink/renderer/tizen_esplusplayer_renderer.h | 304 +++++++ .../video/tizen/video_capture_device_tizen.cc | 7 +- .../media/filters/esplusplayer_util.cc | 5 + .../media/filters/media_player_esplusplayer_tv.cc | 170 +++- .../media/filters/media_player_esplusplayer_tv.h | 22 +- .../media/filters/media_player_tizen.h | 5 + tizen_src/chromium_impl/media/media_efl.gni | 12 + 51 files changed, 2162 insertions(+), 68 deletions(-) create mode 100644 tizen_src/chromium_impl/media/blink/renderer/tizen_esplusplayer_renderer.cc create mode 100644 tizen_src/chromium_impl/media/blink/renderer/tizen_esplusplayer_renderer.h diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 20c3639..ff4af40 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h @@ -472,6 +472,10 @@ class CC_EXPORT LayerImpl { // TODO(sunxd): Remove this function and replace it with visitor pattern. virtual bool is_surface_layer() const; +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + virtual absl::optional GetVideoId() const { return absl::nullopt; } +#endif + int CalculateJitter(); std::string DebugName() const; diff --git a/cc/layers/video_layer.cc b/cc/layers/video_layer.cc index 21b6d7d..9fb763f 100644 --- a/cc/layers/video_layer.cc +++ b/cc/layers/video_layer.cc @@ -10,13 +10,34 @@ namespace cc { scoped_refptr VideoLayer::Create( VideoFrameProvider* provider, - media::VideoTransformation transform) { - return base::WrapRefCounted(new VideoLayer(provider, transform)); + media::VideoTransformation transform +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + absl::optional player_id +#endif +) { + return base::WrapRefCounted(new VideoLayer(provider, transform +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + player_id +#endif + )); } VideoLayer::VideoLayer(VideoFrameProvider* provider, - media::VideoTransformation transform) - : provider_(provider), transform_(transform) { + media::VideoTransformation transform +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + absl::optional player_id +#endif + ) + : provider_(provider), + transform_(transform) +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + player_id_(player_id) +#endif +{ SetMayContainVideo(true); DCHECK(provider_.Read(*this)); } @@ -26,7 +47,12 @@ VideoLayer::~VideoLayer() = default; std::unique_ptr VideoLayer::CreateLayerImpl( LayerTreeImpl* tree_impl) const { return VideoLayerImpl::Create(tree_impl, id(), provider_.Read(*this), - transform_); + transform_ +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + player_id_ +#endif + ); } bool VideoLayer::RequiresSetNeedsDisplayOnHdrHeadroomChange() const { diff --git a/cc/layers/video_layer.h b/cc/layers/video_layer.h index c8f3ea4..9db97e9 100644 --- a/cc/layers/video_layer.h +++ b/cc/layers/video_layer.h @@ -24,7 +24,12 @@ class VideoLayerImpl; class CC_EXPORT VideoLayer : public Layer { public: static scoped_refptr Create(VideoFrameProvider* provider, - media::VideoTransformation transform); + media::VideoTransformation transform +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + absl::optional player_id +#endif + ); VideoLayer(const VideoLayer&) = delete; VideoLayer& operator=(const VideoLayer&) = delete; @@ -37,9 +42,17 @@ class CC_EXPORT VideoLayer : public Layer { // Clears |provider_| to ensure it is not used after destruction. void StopUsingProvider(); + media::VideoTransformation GetTransform() const { return transform_; } + private: VideoLayer(VideoFrameProvider* provider, - media::VideoTransformation transform); + media::VideoTransformation transform +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + absl::optional player_id +#endif + ); + ~VideoLayer() override; // This pointer is only for passing to VideoLayerImpl's constructor. It should @@ -47,6 +60,10 @@ class CC_EXPORT VideoLayer : public Layer { ProtectedSequenceReadable> provider_; const media::VideoTransformation transform_; + +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + absl::optional player_id_; +#endif }; } // namespace cc diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc index b51b823..01a9ade 100644 --- a/cc/layers/video_layer_impl.cc +++ b/cc/layers/video_layer_impl.cc @@ -38,7 +38,12 @@ std::unique_ptr VideoLayerImpl::Create( LayerTreeImpl* tree_impl, int id, VideoFrameProvider* provider, - const media::VideoTransformation& video_transform) { + const media::VideoTransformation& video_transform +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + absl::optional player_id +#endif +) { DCHECK(tree_impl->task_runner_provider()->IsMainThreadBlocked() || base::FeatureList::IsEnabled(features::kNonBlockingCommit)); DCHECK(tree_impl->task_runner_provider()->IsImplThread()); @@ -48,17 +53,32 @@ std::unique_ptr VideoLayerImpl::Create( provider, tree_impl->GetVideoFrameControllerClient()); return base::WrapUnique(new VideoLayerImpl( - tree_impl, id, std::move(provider_client_impl), video_transform)); + tree_impl, id, std::move(provider_client_impl), video_transform +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + player_id +#endif + )); } VideoLayerImpl::VideoLayerImpl( LayerTreeImpl* tree_impl, int id, scoped_refptr provider_client_impl, - const media::VideoTransformation& video_transform) + const media::VideoTransformation& video_transform +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + absl::optional player_id +#endif + ) : LayerImpl(tree_impl, id), provider_client_impl_(std::move(provider_client_impl)), - video_transform_(video_transform) { + video_transform_(video_transform) +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + player_id_(player_id) +#endif +{ set_may_contain_video(true); } @@ -82,7 +102,12 @@ VideoLayerImpl::~VideoLayerImpl() { std::unique_ptr VideoLayerImpl::CreateLayerImpl( LayerTreeImpl* tree_impl) const { return base::WrapUnique(new VideoLayerImpl( - tree_impl, id(), provider_client_impl_, video_transform_)); + tree_impl, id(), provider_client_impl_, video_transform_ +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + player_id_ +#endif + )); } void VideoLayerImpl::DidBecomeActive() { @@ -348,6 +373,12 @@ int VideoLayerImpl::render_target_effect_tree_index() const { } return LayerImpl::render_target_effect_tree_index(); } + +#if BUILDFLAG(IS_TIZEN_TV) +absl::optional VideoLayerImpl::GetVideoId() const { + return player_id_; +} +#endif // BUILDFLAG(IS_TIZEN_TV) #endif void VideoLayerImpl::SetNeedsRedraw() { diff --git a/cc/layers/video_layer_impl.h b/cc/layers/video_layer_impl.h index 4aac591..237fc8c 100644 --- a/cc/layers/video_layer_impl.h +++ b/cc/layers/video_layer_impl.h @@ -37,7 +37,12 @@ class CC_EXPORT VideoLayerImpl : public LayerImpl { LayerTreeImpl* tree_impl, int id, VideoFrameProvider* provider, - const media::VideoTransformation& video_transform); + const media::VideoTransformation& video_transform +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + absl::optional player_id +#endif + ); VideoLayerImpl(const VideoLayerImpl&) = delete; ~VideoLayerImpl() override; @@ -57,6 +62,9 @@ class CC_EXPORT VideoLayerImpl : public LayerImpl { gfx::ContentColorUsage GetContentColorUsage() const override; #if defined(TIZEN_VIDEO_HOLE) int render_target_effect_tree_index() const override; +#if BUILDFLAG(IS_TIZEN_TV) + absl::optional GetVideoId() const override; +#endif // BUILDFLAG(IS_TIZEN_TV) #endif void SetNeedsRedraw(); @@ -74,7 +82,12 @@ class CC_EXPORT VideoLayerImpl : public LayerImpl { LayerTreeImpl* tree_impl, int id, scoped_refptr provider_client_impl, - const media::VideoTransformation& video_transform); + const media::VideoTransformation& video_transform +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + absl::optional player_id +#endif + ); const char* LayerTypeAsString() const override; @@ -94,6 +107,10 @@ class CC_EXPORT VideoLayerImpl : public LayerImpl { media::VideoTransformation video_transform_; +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + absl::optional player_id_; +#endif + #if defined(TIZEN_TBM_SUPPORT) scoped_refptr context_provider_; viz::ResourceId resource_id_; diff --git a/components/cast_streaming/renderer/control/playback_command_forwarding_renderer.cc b/components/cast_streaming/renderer/control/playback_command_forwarding_renderer.cc index ccf00d8..4255a37 100644 --- a/components/cast_streaming/renderer/control/playback_command_forwarding_renderer.cc +++ b/components/cast_streaming/renderer/control/playback_command_forwarding_renderer.cc @@ -43,6 +43,14 @@ class RendererCommandForwarder : public media::mojom::Renderer { ~RendererCommandForwarder() override = default; // media::mojom::Renderer overrides. +#if defined(TIZEN_MULTIMEDIA) + void EnableLowLatencyMode() override {} + void SetHardwareResource( + media::mojom::HardwareResourceConfig config, + media::mojom::Renderer::SetHardwareResourceCallback) override {} + void RequestVideoDecodedBuffer( + media::mojom::Renderer::RequestVideoDecodedBufferCallback cb) override {} +#endif void Initialize( ::mojo::PendingAssociatedRemote client, absl::optional< diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc index b33eec4..a026dd0 100644 --- a/media/base/pipeline_impl.cc +++ b/media/base/pipeline_impl.cc @@ -712,7 +712,7 @@ void PipelineImpl::RendererWrapper::SetCdm(CdmContext* cdm_context, void PipelineImpl::RendererWrapper::SetMediaGeometry(const gfx::RectF rect_f) { LOG(INFO) << __func__; if (shared_state_.renderer) - shared_state_.renderer->SetMediaGeometry(rect_f); + shared_state_.renderer->SetMediaGeometry(rect_f, media::VIDEO_ROTATION_0); } #endif diff --git a/media/base/renderer.h b/media/base/renderer.h index 133476d..e32caab 100644 --- a/media/base/renderer.h +++ b/media/base/renderer.h @@ -22,6 +22,11 @@ namespace media { class CdmContext; class MediaResource; class RendererClient; +#if defined(TIZEN_MULTIMEDIA) +namespace mojom { +enum class HardwareResourceConfig; +} +#endif // Types of media::Renderer. // WARNING: These values are reported to metrics. Entries should not be @@ -97,18 +102,29 @@ class MEDIA_EXPORT Renderer { #if defined(TIZEN_MULTIMEDIA) virtual void Seek(base::TimeDelta time, base::OnceClosure seek_cb) {} virtual void Suspend() {} + virtual void EnableLowLatencyMode() {} + using SetHardwareResourceCB = base::OnceCallback; + virtual void SetHardwareResource(media::mojom::HardwareResourceConfig config, + SetHardwareResourceCB cb) {} + using RequestVideoDecodedBufferCB = base::OnceCallback; + virtual void RequestVideoDecodedBuffer(RequestVideoDecodedBufferCB cb) {} using ToggledFullscreenCB = base::OnceCallback; virtual void ToggleFullscreenMode(bool is_fullscreen, ToggledFullscreenCB cb) {} #endif #if defined(TIZEN_VIDEO_HOLE) + virtual void SetPlayerVideoAbove(int32_t other_id) {} + virtual void UseSubsurfaceController() {} virtual void SetVideoHole(bool is_video_hole) {} - virtual void SetMediaGeometry(const gfx::RectF& rect) {} + virtual void SetMediaGeometry(const gfx::RectF& rect, + media::VideoRotation rotation) {} #endif using StartDateCB = base::OnceCallback; #if BUILDFLAG(IS_TIZEN_TV) + using GetVideoIdCB = base::OnceCallback; + virtual void GetVideoId(GetVideoIdCB cb) {} virtual void SetContentMimeType(const std::string& mime_type) {} virtual void SetParentalRatingResult(bool is_pass) {} virtual void SetActiveTextTrack(int id, bool is_in_band) {} diff --git a/media/base/video_decoder_config.h b/media/base/video_decoder_config.h index 436cfc0..c288349 100644 --- a/media/base/video_decoder_config.h +++ b/media/base/video_decoder_config.h @@ -24,6 +24,13 @@ namespace media { +#if defined(TIZEN_MULTIMEDIA) +constexpr auto kFHDVideoMaxWidth = 1920; +constexpr auto kFHDVideoMaxHeight = 1080; +constexpr auto k8KVideoMaxWidth = 7680; +constexpr auto k8KVideoMaxHeight = 4320; +#endif + // Describes the content of a video stream, as described by the media container // (or otherwise determined by the demuxer). class MEDIA_EXPORT VideoDecoderConfig { @@ -167,10 +174,16 @@ class MEDIA_EXPORT VideoDecoderConfig { #if BUILDFLAG(IS_TIZEN_TV) void set_hdr_info(const std::string& hdr_info) { hdr_info_ = hdr_info; } const std::string& hdr_info() const { return hdr_info_; } - void set_framerate_num(const int num) { framerate_num_ = num; } - void set_framerate_den(const int den) { framerate_den_ = den; } + void set_framerate_num(int num) { framerate_num_ = num; } + void set_framerate_den(int den) { framerate_den_ = den; } + void set_enable_manual_copy(bool enable) { enable_manual_copy_ = enable; } int framerate_num() const { return framerate_num_; } int framerate_den() const { return framerate_den_; } + bool enable_manual_copy() const { return enable_manual_copy_; } +#endif +#if defined(TIZEN_MULTIMEDIA) + void set_max_coded_size(gfx::Size size) { max_coded_size_ = size; } + const gfx::Size& max_coded_size() const { return max_coded_size_; } #endif private: @@ -201,9 +214,14 @@ class MEDIA_EXPORT VideoDecoderConfig { bool is_rtc_ = false; #if BUILDFLAG(IS_TIZEN_TV) + bool needs_raw_access_ = false; int framerate_num_ = 0; int framerate_den_ = 0; std::string hdr_info_; + bool enable_manual_copy_{false}; +#endif +#if defined(TIZEN_MULTIMEDIA) + gfx::Size max_coded_size_{k8KVideoMaxWidth, k8KVideoMaxHeight}; #endif // Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index e7f03f7..87d60b3 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc @@ -521,8 +521,17 @@ scoped_refptr VideoFrame::WrapExternalData( const gfx::Size& natural_size, const uint8_t* data, size_t data_size, - base::TimeDelta timestamp) { - auto layout = GetDefaultLayout(format, coded_size); + base::TimeDelta timestamp, + size_t encoded_data_size) { + absl::optional layout; + if (format == PIXEL_FORMAT_ENCODED) { + auto plane = media::ColorPlaneLayout(encoded_data_size, 0, data_size); + layout = media::VideoFrameLayout::CreateWithPlanes(format, coded_size, + {std::move(plane)}); + } else { + layout = GetDefaultLayout(format, coded_size); + } + if (!layout) return nullptr; return WrapExternalDataWithLayout(*layout, visible_rect, natural_size, data, diff --git a/media/base/video_frame.h b/media/base/video_frame.h index 3ed6fec..f31ae5b 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h @@ -262,7 +262,8 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe { const gfx::Size& natural_size, const uint8_t* data, size_t data_size, - base::TimeDelta timestamp); + base::TimeDelta timestamp, + size_t encoded_data_size = 0); static scoped_refptr WrapExternalDataWithLayout( const VideoFrameLayout& layout, diff --git a/media/base/video_frame_metadata.cc b/media/base/video_frame_metadata.cc index 24d2844..3a64c017 100644 --- a/media/base/video_frame_metadata.cc +++ b/media/base/video_frame_metadata.cc @@ -70,6 +70,9 @@ void VideoFrameMetadata::MergeMetadataFrom( MERGE_OPTIONAL_FIELD(receive_time, metadata_source); MERGE_OPTIONAL_FIELD(wallclock_frame_duration, metadata_source); MERGE_OPTIONAL_FIELD(maximum_composition_delay_in_frames, metadata_source); +#if BUILDFLAG(IS_TIZEN_TV) + MERGE_OPTIONAL_FIELD(player_id, metadata_source); +#endif #undef MERGE_VALUE_FIELD #undef MERGE_OPTIONAL_FIELD diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h index b14a94a..82a2b0a 100644 --- a/media/base/video_frame_metadata.h +++ b/media/base/video_frame_metadata.h @@ -216,6 +216,10 @@ struct MEDIA_EXPORT VideoFrameMetadata { // This is an experimental feature, see crbug.com/1138888 for more // information. absl::optional maximum_composition_delay_in_frames; + +#if BUILDFLAG(IS_TIZEN_TV) + absl::optional player_id; +#endif }; } // namespace media diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index df72051..8daa31a 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc @@ -375,6 +375,8 @@ void ChunkDemuxerStream::CompletePendingReadIfPossible_Locked() { switch (state_) { case UNINITIALIZED: + if (stream_->GetCurrentVideoDecoderConfig().is_rtc()) + return; NOTREACHED_NORETURN(); case RETURNING_ABORT_FOR_READS: // Null buffers should be returned in this state since we are waiting diff --git a/media/mojo/clients/mojo_demuxer_stream_impl.cc b/media/mojo/clients/mojo_demuxer_stream_impl.cc index f4b26f7..7afeabe 100644 --- a/media/mojo/clients/mojo_demuxer_stream_impl.cc +++ b/media/mojo/clients/mojo_demuxer_stream_impl.cc @@ -96,8 +96,14 @@ void MojoDemuxerStreamImpl::OnBufferReady( #if defined(TIZEN_MULTIMEDIA) if (status == Status::kNeedBuffer) { - LOG(INFO) << __func__ << " (" << media::DemuxerStream::GetTypeName(stream_->type()) - << ") kNeedBuffer!"; + static int64_t log_second = -1; + int64_t log_second_now = + (base::TimeTicks::Now() - base::TimeTicks()).InSeconds(); + bool log_on = (log_second != log_second_now); + log_second = log_second_now; + LOG_IF(INFO, log_on) << __func__ << " (" + << media::DemuxerStream::GetTypeName(stream_->type()) + << ") kNeedBuffer!"; std::move(callback).Run(Status::kNeedBuffer, {}, audio_config, video_config); return; diff --git a/media/mojo/clients/mojo_renderer.cc b/media/mojo/clients/mojo_renderer.cc index 148a8b3..8c7ff42 100644 --- a/media/mojo/clients/mojo_renderer.cc +++ b/media/mojo/clients/mojo_renderer.cc @@ -256,14 +256,27 @@ base::TimeDelta MojoRenderer::GetMediaTime() { } #if defined(TIZEN_VIDEO_HOLE) +void MojoRenderer::SetPlayerVideoAbove(int32_t other_id) { + DVLOG(2) << __func__; + BindRemoteRendererIfNeeded(); + remote_renderer_->SetPlayerVideoAbove(other_id); +} + +void MojoRenderer::UseSubsurfaceController() { + DVLOG(2) << __func__; + BindRemoteRendererIfNeeded(); + remote_renderer_->UseSubsurfaceController(); +} + void MojoRenderer::SetVideoHole(bool is_video_hole) { BindRemoteRendererIfNeeded(); remote_renderer_->SetVideoHole(is_video_hole); } -void MojoRenderer::SetMediaGeometry(const gfx::RectF& rect) { +void MojoRenderer::SetMediaGeometry(const gfx::RectF& rect, + VideoRotation rotation) { if (remote_renderer_.is_bound()) - remote_renderer_->SetMediaGeometry(rect); + remote_renderer_->SetMediaGeometry(rect, rotation); } #endif @@ -271,6 +284,26 @@ RendererType MojoRenderer::GetRendererType() { return RendererType::kMojo; } +#if defined(TIZEN_MULTIMEDIA) +void MojoRenderer::EnableLowLatencyMode() { + LOG(INFO) << __func__; + if (remote_renderer_.is_bound()) + remote_renderer_->EnableLowLatencyMode(); +} + +void MojoRenderer::SetHardwareResource(mojom::HardwareResourceConfig config, + SetHardwareResourceCB cb) { + LOG(INFO) << __func__; + if (remote_renderer_.is_bound()) + remote_renderer_->SetHardwareResource(config, std::move(cb)); +} + +void MojoRenderer::RequestVideoDecodedBuffer(RequestVideoDecodedBufferCB cb) { + if (remote_renderer_.is_bound()) + remote_renderer_->RequestVideoDecodedBuffer(std::move(cb)); +} +#endif + void MojoRenderer::OnTimeUpdate(base::TimeDelta time, base::TimeDelta max_time, base::TimeTicks capture_time) { @@ -344,6 +377,13 @@ void MojoRenderer::OnStatisticsUpdate(const PipelineStatistics& stats) { } #if BUILDFLAG(IS_TIZEN_TV) +void MojoRenderer::GetVideoId(GetVideoIdCB cb) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + + if (remote_renderer_.is_bound()) + remote_renderer_->GetVideoId(std::move(cb)); +} + void MojoRenderer::SetContentMimeType(const std::string& mime_type) { DVLOG(2) << __func__ << " mime_type : " << mime_type; DCHECK(task_runner_->RunsTasksInCurrentSequence()); diff --git a/media/mojo/clients/mojo_renderer.h b/media/mojo/clients/mojo_renderer.h index 8ae441e..5bf3a50 100644 --- a/media/mojo/clients/mojo_renderer.h +++ b/media/mojo/clients/mojo_renderer.h @@ -62,6 +62,10 @@ class MojoRenderer : public Renderer, public mojom::RendererClient { #if defined(TIZEN_MULTIMEDIA) void Seek(base::TimeDelta time, base::OnceClosure seek_cb) override; void Suspend() override; + void EnableLowLatencyMode() override; + void SetHardwareResource(mojom::HardwareResourceConfig config, + SetHardwareResourceCB cb) override; + void RequestVideoDecodedBuffer(RequestVideoDecodedBufferCB cb) override; void ToggleFullscreenMode(bool is_fullscreen, ToggledFullscreenCB cb) override; #endif @@ -72,11 +76,15 @@ class MojoRenderer : public Renderer, public mojom::RendererClient { RendererType GetRendererType() override; #if defined(TIZEN_VIDEO_HOLE) + void SetPlayerVideoAbove(int32_t other_id) override; + void UseSubsurfaceController() override; void SetVideoHole(bool is_video_hole) override; - void SetMediaGeometry(const gfx::RectF& rect) override; + void SetMediaGeometry(const gfx::RectF& rect, + VideoRotation rotation) override; #endif #if BUILDFLAG(IS_TIZEN_TV) + void GetVideoId(GetVideoIdCB cb) override; void SetContentMimeType(const std::string& mime_type) override; void SetParentalRatingResult(bool is_pass) override; void SetActiveTextTrack(int id, bool is_in_band) override; diff --git a/media/mojo/clients/mojo_renderer_wrapper.cc b/media/mojo/clients/mojo_renderer_wrapper.cc index f5dee67..bff94b6 100644 --- a/media/mojo/clients/mojo_renderer_wrapper.cc +++ b/media/mojo/clients/mojo_renderer_wrapper.cc @@ -67,8 +67,9 @@ void MojoRendererWrapper::SetVideoHole(bool is_video_hole) { mojo_renderer_->SetVideoHole(is_video_hole); } -void MojoRendererWrapper::SetMediaGeometry(const gfx::RectF& rect) { - mojo_renderer_->SetMediaGeometry(rect); +void MojoRendererWrapper::SetMediaGeometry(const gfx::RectF& rect, + VideoRotation rotation) { + mojo_renderer_->SetMediaGeometry(rect, rotation); } #endif @@ -77,6 +78,11 @@ base::TimeDelta MojoRendererWrapper::GetMediaTime() { } #if BUILDFLAG(IS_TIZEN_TV) +void MojoRendererWrapper::GetVideoId(GetVideoIdCB cb) { + if (mojo_renderer_) + mojo_renderer_->GetVideoId(std::move(cb)); +} + void MojoRendererWrapper::SetContentMimeType(const std::string& mime_type) { if (mojo_renderer_) mojo_renderer_->SetContentMimeType(mime_type); diff --git a/media/mojo/clients/mojo_renderer_wrapper.h b/media/mojo/clients/mojo_renderer_wrapper.h index 4bf07fe..1dc7c14 100644 --- a/media/mojo/clients/mojo_renderer_wrapper.h +++ b/media/mojo/clients/mojo_renderer_wrapper.h @@ -45,11 +45,14 @@ class MojoRendererWrapper : public Renderer { #if defined(TIZEN_VIDEO_HOLE) void SetVideoHole(bool is_video_hole) override; - void SetMediaGeometry(const gfx::RectF& rect) override; + void SetMediaGeometry(const gfx::RectF& rect, + VideoRotation rotation) override; #endif #if BUILDFLAG(IS_TIZEN_TV) using StartDateCB = base::OnceCallback; + using GetVideoIdCB = base::OnceCallback; + void GetVideoId(GetVideoIdCB cb) override; void SetContentMimeType(const std::string& mime_type) override; void SetParentalRatingResult(bool is_pass) override; void SetActiveTextTrack(int id, bool is_in_band) override; diff --git a/media/mojo/mojom/media_types.mojom b/media/mojo/mojom/media_types.mojom index d86cdf8..7ea0505 100644 --- a/media/mojo/mojom/media_types.mojom +++ b/media/mojo/mojom/media_types.mojom @@ -196,6 +196,7 @@ struct VideoDecoderConfig { EncryptionScheme encryption_scheme; VideoColorSpace color_space_info; gfx.mojom.HDRMetadata? hdr_metadata; + bool is_rtc; [EnableIf=is_tizen_tv] string hdr_info; [EnableIf=is_tizen_tv] diff --git a/media/mojo/mojom/renderer.mojom b/media/mojo/mojom/renderer.mojom index b6aaaf0..79a0f93 100644 --- a/media/mojo/mojom/renderer.mojom +++ b/media/mojo/mojom/renderer.mojom @@ -23,6 +23,15 @@ struct MediaUrlParams { bool is_hls; }; +[EnableIf=tizen_multimedia] +enum HardwareResourceConfig { + kMainDecoderMainScaler = 0, + kSubDecoderSubScaler, + kSubDecoderMainScaler, + kMainDecoderSubScaler, + kNone, +}; + // A Mojo equivalent of media::Renderer. Used when audio and video decoding // happens outside of the sandboxed render process. // See media/mojo/README.md @@ -60,10 +69,25 @@ interface Renderer { SetCdm(mojo_base.mojom.UnguessableToken? cdm_id) => (bool success); [EnableIf=tizen_video_hole] + SetPlayerVideoAbove(int32 other_id); + + [EnableIf=tizen_video_hole] + UseSubsurfaceController(); + + [EnableIf=tizen_video_hole] SetVideoHole(bool is_video_hole); [EnableIf=tizen_video_hole] - SetMediaGeometry(gfx.mojom.RectF rect); + SetMediaGeometry(gfx.mojom.RectF rect, VideoRotation rotation); + + [EnableIf=tizen_multimedia] + EnableLowLatencyMode(); + + [EnableIf=tizen_multimedia] + SetHardwareResource(HardwareResourceConfig config) => (bool success); + + [EnableIf=tizen_multimedia] + RequestVideoDecodedBuffer() => (bool success); [EnableIf=tizen_multimedia] ToggleFullscreenMode(bool is_fullscreen) => (); @@ -72,6 +96,9 @@ interface Renderer { SetContentMimeType(string mime_type); [EnableIf=is_tizen_tv] + GetVideoId()=> (int32 player_id); + + [EnableIf=is_tizen_tv] SetParentalRatingResult(bool is_pass); [EnableIf=is_tizen_tv] diff --git a/media/mojo/mojom/renderer_extensions.mojom b/media/mojo/mojom/renderer_extensions.mojom index 966f077..b4a775c 100644 --- a/media/mojo/mojom/renderer_extensions.mojom +++ b/media/mojo/mojom/renderer_extensions.mojom @@ -102,6 +102,12 @@ interface MediaPlayerRendererExtension { [EnableIf=tizen_tbm_support] OnTbmBufferExhausted(gfx.mojom.TbmBufferHandle tbm_buffer_handle); + + [EnableIf=is_tizen_tv] + EnableTbmBufferCallback(bool enabled); + + [EnableIf=is_tizen_tv] + SetCallBackFrameSize(gfx.mojom.Size size); }; // Extension of the mojo::RendererClient communication layer for media flinging, diff --git a/media/mojo/mojom/video_decoder_config_mojom_traits.cc b/media/mojo/mojom/video_decoder_config_mojom_traits.cc index ed74736..dcf30fa 100644 --- a/media/mojo/mojom/video_decoder_config_mojom_traits.cc +++ b/media/mojo/mojom/video_decoder_config_mojom_traits.cc @@ -63,6 +63,8 @@ bool StructTraitsset_level(input.level()); + output->set_is_rtc(input.is_rtc()); + #if BUILDFLAG(IS_TIZEN_TV) std::string hdr; if (!input.ReadHdrInfo(&hdr)) diff --git a/media/mojo/mojom/video_decoder_config_mojom_traits.h b/media/mojo/mojom/video_decoder_config_mojom_traits.h index 5dff94d..204c0ab 100644 --- a/media/mojo/mojom/video_decoder_config_mojom_traits.h +++ b/media/mojo/mojom/video_decoder_config_mojom_traits.h @@ -74,6 +74,10 @@ struct StructTraitsSuspend(); } +void MojoRendererService::EnableLowLatencyMode() { + DVLOG(2) << __func__; + renderer_->EnableLowLatencyMode(); +} + +void MojoRendererService::SetHardwareResource( + media::mojom::HardwareResourceConfig config, + mojom::Renderer::SetHardwareResourceCallback cb) { + DVLOG(2) << __func__; + renderer_->SetHardwareResource(config, std::move(cb)); +} + +void MojoRendererService::RequestVideoDecodedBuffer( + mojom::Renderer::RequestVideoDecodedBufferCallback cb) { + renderer_->RequestVideoDecodedBuffer(std::move(cb)); +} + void MojoRendererService::ToggleFullscreenMode( bool is_fullscreen, ToggleFullscreenModeCallback callback) { @@ -178,12 +195,21 @@ void MojoRendererService::SetCdm( } #if defined(TIZEN_VIDEO_HOLE) +void MojoRendererService::SetPlayerVideoAbove(int32_t other_id) { + renderer_->SetPlayerVideoAbove(other_id); +} + +void MojoRendererService::UseSubsurfaceController() { + renderer_->UseSubsurfaceController(); +} + void MojoRendererService::SetVideoHole(bool is_video_hole) { renderer_->SetVideoHole(is_video_hole); } -void MojoRendererService::SetMediaGeometry(const gfx::RectF& rect) { - renderer_->SetMediaGeometry(rect); +void MojoRendererService::SetMediaGeometry(const gfx::RectF& rect, + VideoRotation rotation) { + renderer_->SetMediaGeometry(rect, rotation); } #endif @@ -210,6 +236,12 @@ void MojoRendererService::OnStatisticsUpdate(const PipelineStatistics& stats) { } #if BUILDFLAG(IS_TIZEN_TV) +void MojoRendererService::GetVideoId(GetVideoIdCallback cb) { + DVLOG(3) << __func__; + if (renderer_) + renderer_->GetVideoId(std::move(cb)); +} + void MojoRendererService::SetContentMimeType(const std::string& mime_type) { DVLOG(3) << __func__ << ", mime_type: " << mime_type; if (renderer_) diff --git a/media/mojo/services/mojo_renderer_service.h b/media/mojo/services/mojo_renderer_service.h index c4ced5f..4ddd5a5 100644 --- a/media/mojo/services/mojo_renderer_service.h +++ b/media/mojo/services/mojo_renderer_service.h @@ -68,6 +68,12 @@ class MEDIA_MOJO_EXPORT MojoRendererService final : public mojom::Renderer, #if defined(TIZEN_MULTIMEDIA) void Seek(base::TimeDelta time, base::OnceClosure seek_cb) final; void Suspend() final; + void EnableLowLatencyMode() final; + void SetHardwareResource( + media::mojom::HardwareResourceConfig config, + mojom::Renderer::SetHardwareResourceCallback cb) final; + void RequestVideoDecodedBuffer( + mojom::Renderer::RequestVideoDecodedBufferCallback cb) final; void ToggleFullscreenMode(bool is_fullscreen, ToggleFullscreenModeCallback callback) final; #endif @@ -79,10 +85,13 @@ class MEDIA_MOJO_EXPORT MojoRendererService final : public mojom::Renderer, #if defined(TIZEN_VIDEO_HOLE) void SetVideoHole(bool is_video_hole) final; - void SetMediaGeometry(const gfx::RectF& rect) final; + void SetMediaGeometry(const gfx::RectF& rect, VideoRotation rotation) final; + void SetPlayerVideoAbove(int32_t other_id) final; + void UseSubsurfaceController() final; #endif #if BUILDFLAG(IS_TIZEN_TV) + void GetVideoId(GetVideoIdCallback cb) final; void SetContentMimeType(const std::string& mime_type) final; void SetParentalRatingResult(bool is_pass) final; void SetActiveTextTrack(int id, bool is_in_band) final; diff --git a/third_party/blink/public/platform/modules/mediastream/web_media_stream_sink.h b/third_party/blink/public/platform/modules/mediastream/web_media_stream_sink.h index 263cbea..e30f95c 100644 --- a/third_party/blink/public/platform/modules/mediastream/web_media_stream_sink.h +++ b/third_party/blink/public/platform/modules/mediastream/web_media_stream_sink.h @@ -9,6 +9,7 @@ #include "third_party/blink/public/platform/modules/mediastream/web_media_stream_source.h" #include "third_party/blink/public/platform/modules/mediastream/web_media_stream_track.h" #include "third_party/blink/public/platform/web_common.h" +#include "ui/gfx/geometry/rect_f.h" namespace blink { diff --git a/third_party/blink/public/web/modules/mediastream/webmediaplayer_ms.h b/third_party/blink/public/web/modules/mediastream/webmediaplayer_ms.h index ac40925..36d2c4e 100644 --- a/third_party/blink/public/web/modules/mediastream/webmediaplayer_ms.h +++ b/third_party/blink/public/web/modules/mediastream/webmediaplayer_ms.h @@ -187,6 +187,9 @@ class BLINK_MODULES_EXPORT WebMediaPlayerMS bool is_opaque); void OnOpacityChanged(bool is_opaque); void OnTransformChanged(media::VideoTransformation video_transform); +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + void SetPlayerId(int id); +#endif // defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) // WebMediaStreamObserver implementation void TrackAdded(const WebString& track_id) override; @@ -349,6 +352,10 @@ class BLINK_MODULES_EXPORT WebMediaPlayerMS // Whether the use of a surface layer instead of a video layer is enabled. bool use_surface_layer_ = false; +#if BUILDFLAG(IS_TIZEN_TV) + int player_id_{0}; +#endif + // Owns the weblayer and obtains/maintains SurfaceIds for // kUseSurfaceLayerForVideo feature. std::unique_ptr bridge_; diff --git a/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.cc b/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.cc index dfbbff4..f4796ac 100644 --- a/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.cc +++ b/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.cc @@ -138,18 +138,30 @@ void LocalVideoCapturerSource::OnStateUpdate(blink::VideoCaptureState state) { case VIDEO_CAPTURE_STATE_ERROR: case VIDEO_CAPTURE_STATE_ERROR_SYSTEM_PERMISSIONS_DENIED: case VIDEO_CAPTURE_STATE_ERROR_CAMERA_BUSY: - case VIDEO_CAPTURE_STATE_ENDED: + case VIDEO_CAPTURE_STATE_ENDED: { + // |release_device_cb_| will unref device by one, and UseDevice will ref + // device by one, call |release_device_cb_| first will cause a unnecessary + // device re-creating opt. for currently camera preview playback solution, + // geometry info from renderer may be missed durnning device recreating. +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_MULTIMEDIA) + base::OnceClosure post_release_device_cb = std::move(release_device_cb_); +#else std::move(release_device_cb_).Run(); +#endif release_device_cb_ = frame && frame->Client() ? manager_->UseDevice(session_id_, &frame->GetBrowserInterfaceBroker()) : base::DoNothing(); +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_MULTIMEDIA) + std::move(post_release_device_cb).Run(); +#endif OnLog( "LocalVideoCapturerSource::OnStateUpdate signaling to " "consumer that source is no longer running."); running_callback_.Run(run_state); break; + } case VIDEO_CAPTURE_STATE_STARTING: case VIDEO_CAPTURE_STATE_PAUSED: diff --git a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc index bb3277e..cd2f694 100644 --- a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc +++ b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc @@ -56,6 +56,10 @@ #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_media.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" +#if defined(TIZEN_VIDEO_HOLE) +#include "ui/gfx/geometry/rect_f.h" +#endif + #if BUILDFLAG(IS_TIZEN) #include "tizen/system_info.h" #endif @@ -189,6 +193,63 @@ class WebMediaPlayerMS::FrameDeliverer { void OnVideoFrame(scoped_refptr frame) { DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_); +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + if (frame->metadata().player_id.has_value()) { + const int player_id = frame->metadata().player_id.value_or(0); + if (player_id != player_id_) { + player_id_ = player_id; + main_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&WebMediaPlayerMS::SetPlayerId, player_, + player_id_)); + } + if (frame->format() == media::PIXEL_FORMAT_ENCODED) { + auto orig_frame = frame; + frame = media::VideoFrame::CreateHoleFrame(orig_frame->natural_size()); + frame->set_timestamp(orig_frame->timestamp()); + frame->metadata().player_id = player_id_; + } + } + + // Make new frame in case there is any TBM buffer attached to prevent + // keeping the buffer in case when rendering stalls + if (frame->storage_type() == media::VideoFrame::STORAGE_HOLE) { +#if defined(TIZEN_TBM_SUPPORT) + if (frame->format() == media::PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER && + request_frame_in_progress_) { + base::AutoLock auto_lock(request_buffer_lock_); + scoped_refptr decoded_video_frame = + media::VideoFrame::WrapExternalYuvData( + media::VideoPixelFormat::PIXEL_FORMAT_NV12, frame->coded_size(), + frame->visible_rect(), frame->natural_size(), + frame->stride(media::VideoFrame::kYPlane), + frame->stride(media::VideoFrame::kUVPlane), + frame->GetWritableVisibleData(media::VideoFrame::kYPlane), + frame->GetWritableVisibleData(media::VideoFrame::kUVPlane), + frame->timestamp()); + request_frame_in_progress_ = false; + if (decoded_video_frame) { + decoded_video_frame->metadata().MergeMetadataFrom(frame->metadata()); + decoded_frame_cb_.Run(std::move(decoded_video_frame)); + } + } +#endif // defined(TIZEN_TBM_SUPPORT) + auto orig_frame = frame; + frame = media::VideoFrame::CreateHoleFrame(orig_frame->natural_size()); + frame->set_timestamp(orig_frame->timestamp()); + frame->metadata().MergeMetadataFrom(orig_frame->metadata()); + EnqueueFrame(orig_frame->unique_id(), std::move(frame)); + return; + } else if (frame->metadata().end_of_stream) { + // create a hole frame to prevent renderer from reading the dirty data in + // eos frame + auto orig_frame = frame; + frame = media::VideoFrame::CreateHoleFrame(orig_frame->natural_size()); + frame->set_timestamp(orig_frame->timestamp()); + frame->metadata().MergeMetadataFrom(orig_frame->metadata()); + EnqueueFrame(orig_frame->unique_id(), std::move(frame)); + return; + } +#endif // defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) // On Android, stop passing frames. #if BUILDFLAG(IS_ANDROID) @@ -330,6 +391,20 @@ class WebMediaPlayerMS::FrameDeliverer { weak_factory_for_pool_.InvalidateWeakPtrs(); } +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_TBM_SUPPORT) + void RequestVideoDecodedBuffer() { + base::AutoLock auto_lock(request_buffer_lock_); + request_frame_in_progress_ = true; + } + + RequestCB decoded_frame_cb_; + base::Lock request_buffer_lock_; + bool request_frame_in_progress_ = false; +#endif + +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + int player_id_{0}; +#endif // defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) bool render_frame_suspended_ = false; const scoped_refptr main_task_runner_; @@ -1313,12 +1388,31 @@ void WebMediaPlayerMS::OnTransformChanged( // Keep the old |video_layer_| alive until SetCcLayer() is called with a new // pointer, as it may use the pointer from the last call. auto new_video_layer = - cc::VideoLayer::Create(compositor_.get(), video_transform); + cc::VideoLayer::Create(compositor_.get(), video_transform +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + absl::optional(player_id_) +#endif + ); + get_client()->SetCcLayer(new_video_layer.get()); video_layer_ = std::move(new_video_layer); } } +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) +void WebMediaPlayerMS::SetPlayerId(int player_id) { + LOG(INFO) << __func__ << " player_id: " << player_id; + player_id_ = player_id; + + if (video_layer_) { + // If we have a video_layer_ already, then we need to call + // OnTransformChanged to reset it with new player_id_. + OnTransformChanged(video_layer_->GetTransform()); + } +} +#endif // defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + bool WebMediaPlayerMS::IsInPictureInPicture() const { DCHECK(client_); return (!client_->IsInAutoPIP() && diff --git a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc index 745f009..337cf39 100644 --- a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc +++ b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc @@ -39,6 +39,11 @@ #include "third_party/libyuv/include/libyuv/video_common.h" #include "third_party/skia/include/core/SkSurface.h" +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE) && \ + defined(TIZEN_MULTIMEDIA) +#include "media/blink/renderer/tizen_esplusplayer_renderer.h" +#endif + namespace WTF { template @@ -299,6 +304,37 @@ WebMediaPlayerMSCompositor::Metadata WebMediaPlayerMSCompositor::GetMetadata() { return current_metadata_; } +#if defined(TIZEN_VIDEO_HOLE) +void WebMediaPlayerMSCompositor::OnDrawableContentRectChanged( + const gfx::Rect& rect) { +#if BUILDFLAG(IS_TIZEN_TV) + media::VideoRotation rotation = media::VIDEO_ROTATION_0; + if (current_frame_ && current_frame_->metadata().transformation.has_value()) + rotation = current_frame_->metadata().transformation.value().rotation; + + std::int32_t player_id{0}; + { + base::AutoLock auto_lock(current_frame_lock_); + if (current_frame_) { + player_id = current_frame_->metadata().player_id.value_or(0); + } + } + + LOG(INFO) << "WebMediaPlayerMSCompositor::OnDrawableContentRectChanged: " + << ", player id:" << player_id << ", rect:" << rect.ToString() + << ", rotation " << media::VideoRotationToString(rotation); + + if (player_id != 0) { +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE) && \ + defined(TIZEN_MULTIMEDIA) + media::TizenEsPlusPlayerRendererManager::GetInstance() + .OnVideoSinkGeometryChange(player_id, gfx::RectF{rect}, rotation); +#endif + } +#endif // BUILDFLAG(IS_TIZEN_TV) +} +#endif // defined(TIZEN_VIDEO_HOLE) + void WebMediaPlayerMSCompositor::SetForceSubmit(bool force_submit) { DCHECK(video_frame_compositor_task_runner_->BelongsToCurrentThread()); submitter_->SetForceSubmit(force_submit); diff --git a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h index c6d73a6..9b81ccb 100644 --- a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h +++ b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h @@ -153,7 +153,7 @@ class MODULES_EXPORT WebMediaPlayerMSCompositor DrawableContentRectChangedCallback cb) override {} // Notifies the client of video plane geometry to be use. - void OnDrawableContentRectChanged(const gfx::Rect&) override {} + void OnDrawableContentRectChanged(const gfx::Rect& rect) override; #endif private: diff --git a/third_party/blink/renderer/platform/media/BUILD.gn b/third_party/blink/renderer/platform/media/BUILD.gn index 7062313..4a6bb85 100644 --- a/third_party/blink/renderer/platform/media/BUILD.gn +++ b/third_party/blink/renderer/platform/media/BUILD.gn @@ -4,6 +4,10 @@ import("//media/media_options.gni") +if (tizen_multimedia) { + import("//tizen_src/chromium_impl/media/media_efl.gni") +} + # TODO(https://crbug.com/1198341): use blink_platform_sources once the code is # ported to Blink code conventions. component("media") { @@ -108,6 +112,11 @@ component("media") { "hls_data_source_provider_impl.h", ] } + + if (tizen_multimedia) { + configs += external_media_efl_blink_config + sources += external_media_efl_blink_sources + } } source_set("unit_tests") { diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.cc b/third_party/blink/renderer/platform/media/web_media_player_impl.cc index 1542bc1..f11a400 100644 --- a/third_party/blink/renderer/platform/media/web_media_player_impl.cc +++ b/third_party/blink/renderer/platform/media/web_media_player_impl.cc @@ -2104,7 +2104,12 @@ void WebMediaPlayerImpl::OnMetadata(const media::PipelineMetadata& metadata) { DCHECK(!video_layer_); video_layer_ = cc::VideoLayer::Create( compositor_.get(), - pipeline_metadata_.video_decoder_config.video_transformation()); + pipeline_metadata_.video_decoder_config.video_transformation() +#if defined(TIZEN_VIDEO_HOLE) && BUILDFLAG(IS_TIZEN_TV) + , + absl::nullopt +#endif + ); video_layer_->SetContentsOpaque(opaque_); client_->SetCcLayer(video_layer_.get()); } diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc index d3218bc3..ef39ad3 100644 --- a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc +++ b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc @@ -10,6 +10,7 @@ #include "base/trace_event/trace_event.h" #include "base/types/optional_util.h" #include "media/base/media_switches.h" +#include "media/base/video_types.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.h" #include "third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h" @@ -223,6 +224,26 @@ void WebRtcVideoTrackSource::OnFrameCaptured( webrtc::Timestamp::Micros(frame->timestamp().InMicroseconds()); } +#if BUILDFLAG(IS_TIZEN) + if (frame->format() == media::PIXEL_FORMAT_ENCODED +#if defined(TIZEN_VIDEO_HOLE) + || frame->storage_type() == media::VideoFrame::STORAGE_HOLE +#endif + ) { + // The webrtc::VideoFrame::UpdateRect expected by WebRTC must + // be relative to the |visible_rect()|. We need to translate. + absl::optional cropped_rect; + if (accumulated_update_rect_) { + cropped_rect = + CropRectangle(*accumulated_update_rect_, frame->visible_rect()); + } + + DeliverFrame(std::move(frame), base::OptionalToPtr(cropped_rect), + translated_camera_time_us, capture_time_identifier); + return; + } +#endif + // Translate the |crop_*| values output by AdaptFrame() from natural size to // visible size. This is needed to apply the new cropping on top of any // existing soft-applied cropping and scaling when using diff --git a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc index 68bbcb5..0fcf81e 100644 --- a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc +++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc @@ -854,7 +854,14 @@ void VideoCaptureImpl::StopCapture(int client_id) { DVLOG(1) << "StopCapture: No more client, stopping ..."; StopDevice(); client_buffers_.clear(); +#if !BUILDFLAG(IS_TIZEN_TV) && !defined(TIZEN_MULTIMEDIA) + // the current weak ptr is owned by capture impl manager, and this capture + // impl instance shall not be able to re-start again by invalidate weak ptr. + // it is supposed to re-creating capture impl instead, but re-creating is + // skipped on tizen tv product, so remove this line to make it available + // to respond to the follow-up callings. weak_factory_.InvalidateWeakPtrs(); +#endif } void VideoCaptureImpl::RequestRefreshFrame() { @@ -940,7 +947,10 @@ void VideoCaptureImpl::OnStateChanged( OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_STOPPED"); state_ = VIDEO_CAPTURE_STATE_STOPPED; client_buffers_.clear(); +#if !BUILDFLAG(IS_TIZEN_TV) && !defined(TIZEN_MULTIMEDIA) + // see comments in StopCapture weak_factory_.InvalidateWeakPtrs(); +#endif if (!clients_.empty() || !clients_pending_on_restart_.empty()) { OnLog("VideoCaptureImpl restarting capture"); RestartCapture(); @@ -1026,6 +1036,28 @@ void VideoCaptureImpl::OnBufferReady( (reference_time - base::TimeTicks()).InMicroseconds(), "time_delta", buffer->info->timestamp.InMicroseconds()); +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE) && \ + defined(TIZEN_MULTIMEDIA) + // push shared buffer handle to tizen esplusplayer renderer + const auto& iter = client_buffers_.find(buffer->buffer_id); + DCHECK(iter != client_buffers_.end()); + scoped_refptr buffer_context = iter->second; + if (buffer_context->buffer_type() == + VideoFrameBufferHandleType::kUnsafeShmemRegion && + buffer->info->pixel_format == media::PIXEL_FORMAT_ENCODED) { + if (renderer_ && renderer_->IsReady()) { + renderer_->QueueBuffer(buffer->info->metadata, buffer->info->coded_size, + buffer_context->data(), + buffer->info->encoded_data_size, + true /* key frame */); + GetVideoCaptureHost()->ReleaseBuffer(device_id_, buffer->buffer_id, + media::VideoCaptureFeedback()); + return; + } + LOG(INFO) << "renderer is not exists, or not prepared."; + } +#endif + // Create and initialize frame preparers for the non-scaled and the scaled // frames. auto frame_preparer = @@ -1076,6 +1108,18 @@ void VideoCaptureImpl::BindVideoFrameOnMediaThread( std::move(on_frame_ready_callback).Run(std::move(frame_preparer)); } +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE) && \ + defined(TIZEN_MULTIMEDIA) +void VideoCaptureImpl::OnVideoFrameReadyFromRenderer( + scoped_refptr frame, + base::TimeTicks reference_time) { + DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_); + for (const auto& client : clients_) { + client.second.deliver_frame_cb.Run(frame, reference_time); + } +} +#endif + void VideoCaptureImpl::OnVideoFrameReady( base::TimeTicks reference_time, std::unique_ptr frame_preparer) { @@ -1217,6 +1261,27 @@ void VideoCaptureImpl::StartCaptureInternal() { } start_outcome_reported_ = false; base::UmaHistogramBoolean("Media.VideoCapture.Start", true); +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE) && \ + defined(TIZEN_MULTIMEDIA) + const media::VideoCodec codec = + (params_.requested_format.pixel_format == media::PIXEL_FORMAT_ENCODED + ? media::VideoCodec::kH264 + : media::VideoCodec::kMJPEG); + if (!renderer_) + renderer_ = media::TizenEsPlusPlayerRendererManager::GetInstance() + .CreateTizenEsPlusPlayerRenderer( + codec, gfx::Size(1920, 1080), + media::HardwareResouceType::kSub, /* sub-scaler */ + media::HardwareResouceType::kMain, /* main-decoder */ + media::CanDropFrames::kYes, media::Mode::kVideoHole, + base::DoNothing(), + base::BindPostTaskToCurrentDefault(base::BindRepeating( + &VideoCaptureImpl::OnVideoFrameReadyFromRenderer, + base::Unretained(this))), + true /* do not handle sink changes by listener */, + true /* enable espp manual copy */); +#endif // BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE) && + // defined(TIZEN_MULTIMEDIA) GetVideoCaptureHost()->Start(device_id_, session_id_, params_, observer_receiver_.BindNewPipeAndPassRemote()); diff --git a/third_party/blink/renderer/platform/video_capture/video_capture_impl.h b/third_party/blink/renderer/platform/video_capture/video_capture_impl.h index b0d9da0..bf4fb98 100644 --- a/third_party/blink/renderer/platform/video_capture/video_capture_impl.h +++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl.h @@ -29,6 +29,11 @@ #include "third_party/blink/renderer/platform/allow_discouraged_type.h" #include "third_party/blink/renderer/platform/platform_export.h" +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE) && \ + defined(TIZEN_MULTIMEDIA) +#include "media/blink/renderer/tizen_esplusplayer_renderer.h" +#endif + namespace base { class SequencedTaskRunner; } // namespace base @@ -201,6 +206,11 @@ class PLATFORM_EXPORT VideoCaptureImpl base::OnceCallback)> on_frame_ready_callback, base::OnceCallback on_gpu_context_lost); +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE) && \ + defined(TIZEN_MULTIMEDIA) + void OnVideoFrameReadyFromRenderer(scoped_refptr frame, + base::TimeTicks reference_time); +#endif void OnVideoFrameReady( base::TimeTicks reference_time, std::unique_ptr frame_preparer); @@ -309,6 +319,11 @@ class PLATFORM_EXPORT VideoCaptureImpl THREAD_CHECKER(io_thread_checker_); base::OneShotTimer startup_timeout_; +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE) && \ + defined(TIZEN_MULTIMEDIA) + std::unique_ptr renderer_; +#endif // BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE) && + // defined(TIZEN_MULTIMEDIA) base::WeakPtr weak_this_; // WeakPtrFactory pointing back to |this| object, for use with diff --git a/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc b/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc index fa8aaca..770f54b 100644 --- a/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc +++ b/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc @@ -285,7 +285,10 @@ bool CanConvertToWebRtcVideoFrameBuffer(const media::VideoFrame* frame) { frame->format())) || frame->storage_type() == media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER || - frame->HasTextures(); +#if defined(TIZEN_VIDEO_HOLE) + frame->storage_type() == media::VideoFrame::STORAGE_HOLE || +#endif + frame->format() == media::PIXEL_FORMAT_ENCODED || frame->HasTextures(); } // static diff --git a/tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.cc b/tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.cc index 7278fa9..51abec6 100644 --- a/tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.cc +++ b/tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.cc @@ -62,6 +62,8 @@ TizenRendererImpl::TizenRendererImpl( video_rect_(gfx::RectF()), #endif #if BUILDFLAG(IS_TIZEN_TV) + is_low_latency_(false), + hw_res_cfg_(-1), notify_playback_state_(media::kPlaybackStop), #endif renderer_extension_receiver_(this, @@ -232,11 +234,20 @@ void TizenRendererImpl::SetPlayerInitialize() { #if defined(TIZEN_VIDEO_HOLE) if (is_video_hole_) { SetPlayerVideoHole(); - SetPlayerMediaGeometry(); + SetPlayerMediaGeometry(media::VIDEO_ROTATION_0); } #endif media_player_->Initialize(sink_); + +#if BUILDFLAG(IS_TIZEN_TV) + if (is_low_latency_) { + EnablePlayerLowLatencyMode(); + } + if (hw_res_cfg_ != -1) { + SetPlayerHardwareResource(hw_res_cfg_); + } +#endif } void TizenRendererImpl::SetPlayerPrepare() { @@ -294,6 +305,24 @@ void TizenRendererImpl::Seek(base::TimeDelta time, base::OnceClosure seek_cb) { } #if defined(TIZEN_VIDEO_HOLE) +void TizenRendererImpl::SetPlayerVideoAbove(int32_t other_id) { + if (media_player_) { + media_player_->SetPlayerVideoAbove(other_id); + } +} + +void TizenRendererImpl::UseSubsurfaceController() { + if (use_subsurface_controller_ == true) { + LOG(INFO) << "Skip same setting."; + return; + } + + if (media_player_) { + media_player_->UseSubsurfaceController(); + use_subsurface_controller_ = true; + } +} + void TizenRendererImpl::SetVideoHole(bool is_video_hole) { if (is_video_hole_ == is_video_hole) return; @@ -307,15 +336,17 @@ void TizenRendererImpl::SetPlayerVideoHole() { media_player_->SetVideoHole(is_video_hole_); } -void TizenRendererImpl::SetMediaGeometry(const gfx::RectF& rect) { +void TizenRendererImpl::SetMediaGeometry(const gfx::RectF& rect, + media::VideoRotation rotation) { if (video_rect_ == rect) return; video_rect_ = rect; - SetPlayerMediaGeometry(); + video_rotation_ = rotation; + SetPlayerMediaGeometry(rotation); } -void TizenRendererImpl::SetPlayerMediaGeometry() { +void TizenRendererImpl::SetPlayerMediaGeometry(media::VideoRotation rotation) { if (media_player_) { // Always get the latest viewport rect. media_player_->SetMediaGeometry(GetViewportRect(), video_rect_); @@ -343,7 +374,7 @@ gfx::Rect TizenRendererImpl::GetViewportRect() const { void TizenRendererImpl::OnWebViewMoved() { if (media_player_) { LOG_ID(INFO, player_id_) << __func__ << " Reset WebView-Position."; - SetPlayerMediaGeometry(); + SetPlayerMediaGeometry(video_rotation_); } } #endif @@ -370,7 +401,72 @@ void TizenRendererImpl::Suspend() { is_suspended_ = true; } +void TizenRendererImpl::EnableLowLatencyMode() { +#if BUILDFLAG(IS_TIZEN_TV) + if (is_low_latency_) + return; + + is_low_latency_ = true; + EnablePlayerLowLatencyMode(); +#endif +} + +int ToPlayerHardwareResourceConfig( + media::mojom::HardwareResourceConfig config) { + switch (config) { + case media::mojom::HardwareResourceConfig::kMainDecoderMainScaler: + return 0; + case media::mojom::HardwareResourceConfig::kSubDecoderSubScaler: + return 1; + case media::mojom::HardwareResourceConfig::kSubDecoderMainScaler: + return 2; + case media::mojom::HardwareResourceConfig::kMainDecoderSubScaler: + return 3; + default: + return -1; + } +} + +void TizenRendererImpl::SetHardwareResource( + media::mojom::HardwareResourceConfig config, + SetHardwareResourceCB cb) { +#if BUILDFLAG(IS_TIZEN_TV) + int player_cfg = ToPlayerHardwareResourceConfig(config); + if (player_cfg == -1) { + LOG(ERROR) << "Invalid config."; + std::move(cb).Run(false); + return; + } + + if (hw_res_cfg_ == player_cfg) { + std::move(cb).Run(true); + return; + } + hw_res_cfg_ = player_cfg; + SetPlayerHardwareResource(player_cfg); +#endif + std::move(cb).Run(true); +} + #if BUILDFLAG(IS_TIZEN_TV) +void TizenRendererImpl::EnablePlayerLowLatencyMode() { + if (!media_player_) { + LOG_ID(ERROR, player_id_) << "media_player_ is not created yet"; + return; + } + + media_player_->EnableLowLatencyMode(); +} + +void TizenRendererImpl::SetPlayerHardwareResource(int config) { + if (!media_player_) { + LOG_ID(ERROR, player_id_) << "media_player_ is not created yet"; + return; + } + + media_player_->SetHardwareResource(config); +} + void TizenRendererImpl::SetActiveTextTrack(int id, bool is_in_band) { LOG_ID(INFO, player_id_) << "(" << static_cast(this) << ") " << __func__ << " " << id << "/ " << is_in_band; @@ -438,6 +534,18 @@ content::WebContentsDelegate* TizenRendererImpl::GetWebContentsDelegate() } #endif +void TizenRendererImpl::RequestVideoDecodedBuffer( + RequestVideoDecodedBufferCB cb) { + if (!media_player_) { + LOG_ID(ERROR, player_id_) << "media_player_ is not created yet"; + std::move(cb).Run(false); + return; + } + + media_player_->RequestVideoDecodedBuffer(); + std::move(cb).Run(true); +} + void TizenRendererImpl::ToggleFullscreenMode(bool is_fullscreen, ToggledFullscreenCB cb) { if (media_player_) @@ -539,6 +647,7 @@ void TizenRendererImpl::OnStatisticsUpdate( const media::PipelineStatistics& stats) { NOTIMPLEMENTED(); } + #if BUILDFLAG(IS_TIZEN_TV) void TizenRendererImpl::NotifyTrackInfoToBrowser(int active_track_id) { LOG_ID(INFO, player_id_) @@ -657,7 +766,27 @@ void TizenRendererImpl::OnLivePlaybackComplete() { } client_->OnLivePlaybackComplete(); } -#endif + +void TizenRendererImpl::GetVideoId(GetVideoIdCB cb) { + std::move(cb).Run(player_id_); +} + +void TizenRendererImpl::EnableTbmBufferCallback(bool enable) { + if (!media_player_) { + LOG_ID(ERROR, player_id_) << "media_player_ is not created yet"; + return; + } + media_player_->EnableTbmBufferCallback(enable); +} + +void TizenRendererImpl::SetCallBackFrameSize(const gfx::Size& size) { + if (!media_player_) { + LOG_ID(ERROR, player_id_) << "media_player_ is not created yet"; + return; + } + media_player_->SetCallBackFrameSize(size); +} +#endif // BUILDFLAG(IS_TIZEN_TV) void TizenRendererImpl::OnSeekableTimeChange(base::TimeDelta min_time, base::TimeDelta max_time, diff --git a/tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.h b/tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.h index e45d45a..6753740 100644 --- a/tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.h +++ b/tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.h @@ -17,6 +17,7 @@ #include "media/base/renderer_client.h" #include "media/base/video_renderer_sink.h" #include "media/base/waiting.h" +#include "media/mojo/mojom/renderer.mojom.h" #include "media/mojo/mojom/renderer_extensions.mojom.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -87,11 +88,19 @@ class CONTENT_EXPORT TizenRendererImpl void OnUpdateAudioMutingState(bool muted) {} void OnWebContentsDestroyed(); - void Seek(base::TimeDelta time, base::OnceClosure seek_cb); + void Seek(base::TimeDelta time, base::OnceClosure seek_cb) override; void Suspend() override; + void EnableLowLatencyMode() override; + void SetHardwareResource(media::mojom::HardwareResourceConfig config, + SetHardwareResourceCB cb) override; + void RequestVideoDecodedBuffer(RequestVideoDecodedBufferCB cb) override; void ToggleFullscreenMode(bool is_fullscreen, ToggledFullscreenCB cb) final; +#if defined(TIZEN_VIDEO_HOLE) + void SetPlayerVideoAbove(int32_t other_id) override; + void UseSubsurfaceController() override; +#endif // MediaPlayerTizenClient implementation. void OnError(media::PipelineStatus error) override; @@ -130,6 +139,9 @@ class CONTENT_EXPORT TizenRendererImpl std::string* drm_info = NULL) override; void UpdateCurrentTime(base::TimeDelta current_time) override; void OnLivePlaybackComplete() override; + void GetVideoId(GetVideoIdCB cb) override; + void SetCallBackFrameSize(const gfx::Size& size) override; + void EnableTbmBufferCallback(bool enable) override; #endif #if defined(TIZEN_TBM_SUPPORT) @@ -152,7 +164,8 @@ class CONTENT_EXPORT TizenRendererImpl #if defined(TIZEN_VIDEO_HOLE) void SetVideoHole(bool is_video_hole) final; - void SetMediaGeometry(const gfx::RectF& rect) final; + void SetMediaGeometry(const gfx::RectF& rect, + media::VideoRotation rotation) final; gfx::Rect GetViewportRect() const; #endif @@ -182,10 +195,12 @@ class CONTENT_EXPORT TizenRendererImpl void SetPlayerPrepare(); #if defined(TIZEN_VIDEO_HOLE) void SetPlayerVideoHole(); - void SetPlayerMediaGeometry(); + void SetPlayerMediaGeometry(media::VideoRotation rotation); void OnWebViewMoved(); #endif #if BUILDFLAG(IS_TIZEN_TV) + void EnablePlayerLowLatencyMode(); + void SetPlayerHardwareResource(int config); void SetActiveTextTrack(int id, bool is_in_band) override; void SetActiveAudioTrack(int index) override; void SetActiveVideoTrack(int index) override; @@ -242,11 +257,16 @@ class CONTENT_EXPORT TizenRendererImpl bool is_suspended_ = false; #if defined(TIZEN_VIDEO_HOLE) + bool use_subsurface_controller_ = false; bool is_video_hole_ = false; gfx::RectF video_rect_; + media::VideoRotation video_rotation_ = media::VIDEO_ROTATION_0; #endif #if BUILDFLAG(IS_TIZEN_TV) + bool is_low_latency_; + int hw_res_cfg_; + int notify_playback_state_; // Stores the mime type. Required for URL streams which are DASH // content, so that we can set it to the media_player_ before calling diff --git a/tizen_src/chromium_impl/content/renderer/media/tizen/media_player_renderer_client.cc b/tizen_src/chromium_impl/content/renderer/media/tizen/media_player_renderer_client.cc index caf7284..7c8729e 100644 --- a/tizen_src/chromium_impl/content/renderer/media/tizen/media_player_renderer_client.cc +++ b/tizen_src/chromium_impl/content/renderer/media/tizen/media_player_renderer_client.cc @@ -75,8 +75,10 @@ void MediaPlayerRendererClient::SetVideoHole(bool is_video_hole) { MojoRendererWrapper::SetVideoHole(is_video_hole); } -void MediaPlayerRendererClient::SetMediaGeometry(const gfx::RectF& rect) { - MojoRendererWrapper::SetMediaGeometry(rect); +void MediaPlayerRendererClient::SetMediaGeometry( + const gfx::RectF& rect, + media::VideoRotation rotation) { + MojoRendererWrapper::SetMediaGeometry(rect, rotation); } #endif diff --git a/tizen_src/chromium_impl/content/renderer/media/tizen/media_player_renderer_client.h b/tizen_src/chromium_impl/content/renderer/media/tizen/media_player_renderer_client.h index 5109bf4..884695e 100644 --- a/tizen_src/chromium_impl/content/renderer/media/tizen/media_player_renderer_client.h +++ b/tizen_src/chromium_impl/content/renderer/media/tizen/media_player_renderer_client.h @@ -67,7 +67,8 @@ class CONTENT_EXPORT MediaPlayerRendererClient #if defined(TIZEN_VIDEO_HOLE) void SetVideoHole(bool is_video_hole) override; - void SetMediaGeometry(const gfx::RectF& rect) override; + void SetMediaGeometry(const gfx::RectF& rect, + media::VideoRotation rotation) override; #endif // media::mojom::MediaPlayerRendererClientExtension implementation diff --git a/tizen_src/chromium_impl/media/audio/tizen/capi_usb_audio_input_stream.cc b/tizen_src/chromium_impl/media/audio/tizen/capi_usb_audio_input_stream.cc index da4df17..a5653b0 100644 --- a/tizen_src/chromium_impl/media/audio/tizen/capi_usb_audio_input_stream.cc +++ b/tizen_src/chromium_impl/media/audio/tizen/capi_usb_audio_input_stream.cc @@ -60,7 +60,7 @@ bool CapiUsbAudioInputStream::OpenMic() { return false; } - int device_id = std::stoi(device_name_, nullptr, 0); + int device_id = std::atoi(device_name_.c_str()); sound_device_h device; sound_device_type_e device_type; sound_stream_type_e stream_type = SOUND_STREAM_TYPE_MEDIA_EXTERNAL_ONLY; diff --git a/tizen_src/chromium_impl/media/blink/renderer/tizen_esplusplayer_renderer.cc b/tizen_src/chromium_impl/media/blink/renderer/tizen_esplusplayer_renderer.cc new file mode 100644 index 0000000..306588d --- /dev/null +++ b/tizen_src/chromium_impl/media/blink/renderer/tizen_esplusplayer_renderer.cc @@ -0,0 +1,883 @@ +// Copyright 2022 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/blink/renderer/tizen_esplusplayer_renderer.h" + +#include "base/base_switches.h" +#include "base/command_line.h" +#include "base/functional/callback_forward.h" +#include "base/functional/callback_helpers.h" +#include "base/logging.h" +#include "base/time/time.h" +#include "base/trace_event/trace_event.h" +#include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_frame_visitor.h" +#include "content/renderer/media/media_interface_factory.h" +#include "media/base/video_codecs.h" +#include "media/renderers/video_overlay_factory.h" +// #include "ui/gfx/tbm_buffer_handle_inter_process.h" + +#if defined(ENABLE_AUTO_ZOOM) +#include "media/mojo/mojom/ai_zoom_settings.mojom.h" +#endif // defined(ENABLE_AUTO_ZOOM) + +#if defined(TIZEN_HW_ENCODER) && !defined(TIZEN_CAPI_ENCODER_TV_API) +#include "content/renderer/render_thread_impl.h" +#endif + +#define LOG_ID(severity) LOG(severity) << "[" << id_ << "]: " + +namespace { +class MainFrameFinder : public content::RenderFrameVisitor { + public: + content::RenderFrame* result{nullptr}; + bool Visit(content::RenderFrame* render_frame) final { + if (render_frame && render_frame->IsMainFrame()) { + result = render_frame; + return false; + } + return true; + } +}; +} // namespace + +namespace media { + +TizenEsPlusPlayerRendererManager::TizenEsPlusPlayerRendererManager() = default; + +TizenEsPlusPlayerRendererManager::~TizenEsPlusPlayerRendererManager() { + NOTREACHED(); +} + +// static +TizenEsPlusPlayerRendererManager& +TizenEsPlusPlayerRendererManager::GetInstance() { + static base::NoDestructor instance; + return *instance; +} + +std::unique_ptr +TizenEsPlusPlayerRendererManager::CreateTizenEsPlusPlayerRenderer( + media::VideoCodec codec, + gfx::Size init_size, + media::HardwareResouceType scaler_type, + media::HardwareResouceType decoder_type, + media::CanDropFrames can_drop_frames, + media::Mode mode, + media::InitCb init_cb, + media::FrameCb frame_cb, + bool has_id, + bool could_enable_user_data) { + base::AutoLock lk(lock_); + + // An instance with |renderer_id| equal to 0 means that it will update the + // geometry to ESPP by registering and responding to listener events. + auto selected_id = 0; + if (has_id) + selected_id = ++index_; + + auto id_iter = id_to_renderers_.find(selected_id); + if (id_iter != id_to_renderers_.end()) { + LOG(ERROR) << "Renderer already exists."; + return nullptr; + } + + if (!SelectHWResource(scaler_type, decoder_type, mode)) { + LOG(ERROR) << "Resource conflicts or invalid combination."; + return nullptr; + } + + auto renderer = base::WrapUnique(new TizenEsPlusPlayerRenderer( + codec, init_size, scaler_type, decoder_type, can_drop_frames, mode, + std::move(init_cb), std::move(frame_cb), selected_id, + could_enable_user_data)); + id_to_renderers_[selected_id] = renderer->GetWeakPtr(); + return renderer; +} + +base::WeakPtr +TizenEsPlusPlayerRendererManager::GetTizenEsPlusPlayerRenderer(int id) { + auto id_iter = id_to_renderers_.find(id); + if (id_iter == id_to_renderers_.end()) { + LOG(ERROR) << "Renderer does not exist:" << id; + return nullptr; + } + + auto renderer = id_to_renderers_[id]; + if (!renderer) { + LOG(ERROR) << "Renderer is invalid:" << id; + return nullptr; + } + + return renderer; +} + +void TizenEsPlusPlayerRendererManager::OnVideoSinkGeometryChange( + int id, + const gfx::RectF& rect, + media::VideoRotation rotation) { + base::AutoLock lk(lock_); + auto renderer = GetTizenEsPlusPlayerRenderer(id); + if (renderer) + renderer->OnVideoSinkGeometryChange(rect, rotation); +} + +void TizenEsPlusPlayerRendererManager::OnZOrderChanged( + int broadcast_id, + const std::vector& video_ids) { + base::AutoLock lk(lock_); + + size_t size = video_ids.size(); + if (size < 2) { + return; + } + + // Skip same z-order + if (video_ids_order_ == video_ids) { + return; + } + + for (size_t i = 0; i < size - 1; i++) { + auto renderer = GetTizenEsPlusPlayerRenderer(video_ids[i]); + if (!renderer) + continue; + + for (size_t j = i + 1; j < size; j++) { + auto renderer_other = GetTizenEsPlusPlayerRenderer(video_ids[j]); + if (!renderer_other) + continue; + renderer->SetPlayerVideoAbove(renderer_other->GetVideoId()); + break; + } + } + video_ids_order_ = video_ids; +} + +void TizenEsPlusPlayerRendererManager::RemoveTizenEsPlusPlayerRenderer(int id) { + base::AutoLock lk(lock_); + auto it = id_to_renderers_.find(id); + video_ids_order_.clear(); + if (it != id_to_renderers_.end()) + id_to_renderers_.erase(it); +} + +bool TizenEsPlusPlayerRendererManager::HasResourceConflict( + const media::SelectedResource& type) { + for (const auto& it : id_to_renderers_) { + if (it.second->selected_resource().first == type.first || + it.second->selected_resource().second == type.second) { + return true; + } + } + return false; +}; + +bool TizenEsPlusPlayerRendererManager::HasResourceConflictScaler( + const media::HardwareResouceType& type) { + for (const auto& it : id_to_renderers_) { + if (it.second->selected_resource().first == type) { + return true; + } + } + return false; +}; + +bool TizenEsPlusPlayerRendererManager::HasResourceConflictDecoder( + const media::HardwareResouceType& type) { + for (const auto& it : id_to_renderers_) { + if (it.second->selected_resource().second == type) { + return true; + } + } + return false; +}; + +bool TizenEsPlusPlayerRendererManager::SelectHWResource( + media::HardwareResouceType& scaler_type, + media::HardwareResouceType& decoder_type, + const media::Mode& mode) { + if (mode == media::Mode::kVideoHoleWithMappingBuffer && + scaler_type == media::HardwareResouceType::kSub) { + LOG(ERROR) << "Invalid combination, mode:" << static_cast(mode) + << " scaler_type:" << static_cast(scaler_type) + << " mode:" << static_cast(mode); + return false; + } + + if (HasResourceConflict({scaler_type, decoder_type})) { + return false; + } + + // select for scaler kAny case + if (scaler_type == media::HardwareResouceType::kAny) { + while (scaler_type != media::HardwareResouceType::kEnd) { + scaler_type = static_cast( + static_cast(scaler_type) + 1); + if (!HasResourceConflictScaler(scaler_type)) { + break; + } + } + } + if (scaler_type == media::HardwareResouceType::kEnd) { + return false; + } + + // select for decoder kAny case + if (decoder_type == media::HardwareResouceType::kAny) { + while (decoder_type != media::HardwareResouceType::kEnd) { + decoder_type = static_cast( + static_cast(decoder_type) + 1); + if (!HasResourceConflictDecoder(decoder_type)) { + break; + } + } + } + if (decoder_type == media::HardwareResouceType::kEnd) { + return false; + } + + return true; +} + +TizenEsPlusPlayerRenderer::TizenEsPlusPlayerRenderer( + media::VideoCodec codec, + gfx::Size init_size, + HardwareResouceType scaler_type, + HardwareResouceType decoder_type, + CanDropFrames can_drop_frames, + Mode mode, + InitCb init_cb, + FrameCb frame_cb, + int renderer_id, + bool could_enable_user_data) + : player_state_(Status::NONE), + codec_(codec), + current_frame_size_(init_size), + init_cb_(std::move(init_cb)), + frame_cb_(std::move(frame_cb)), + mode_(mode), + tbm_frame_in_use_(0), + pending_disable_tbm_(false), + id_(renderer_id), + could_enable_user_data_(could_enable_user_data) { + LOG_ID(INFO) << "Create renderer id:" << id_ + << " mode:" << static_cast(mode) + << " codec:" << static_cast(codec) + << " hardware scaler:" << static_cast(scaler_type) + << " hardware decoder:" << static_cast(decoder_type) + << " can_drop_frames:" << static_cast(can_drop_frames) + << " init size:" << init_size.ToString() + << " could_enable_user_data:" << could_enable_user_data; + log_ = std::make_unique(); + selected_resource_ = std::make_pair(scaler_type, decoder_type); + +#if defined(TIZEN_HW_ENCODER) && !defined(TIZEN_CAPI_ENCODER_TV_API) + GetScalerUsageManager(); +#endif + + // Unretained is safe because |this| will outlive |worker_task_runner_|. + worker_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&TizenEsPlusPlayerRenderer::Init, base::Unretained(this))); +} + +TizenEsPlusPlayerRenderer::~TizenEsPlusPlayerRenderer() { + // Make sure |mojo_renderer_| is deleted before |worker_task_runner_| on which + // all |mojo_renderer_| related task is running + base::WaitableEvent sync_with_worker_task_runner{ + base::WaitableEvent::ResetPolicy::MANUAL}; + worker_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&TizenEsPlusPlayerRenderer::ReleaseRendererOnWorkThread, + base::Unretained(this), &sync_with_worker_task_runner)); + sync_with_worker_task_runner.Wait(); + LOG_ID(INFO) << " Mojo renderer released."; +} + +void TizenEsPlusPlayerRenderer::DidTakeResources() { +#if defined(TIZEN_HW_ENCODER) && !defined(TIZEN_CAPI_ENCODER_TV_API) + if (scaler_manager_ && uses_subresource_.has_value() && + uses_subresource_.value()) + scaler_manager_->SetUsed(true); +#endif +} + +void TizenEsPlusPlayerRenderer::DidFreeResources() { +#if defined(TIZEN_HW_ENCODER) && !defined(TIZEN_CAPI_ENCODER_TV_API) + if (scaler_manager_ && uses_subresource_.has_value() && + uses_subresource_.value()) + scaler_manager_->SetUsed(false); +#endif +} + +void TizenEsPlusPlayerRenderer::SetGeometryOnWorkerThread( + const gfx::RectF& rect, + media::VideoRotation rotation) { + DCHECK(worker_task_runner_->BelongsToCurrentThread()); + mojo_renderer_->SetMediaGeometry(rect, rotation); +} + +void TizenEsPlusPlayerRenderer::StartPlayingOnWorkerThread( + base::TimeDelta time) { + DCHECK(worker_task_runner_->BelongsToCurrentThread()); + mojo_renderer_->StartPlayingFrom(time); + player_state_ = Status::PREPARED; +} + +void TizenEsPlusPlayerRenderer::ReleaseRendererOnWorkThread( + base::WaitableEvent* event) { + DCHECK(worker_task_runner_->BelongsToCurrentThread()); + media::TizenEsPlusPlayerRendererManager::GetInstance() + .RemoveTizenEsPlusPlayerRenderer(id_); + // invalidate all weak ptrs at once to prevent any task from running again. + weak_factory_.InvalidateWeakPtrs(); + mojo_renderer_.reset(); + renderer_extension_remote_.reset(); + client_extension_receiver_.reset(); + event->Signal(); +} + +void TizenEsPlusPlayerRenderer::OnHardwareResourcesComplete(bool success) { + LOG_ID(INFO) << " success:" << success; + DCHECK(worker_task_runner_->BelongsToCurrentThread()); + if (success && selected_resource_.first == HardwareResouceType::kSub) { + uses_subresource_ = true; + DidTakeResources(); + } +} + +#if defined(TIZEN_HW_ENCODER) && !defined(TIZEN_CAPI_ENCODER_TV_API) +void TizenEsPlusPlayerRenderer::GetScalerUsageManager() { + LOG_ID(INFO) << __func__; + base::WaitableEvent event{base::WaitableEvent::ResetPolicy::MANUAL}; + content::RenderThreadImpl::DeprecatedGetMainTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce( + [](base::WaitableEvent* event, media::ScalerUsageManager** manager) { + *manager = + content::RenderThreadImpl::current()->GetScalerUsageManager(); + event->Signal(); + }, + &event, &scaler_manager_)); + + event.Wait(); +} +#endif + +mojom::HardwareResourceConfig +TizenEsPlusPlayerRenderer::ToMojomHardwareResourceConfig( + SelectedResource types) { + if (types.first == HardwareResouceType::kMain) { + if (types.second == HardwareResouceType::kMain) { + return mojom::HardwareResourceConfig::kMainDecoderMainScaler; + } else if (types.second == HardwareResouceType::kSub) { + return mojom::HardwareResourceConfig::kSubDecoderMainScaler; + } + } else if (types.first == HardwareResouceType::kSub) { + if (types.second == HardwareResouceType::kMain) { + return mojom::HardwareResourceConfig::kMainDecoderSubScaler; + } else if (types.second == HardwareResouceType::kSub) { + return mojom::HardwareResourceConfig::kSubDecoderSubScaler; + } + } + return mojom::HardwareResourceConfig::kNone; +} + +void TizenEsPlusPlayerRenderer::SelectHardwareResources() { + LOG_ID(INFO) << __func__; + if (mode_ != Mode::kVideoHole && mode_ != Mode::kVideoHoleWithMappingBuffer) { + LOG_ID(INFO) << "Skip hardware resource selecting."; + return; + } + + mojom::HardwareResourceConfig cfg = + ToMojomHardwareResourceConfig(selected_resource_); + if (cfg == mojom::HardwareResourceConfig::kNone) { + LOG_ID(INFO) << "Invalid hardware resource selecting."; + return; + } + + mojo_renderer_->SetHardwareResource( + std::move(cfg), + base::BindOnce(&TizenEsPlusPlayerRenderer::OnHardwareResourcesComplete, + GetWeakPtr())); +} + +void TizenEsPlusPlayerRenderer::SetupBeforePlaying() { + LOG_ID(INFO) << __func__; + DCHECK(worker_task_runner_->BelongsToCurrentThread()); + + if (player_state_ != Status::INITIALISING) { + LOG_ID(ERROR) << "Wrong status."; + return; + } + + bool OffscreenRenderingEnabled = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableOffscreenRendering); + if (mode_ == Mode::kVideoHole || mode_ == Mode::kVideoHoleWithMappingBuffer) { + mojo_renderer_->SetVideoHole(true); + if (!OffscreenRenderingEnabled) { + LOG_ID(INFO) + << __func__ + << ", offscreen rendering is not enabled, use subsurface controller"; + mojo_renderer_->UseSubsurfaceController(); + } else { + // fixme: in this case (web browser), there will be z-order issues in dual + // decoder + LOG_ID(INFO) << __func__ + << ", offscreen rendering is enabled, can't use subsurface " + "controller"; + } + } + + mojo_renderer_->EnableLowLatencyMode(); + mojo_renderer_->SetPlaybackRate(1.0); + SelectHardwareResources(); + mojo_renderer_->GetVideoId(base::BindOnce( + &TizenEsPlusPlayerRenderer::OnGetVideoId, weak_factory_.GetWeakPtr())); +} + +VideoCodecProfile TizenEsPlusPlayerRenderer::GetCodecProfile(VideoCodec codec) { + LOG_ID(INFO) << __func__; + VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN; + if (codec_ == VideoCodec::kMJPEG) { + profile = VIDEO_CODEC_PROFILE_UNKNOWN; + } else if (codec == VideoCodec::kH264) { + profile = H264PROFILE_BASELINE; + } else if (codec == VideoCodec::kVP8) { + profile = VP8PROFILE_MIN; + } else { + LOG_ID(ERROR) << "Unknown codec:" << codec; + } + + return profile; +} + +bool TizenEsPlusPlayerRenderer::UpdateVideoConfig() { + LOG_ID(INFO) << __func__; + DCHECK(worker_task_runner_->BelongsToCurrentThread()); + + if (!media_resource_) { + LOG_ID(INFO) << "No source created yet, create new one."; + media_resource_ = std::make_unique(); + media_resource_->ResetStream(); + } + + ChunkDemuxerStream* stream = media_resource_->GetVideoStream(); + if (!stream) { + LOG_ID(ERROR) << "No video stream."; + return false; + } + + VideoDecoderConfig cfg = VideoDecoderConfig( + codec_, GetCodecProfile(codec_), VideoDecoderConfig::AlphaMode::kIsOpaque, + VideoColorSpace(), VideoTransformation(), current_frame_size_, + gfx::Rect{0, 0, current_frame_size_.width(), + current_frame_size_.height()}, + current_frame_size_, std::vector{}, + EncryptionScheme::kUnencrypted); + // it is needed to set espp to manual copy mode now if we want to enable user + // data later. + cfg.set_enable_manual_copy(could_enable_user_data_); + + // Fix the video max resolution to FHD before setting it to ESPP to ensure + // that our hardware decoder selection logic is not disrupted. That is to say + // we hope the allocated decoder is 'just enough' rather than 'more than + // enough'. + cfg.set_max_coded_size({kFHDVideoMaxWidth, kFHDVideoMaxHeight}); + cfg.set_is_rtc(true); + return stream->UpdateVideoConfig(cfg, false, log_.get()); +} + +void TizenEsPlusPlayerRenderer::Init() { + TRACE_EVENT0("media", "TizenEsPlusPlayerRenderer::Init"); + LOG_ID(INFO) << __func__; + DCHECK(worker_task_runner_->BelongsToCurrentThread()); + + MainFrameFinder find_main_frame; + content::RenderFrame::ForEach(&find_main_frame); + if (!find_main_frame.result) { + LOG_ID(ERROR) + << "Couldn't find main render frame, EsPlusPlayer Renderer will " + "be disabled"; + return; + } + + player_state_ = Status::INITIALISING; + + // init mojo + media_interface_factory_ = std::make_unique( + find_main_frame.result->GetBrowserInterfaceBroker()); + + mojo::PendingRemote renderer_remote; + media_interface_factory_->CreateMediaPlayerRenderer( + client_extension_receiver_.BindNewPipeAndPassRemote(), + renderer_remote.InitWithNewPipeAndPassReceiver(), + renderer_extension_remote_.BindNewPipeAndPassReceiver()); + + mojo_renderer_ = std::make_unique( + worker_task_runner_, nullptr, /* VideoOverlayFactory */ + nullptr, /* VideoRendererSink */ + std::move(renderer_remote)); + + // init source and esplusplayer settings + UpdateVideoConfig(); + + // init renderer + mojo_renderer_->Initialize( + media_resource_.get(), this, + base::BindOnce(&TizenEsPlusPlayerRenderer::OnRendererInitResult, + GetWeakPtr())); + +#if defined(ENABLE_AUTO_ZOOM) + if (pending_ai_zoom_settings_) { + SetAiZoomSettings(*pending_ai_zoom_settings_); + pending_ai_zoom_settings_.reset(); + } +#endif // defined(ENABLE_AUTO_ZOOM) +} + +void TizenEsPlusPlayerRenderer::OnGetVideoId(int32_t player_id) { + LOG_ID(INFO) << " player_id:" << player_id; + DCHECK(worker_task_runner_->BelongsToCurrentThread()); + video_id_ = player_id; +} + +void TizenEsPlusPlayerRenderer::OnRendererInitResult(PipelineStatus status) { + LOG_ID(INFO) << " status:" << status; + DCHECK(worker_task_runner_->BelongsToCurrentThread()); + + if (status != PIPELINE_OK) { + player_state_ = Status::ERROR; + if (init_cb_) + std::move(init_cb_).Run(false); + return; + } + + SetupBeforePlaying(); + player_state_ = Status::INITIALISED; + if (init_cb_) + std::move(init_cb_).Run(true); +} + +bool TizenEsPlusPlayerRenderer::IsReady() { + if (player_state_ == Status::INITIALISED || + player_state_ == Status::PREPARED) { + return true; + } + return false; +} + +VideoFrameMetadata TizenEsPlusPlayerRenderer::GetMetaData( + base::TimeDelta timestamp) { + PendingFrame pending_frame; + { + base::AutoLock lk(pending_frames_lock_); + while (!pending_frames_.empty()) { + pending_frame = pending_frames_.front(); + if (pending_frame.timestamp.InMilliseconds() >= + timestamp.InMilliseconds()) { + if (pending_frame.timestamp.InMilliseconds() == + timestamp.InMilliseconds()) { + pending_frames_.pop_front(); + } + break; + } else { + pending_frames_.pop_front(); + } + } + } + if (pending_frame.timestamp.InMilliseconds() != timestamp.InMilliseconds()) { + LOG_ID(ERROR) << "Could not find pending frame by timestamp: " + << timestamp.InMilliseconds(); + return lastVideoFrameMeta_; + } + return pending_frame.metadata.value(); +} + +bool TizenEsPlusPlayerRenderer::QueueBuffer(const VideoFrameMetadata& meta, + const gfx::Size& coded_size, + const uint8_t* data, + std::size_t size, + bool key_frame) { + UpdateLastCaptureResolution(meta); + + ChunkDemuxerStream* stream = media_resource_->GetVideoStream(); + if (!stream) { + LOG_ID(ERROR) << "No video stream."; + return true; + } + + base::TimeDelta ts = + meta.reference_time.value_or(base::TimeTicks()) - base::TimeTicks(); + TRACE_EVENT2("media", "TizenEsPlusPlayerRenderer::QueueBuffer", "key_frame", + key_frame, "timestamp", ts.InMilliseconds()); + bool request_key_frame = false; + { + base::AutoLock lk(append_frame_lock_); + StreamParser::BufferQueue buffer_queue; + auto buffer = StreamParserBuffer::CopyFrom(data, size, key_frame, + DemuxerStream::Type::VIDEO, 0); + buffer->set_timestamp(ts); + buffer->set_duration(base::Milliseconds(33)); + buffer->set_is_duration_estimated(true); + buffer_queue.push_back(std::move(buffer)); + stream->Append(buffer_queue); + + // we could not clean buffer until key frame received. + double queue_buffer_size = stream->GetBufferedSize(); + if (queue_buffer_size >= kMaxBufferSize) { + LOG_ID(INFO) << "Max buffer size(" << kMaxBufferSize << ") reached."; + request_key_frame = true; + if (key_frame) { + LOG_ID(INFO) << "Clean bufer"; + stream->Remove(first_buffer_ts.value_or(base::Seconds(0)), ts, ts); + stream->Seek(ts); + } + } + } + + if (!first_buffer_ts.has_value()) { + LOG_ID(INFO) << "Seek to the stream beginning timestamp:" + << ts.InMilliseconds() << "(" << ts << ")" + << " from where the esplusplayer shall read."; + stream->Seek(ts); + first_buffer_ts = ts; + + // prepare and start player from now + worker_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&TizenEsPlusPlayerRenderer::StartPlayingOnWorkerThread, + GetWeakPtr(), ts)); + } + + if (mode_ == Mode::kVideoHole) { + auto frame = media::VideoFrame::CreateHoleFrame(coded_size); + if (!frame) { + LOG_ID(ERROR) << "create hole frame failed!"; + return request_key_frame; + } + frame->set_timestamp(ts); + frame->metadata().MergeMetadataFrom(meta); + frame->metadata().player_id = id_; + if (frame_cb_) + frame_cb_.Run(std::move(frame), *meta.reference_time); + } else if (mode_ == Mode::kVideoHoleWithMappingBuffer) { + base::AutoLock lk(pending_frames_lock_); + pending_frames_.push_back(PendingFrame{ts, meta}); + } + lastVideoFrameMeta_ = meta; + + return request_key_frame; +} + +void TizenEsPlusPlayerRenderer::OnRequestSeek(base::TimeDelta time) { + mojo_renderer_->Seek(time, base::DoNothing()); + ChunkDemuxerStream* stream = media_resource_->GetVideoStream(); + if (!stream) { + LOG_ID(ERROR) << "No video stream."; + return; + } + + // ESPP shall flush all frames cached after seek, so it should not feed any + // frame before seek. + stream->StartReturningData(); +} + +void TizenEsPlusPlayerRenderer::OnError(PipelineStatus status) { + LOG_ID(INFO) << " status:" << status; + DCHECK(worker_task_runner_->BelongsToCurrentThread()); + player_state_ = Status::ERROR; +} + +#if defined(TIZEN_TBM_SUPPORT) +void TizenEsPlusPlayerRenderer::OnNewTbmFrameAvailable( + uint32_t player_id, + gfx::TbmBufferHandleInterProcess tbm_buffer_handle_inter_process, + base::TimeDelta timestamp) { + TRACE_EVENT1("media", "TizenEsPlusPlayerRenderer::OnNewTbmFrameAvailable", + "timestamp", timestamp.InMilliseconds()); + DCHECK(worker_task_runner_->BelongsToCurrentThread()); + auto [tbm_buffer_handle, tbm_surface_release_cb_runner] = + gfx::ToTbmBufferHandle(tbm_buffer_handle_inter_process); + + auto frame = media::VideoFrame::WrapTBMInterProcessBuffer( + gfx::Size(tbm_buffer_handle.width, tbm_buffer_handle.height), timestamp, + tbm_buffer_handle); + if (!frame) { + LOG_ID(ERROR) << "Failed to wrap TBM IPC buffer."; + return; + } + + frame->AddDestructionObserver(tbm_surface_release_cb_runner.Release()); + frame->metadata().player_id = id_; + + // Webrtc TBM from esplayer will be destroyed from + // video frame DestructionObserver + frame->SetTbmDestroyType(gfx::kDestroyTbmByVideoFrame); + frame->AddDestructionObserver(BindToCurrentLoop(base::BindOnce( + &TizenEsPlusPlayerRenderer::ReleaseMediaPacket, GetWeakPtr(), + reinterpret_cast(tbm_buffer_handle.media_packet)))); + frame->metadata().MergeMetadataFrom(GetMetaData(timestamp)); + if (frame_cb_) { + frame_cb_.Run(std::move(frame), timestamp + base::TimeTicks()); + } + tbm_frame_in_use_++; +} + +void TizenEsPlusPlayerRenderer::ReleaseMediaPacket(uintptr_t media_packet) { + if (!worker_task_runner_->BelongsToCurrentThread()) { + worker_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&TizenEsPlusPlayerRenderer::ReleaseMediaPacket, + GetWeakPtr(), media_packet)); + return; + } + + if (!renderer_extension_remote_.is_bound()) { + LOG_ID(INFO) << "Extension mojo is unbound."; + return; + } + + renderer_extension_remote_->OnMediaPacketExhausted(media_packet); + tbm_frame_in_use_--; + if (tbm_frame_in_use_ == 0 && pending_disable_tbm_) + EnableTbmBufferCallback(false); +} +#endif + +void TizenEsPlusPlayerRenderer::EnableTbmBufferCallback(bool enable) { + if (!worker_task_runner_->BelongsToCurrentThread()) { + worker_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&TizenEsPlusPlayerRenderer::EnableTbmBufferCallback, + GetWeakPtr(), enable)); + return; + } + + if (!could_enable_user_data_) { + LOG_ID(INFO) + << " Current instance is initialized without user data support."; + return; + } + + // ESPP will delete all TBM buffers immediately when disable TBM, + // so we need to make sure there is no TBM buffer in use currently, + // or disable TBM later. + if (!enable && tbm_frame_in_use_ > 0) { + LOG_ID(INFO) << " There are still " << tbm_frame_in_use_ + << " TBM buffer(s) in use, pending disable TBM."; + pending_disable_tbm_ = true; + return; + } + pending_disable_tbm_ = false; + + // TODO(vd.wasm) This assumes that initial mode will be `kVideoHole`. + auto new_mode = + (enable ? Mode::kVideoHoleWithMappingBuffer : Mode::kVideoHole); + if (mode_ == new_mode) { + return; + } + + mode_ = new_mode; + renderer_extension_remote_->EnableTbmBufferCallback(enable); + LOG_ID(INFO) << " new mode:" << static_cast(mode_); +} + +void TizenEsPlusPlayerRenderer::SetCallBackFrameSize(const gfx::Size& size) { + if (!worker_task_runner_->BelongsToCurrentThread()) { + worker_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&TizenEsPlusPlayerRenderer::SetCallBackFrameSize, + GetWeakPtr(), size)); + return; + } + + LOG_ID(INFO) << " new size:" << size.ToString(); + renderer_extension_remote_->SetCallBackFrameSize(size); +} + +void TizenEsPlusPlayerRenderer::UpdateLastCaptureResolution( + const VideoFrameMetadata& meta) { + if (!meta.source_size.has_value()) + return; + + gfx::Size source_size = *meta.source_size; + if (last_capture_size_ != source_size) { + LOG_ID(INFO) << ", capture source size changed from " + << last_capture_size_.ToString() << " to " + << source_size.ToString(); + SetCallBackFrameSize(source_size); + last_capture_size_ = source_size; + } +} + +#if defined(ENABLE_AUTO_ZOOM) +void TizenEsPlusPlayerRenderer::SetAiZoomSettings( + const media::TizenAiZoomSettings& settings) { + if (!worker_task_runner_->BelongsToCurrentThread()) { + worker_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&TizenEsPlusPlayerRenderer::SetAiZoomSettings, + GetWeakPtr(), settings)); + return; + } + + LOG_ID(INFO) << " renderer extensions bound = " + << renderer_extension_remote_.is_bound() + << ", ai zoom settings = " << settings.AsHumanReadableString(); + + if (!renderer_extension_remote_.is_bound()) { + pending_ai_zoom_settings_ = settings; + return; + } + + renderer_extension_remote_->SetAiZoomSettings(settings); +} +#endif // defined(ENABLE_AUTO_ZOOM) + +void TizenEsPlusPlayerRenderer::SetPlayerVideoAbove(int32_t other_id) { + if (!worker_task_runner_->BelongsToCurrentThread()) { + worker_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&TizenEsPlusPlayerRenderer::SetPlayerVideoAbove, + base::Unretained(this), other_id)); + return; + } + + LOG_ID(INFO) << __func__ << " other_id:" << other_id; + mojo_renderer_->SetPlayerVideoAbove(other_id); +} + +void TizenEsPlusPlayerRenderer::OnVideoSinkGeometryChange( + const gfx::RectF& rect, + media::VideoRotation rotation) { + LOG_ID(INFO) << " rect:" << rect.ToString() << " rotation:" << rotation; + worker_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&TizenEsPlusPlayerRenderer::SetGeometryOnWorkerThread, + GetWeakPtr(), rect, rotation)); +} + +base::WeakPtr +TizenEsPlusPlayerRenderer::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + +void TizenEsPlusPlayerRenderer::StreamResource::ResetStream() { + LOG(INFO) << __func__; + demuxer_streamer_ = std::make_unique( + DemuxerStream::VIDEO, MediaTrack::Id("tizen renderer video stream")); +} + +std::vector +TizenEsPlusPlayerRenderer::StreamResource::GetAllStreams() { + LOG(INFO) << __func__; + std::vector v; + if (demuxer_streamer_) + v.push_back(demuxer_streamer_.get()); + return v; +} + +} // namespace media diff --git a/tizen_src/chromium_impl/media/blink/renderer/tizen_esplusplayer_renderer.h b/tizen_src/chromium_impl/media/blink/renderer/tizen_esplusplayer_renderer.h new file mode 100644 index 0000000..8addc02 --- /dev/null +++ b/tizen_src/chromium_impl/media/blink/renderer/tizen_esplusplayer_renderer.h @@ -0,0 +1,304 @@ +// Copyright 2022 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_RENDERER_TIZEN_ESPLUSPLAYER_RENDERER +#define MEDIA_RENDERER_TIZEN_ESPLUSPLAYER_RENDERER + +#include +#include + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" +#include "base/synchronization/waitable_event.h" +#include "base/task/single_thread_task_runner.h" +#include "base/task/thread_pool.h" +#include "content/renderer/media/media_interface_factory.h" +#include "media/base/media_util.h" +#include "media/base/renderer_client.h" +#include "media/filters/chunk_demuxer.h" +#include "media/mojo/clients/mojo_renderer.h" +#include "media/mojo/mojom/interface_factory.mojom.h" +#include "media/mojo/mojom/renderer_extensions.mojom.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_sink.h" + +#if defined(TIZEN_TBM_SUPPORT) +#include "tizen_src/chromium_impl/ui/gfx/tbm_buffer_handle_inter_process.h" +#endif + +#if defined(TIZEN_HW_ENCODER) && !defined(TIZEN_CAPI_ENCODER_TV_API) +#include "tizen_src/chromium_impl/media/base/tizen/scaler_usage_manager.h" +#endif + +namespace media { + +enum class CanDropFrames { kNo, kYes }; +enum class HardwareResouceCategory { kScaler, kDeocder }; +enum class HardwareResouceType { kAny, kMain, kSub, kEnd }; +enum class Mode { kVideoHole, kTexture, kVideoHoleWithMappingBuffer }; + +using FrameCb = base::RepeatingCallback, + base::TimeTicks)>; +using InitCb = base::OnceCallback; +using SelectedResource = std::pair; + +class TizenEsPlusPlayerRenderer; + +class TizenEsPlusPlayerRendererManager { + public: + static TizenEsPlusPlayerRendererManager& GetInstance(); + std::unique_ptr CreateTizenEsPlusPlayerRenderer( + media::VideoCodec codec, + gfx::Size init_size, + media::HardwareResouceType scaler_type, + media::HardwareResouceType decoder_type, + media::CanDropFrames can_drop_frames, + media::Mode mode, + media::InitCb init_cb, + media::FrameCb frame_cb, + bool has_id, + bool could_enable_user_data); + + void RemoveTizenEsPlusPlayerRenderer(int id); + void OnVideoSinkGeometryChange(int id, + const gfx::RectF& rect, + media::VideoRotation rotation); + void OnZOrderChanged(int broadcast_id, const std::vector& video_ids); + + private: + friend class base::NoDestructor; + + TizenEsPlusPlayerRendererManager(); + ~TizenEsPlusPlayerRendererManager(); + // this function should be carefully used, as the got weakptr could + // be invalid anytime. + base::WeakPtr GetTizenEsPlusPlayerRenderer(int id); + bool HasResourceConflict(const media::SelectedResource& type); + bool HasResourceConflictScaler(const media::HardwareResouceType& type); + bool HasResourceConflictDecoder(const media::HardwareResouceType& type); + bool SelectHWResource(media::HardwareResouceType& scaler_type, + media::HardwareResouceType& decoder_type, + const media::Mode& mode); + + int index_{0}; + std::unordered_map> + id_to_renderers_; + std::vector video_ids_order_; + base::Lock lock_; +}; + +// This class is used for rendering camera video stream by upstream +// mojo renderer interface on Tizen TV products. +// all mojo related process should be handled on |worker_task_runner_|. +class TizenEsPlusPlayerRenderer final + : public RendererClient, + public media::mojom::MediaPlayerRendererClientExtension { + public: + // max buffer queue size, clear the whole buffer queue once it is exceeded. + static constexpr double kMaxBufferSize = 8 * 1024 * 1024; + + // We need a way to get the meta data in TBM callback to constructe video + // frame: store meta data in pending frame, and get it by timestamp in TBM + // callback. + struct PendingFrame { + base::TimeDelta timestamp; + absl::optional metadata{}; + }; + VideoFrameMetadata GetMetaData(base::TimeDelta timestamp); + + ~TizenEsPlusPlayerRenderer() override; + + int32_t GetVideoId() { return video_id_; } + void OnGetVideoId(int32_t player_id); + void OnRendererInitResult(PipelineStatus status); + bool IsReady(); + // QueueBuffer should be called on IO thread + bool QueueBuffer(const VideoFrameMetadata& meta, + const gfx::Size& coded_size, + const uint8_t* data, + std::size_t size, + bool key_frame); + + // RendererClient implementation + void OnError(PipelineStatus status) override; + void OnFallback(PipelineStatus status) override {} + void OnEnded() override {} + void OnStatisticsUpdate(const PipelineStatistics&) override {} + // void OnPlayerStarted(bool) override {} + void OnBufferingStateChange(BufferingState, + BufferingStateChangeReason) override {} + void OnWaiting(WaitingReason) override {} + void OnAudioConfigChange(const AudioDecoderConfig&) override {} + void OnVideoConfigChange(const VideoDecoderConfig&) override {} + void OnVideoNaturalSizeChange(const gfx::Size&) override {} + void OnVideoOpacityChange(bool) override {} + bool IsVideoStreamAvailable() override { return IsReady(); } + void OnVideoFrameRateChange(absl::optional) override {} + + // media::mojom::MediaPlayerRendererClientExtension implementation + void OnDurationChange(base::TimeDelta duration) override {} + void OnVideoSizeChange(const gfx::Size& size) override {} +#if defined(TIZEN_MULTIMEDIA) + void OnBufferUpdate(base::TimeDelta time) override {} + void OnRequestSeek(base::TimeDelta time) override; +#endif + void OnNewFrameAvailable(uint32_t playerId, + base::UnsafeSharedMemoryRegion frame, + uint32_t size, + base::TimeDelta timestamp, + uint32_t width, + uint32_t height) override {} +#if defined(TIZEN_TBM_SUPPORT) + void OnNewTbmFrameAvailable( + uint32_t playerId, + gfx::TbmBufferHandleInterProcess tbm_buffer_handle, + base::TimeDelta timestamp) override; + void ReleaseMediaPacket(uintptr_t media_packet); +#endif + void EnableTbmBufferCallback(bool enable); + void SetCallBackFrameSize(const gfx::Size& size); + void UpdateLastCaptureResolution(const VideoFrameMetadata& meta); + void NotifyTrackInfoToBrowser(int) override {} + using RendererClient::AddTrackInfo; + void AddTrackInfo(media::mojom::MediaTrackInfoPtr trackinfo) override {} + // using RendererClient::OnRegisterTimelineCbInfo; + // void OnRegisterTimelineCbInfo( + // media::mojom::register_timeline_cb_info_sPtr info) override {} + // void OnSyncTimelineCbInfo(const std::string& timeline_selector, + // int sync) override {} + // void OnMrsUrlChange(const std::string& url) override {} + // void OnContentIdChange(const std::string& id) override {} +#if defined(ENABLE_AUTO_ZOOM) + void SetAiZoomSettings(const media::TizenAiZoomSettings& settings); +#endif // defined(ENABLE_AUTO_ZOOM) + void SetPlayerVideoAbove(int32_t other_id); + void OnVideoSinkGeometryChange(const gfx::RectF& rect, + media::VideoRotation rotation); + + const SelectedResource& selected_resource() const { + return selected_resource_; + } + + base::WeakPtr GetWeakPtr(); + + private: + friend class TizenEsPlusPlayerRendererManager; + TizenEsPlusPlayerRenderer(media::VideoCodec codec, + gfx::Size init_size, + HardwareResouceType scaler_type, + HardwareResouceType decoder_type, + CanDropFrames can_drop_frames, + Mode mode, + InitCb init_cb, + FrameCb frame_cb, + int renderer_id, + bool could_enable_user_data); + + void Init(); + bool UpdateVideoConfig(); + VideoCodecProfile GetCodecProfile(VideoCodec codec); + // something must be done before esplusplayer prepared + void SetupBeforePlaying(); + + // HW resources + void OnHardwareResourcesComplete(bool success); +#if defined(TIZEN_HW_ENCODER) && !defined(TIZEN_CAPI_ENCODER_TV_API) + void GetScalerUsageManager(); +#endif + void SelectHardwareResources(); + void DidTakeResources(); + void DidFreeResources(); + + void ReleaseRendererOnWorkThread(base::WaitableEvent* event); + void StartPlayingOnWorkerThread(base::TimeDelta time); + void SetGeometryOnWorkerThread(const gfx::RectF& rect, + media::VideoRotation rotation); + mojom::HardwareResourceConfig ToMojomHardwareResourceConfig( + SelectedResource types); + + mojo::Remote + renderer_extension_remote_; + mojo::Receiver + client_extension_receiver_{this}; + std::unique_ptr media_interface_factory_; + std::unique_ptr mojo_renderer_; + + // all mojo IPC should be handled and posted to this dedicated runner. + scoped_refptr worker_task_runner_{ + base::ThreadPool::CreateSingleThreadTaskRunner( + {base::TaskPriority::USER_VISIBLE, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})}; + + class StreamResource : public MediaResource { + public: + ~StreamResource() override = default; + std::vector GetAllStreams() override; + ChunkDemuxerStream* GetVideoStream() { return demuxer_streamer_.get(); } + void ResetStream(); + + private: + std::unique_ptr demuxer_streamer_; + }; + + enum class Status { + NONE, + ERROR, + SUSPENDED, + INITIALISING, + INITIALISED, + PREPARED + }; + +#if defined(TIZEN_HW_ENCODER) && !defined(TIZEN_CAPI_ENCODER_TV_API) + ScalerUsageManager* scaler_manager_; +#endif + SelectedResource selected_resource_; + absl::optional uses_subresource_; + + std::unique_ptr media_resource_; + std::atomic player_state_; + + VideoCodec codec_; + gfx::Size current_frame_size_; + std::unique_ptr log_; + + InitCb init_cb_; + FrameCb frame_cb_; + Mode mode_; + + absl::optional first_buffer_ts; + + int tbm_frame_in_use_; + bool pending_disable_tbm_; + int id_; + int video_id_; + // it indicates whether the current player could be running in TBM mode. + bool could_enable_user_data_; + +#if defined(ENABLE_AUTO_ZOOM) + std::optional pending_ai_zoom_settings_; +#endif // defined(ENABLE_AUTO_ZOOM) + + base::Lock pending_frames_lock_{}; + base::Lock append_frame_lock_{}; + std::deque pending_frames_{}; + + // In case get none from pending_frames_, use latest meta data + VideoFrameMetadata lastVideoFrameMeta_; + + // Save the latest capture resolution, when it's changed, send + // SetCallBackFrameSize to UI process + gfx::Size last_capture_size_; + + base::WeakPtrFactory weak_factory_{this}; +}; + +} // namespace media + +#endif // MEDIA_RENDERER_TIZEN_ESPLUSPLAYER_RENDERER diff --git a/tizen_src/chromium_impl/media/capture/video/tizen/video_capture_device_tizen.cc b/tizen_src/chromium_impl/media/capture/video/tizen/video_capture_device_tizen.cc index 729eff0..86ea118 100644 --- a/tizen_src/chromium_impl/media/capture/video/tizen/video_capture_device_tizen.cc +++ b/tizen_src/chromium_impl/media/capture/video/tizen/video_capture_device_tizen.cc @@ -591,9 +591,10 @@ void VideoCaptureDeviceTizen::OnCameraCaptured(camera_preview_data_s* frame, if (self->first_ref_time_.is_null()) self->first_ref_time_ = now; - self->client_->OnIncomingCapturedBuffer(std::move(self->buffer_), - videocaptureformat, now, - now - self->first_ref_time_); + self->client_->OnIncomingCapturedBufferExt( + std::move(self->buffer_), videocaptureformat, gfx::ColorSpace(), now, + now - self->first_ref_time_, gfx::Rect(videocaptureformat.frame_size), + VideoFrameMetadata(), frame->data.encoded_plane.size); // statistics & log every seconds ++(self->frame_total_); diff --git a/tizen_src/chromium_impl/media/filters/esplusplayer_util.cc b/tizen_src/chromium_impl/media/filters/esplusplayer_util.cc index 1e42c3d..a4efe57 100644 --- a/tizen_src/chromium_impl/media/filters/esplusplayer_util.cc +++ b/tizen_src/chromium_impl/media/filters/esplusplayer_util.cc @@ -142,6 +142,11 @@ esplusplayer_video_mime_type ConvertToESPlusVideoMimeType( case media::VideoCodec::kAV1: videoMimeType = ESPLUSPLAYER_VIDEO_MIME_TYPE_AV1; break; +#if defined(TIZEN_MULTIMEDIA_MJPEG_SUPPORT) + case media::VideoCodec::kMJPEG: + videoMimeType = ESPLUSPLAYER_VIDEO_MIME_TYPE_MJPEG; + break; +#endif default: { LOG(WARNING) << "Unknown codec :" << codec << ". Returning H264."; videoMimeType = ESPLUSPLAYER_VIDEO_MIME_TYPE_H264; diff --git a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.cc b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.cc index c781940..a56e135 100644 --- a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.cc +++ b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.cc @@ -156,8 +156,8 @@ bool MediaPlayerESPlusPlayerTV::ReadFromBufferQueue(DemuxerStream::Type type) { } bool MediaPlayerESPlusPlayerTV::SetSubmitDataType( - const bool is_drm_eme, - const bool single_process_mode) { + const bool& is_drm_eme, + const bool& single_process_mode) { int error = ESPLUSPLAYER_ERROR_TYPE_NONE; is_drm_eme_ = is_drm_eme; if (is_drm_eme) { @@ -176,8 +176,8 @@ bool MediaPlayerESPlusPlayerTV::SetSubmitDataType( esplayer_, ESPLUSPLAYER_SUBMIT_DATA_TYPE_CLEAN_DATA); } if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) { - LOG(ERROR) << "esplusplayer_set_submit_data_type failed. error code " - << error; + LOG_ID(ERROR, player_id_) + << "esplusplayer_set_submit_data_type failed. error code " << error; return false; } return true; @@ -314,14 +314,154 @@ esplusplayer_submit_status MediaPlayerESPlusPlayerTV::SubmitEsPacket( void MediaPlayerESPlusPlayerTV::EnableLowLatencyMode() { - NOTIMPLEMENTED(); + if (!esplayer_) { + LOG(ERROR) << "Invalid player handle."; + return; + } + + if (GetPlayerState() != ESPLUSPLAYER_STATE_IDLE) { + LOG(ERROR) << "Invalid player state."; + return; + } + + auto error = esplusplayer_set_low_latency_mode( + esplayer_, ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO); + if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) { + LOG(ERROR) << "esplusplayer_set_low_latency_mode failed. error #" + << esplusplayer_get_error_string( + static_cast(error)); + } + error = esplusplayer_set_low_latency_mode( + esplayer_, ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_SYNC); + if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) { + LOG(ERROR) << "esplusplayer_set_low_latency_mode failed. error #" + << esplusplayer_get_error_string( + static_cast(error)); + } + is_video_low_latency_ = true; } void MediaPlayerESPlusPlayerTV::SetHardwareResource(int config) { - NOTIMPLEMENTED(); + LOG(INFO) << __func__ << " config:" << config; + if (!esplayer_) { + LOG(ERROR) << "Invalid player handle."; + return; + } + + if (GetPlayerState() == ESPLUSPLAYER_STATE_NONE) { + LOG(ERROR) << "Invalid player state."; + return; + } + + auto error = esplusplayer_set_alternative_video_resource(esplayer_, config); + if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) { + LOG(ERROR) << "esplusplayer_set_alternative_video_resource failed. error #" + << esplusplayer_get_error_string( + static_cast(error)); + return; + } + + return; } void MediaPlayerESPlusPlayerTV::EnableTbmBufferCallback(bool enable) { + LOG_ID(INFO, player_id_) << __func__ << " enable: " << enable; +#if TIZEN_VERSION_AT_LEAST(6, 0, 0) + if (decoded_frame_buffer_type_ == + ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_SCALE) { + LOG_ID(INFO, player_id_) << "tbm buffer callback had enabled, skip it"; + return; + } + + enable_tbm_buffer_callback_ = enable; + if (enable && GetPlayerState() == ESPLUSPLAYER_STATE_NONE) { + LOG_ID(INFO, player_id_) + << "Invalid player state. To enable Tbm buffer callback the " + "player must not be NONE."; + return; + } + + // fixme: ESPP crash if set type to none, so skip it. + if (!enable) + return; + + esplusplayer_decoded_video_frame_buffer_type type = + (enable ? ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_SCALE + : ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_NONE); + + int error = esplusplayer_set_video_frame_buffer_type(esplayer_, type); + if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) { + LOG_ID(ERROR, player_id_) + << "esplusplayer_set_video_frame_buffer_type failed. error #" + << esplusplayer_get_error_string( + static_cast(error)); + return; + } + decoded_frame_buffer_type_ = type; + + // TODO(vd.wasm) Add method for setting buffer resolution. + if (decoded_frame_buffer_type_ == + ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_SCALE) { + int width = + pending_cb_frame_width_ > 0 ? pending_cb_frame_width_ : cb_frame_width_; + width = width > 0 ? width : kDefaultCallBackFrameWidth; + int height = pending_cb_frame_height_ > 0 ? pending_cb_frame_height_ + : cb_frame_height_; + height = height > 0 ? height : kDefaultCallBackFrameHeight; + SetCallBackFrameSize(gfx::Size(width, height)); + } + +#else + LOG_ID(INFO, player_id_) + << "EnableTbmBufferCallback not support in this version"; +#endif +} + +void MediaPlayerESPlusPlayerTV::SetCallBackFrameSize(const gfx::Size& size) { + LOG_ID(INFO, player_id_) << "Going to set callback frame size: " + << size.width() << "x" << size.height(); +#if TIZEN_VERSION_AT_LEAST(6, 0, 0) + if (size.width() <= 0 || size.height() <= 0 || + size.width() > kMaxCallBackFrameWidth || + size.height() > kMaxCallBackFrameHeight) { + LOG(WARNING) << "invalid callback frame size:" << size.width() << "x" + << size.height(); + return; + } + if (cb_frame_width_ == size.width() && cb_frame_height_ == size.height()) + return; + if (decoded_frame_buffer_type_ == + ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_SCALE && + GetPlayerState() != ESPLUSPLAYER_STATE_NONE) { + int player_error = esplusplayer_set_video_frame_buffer_scale_resolution( + esplayer_, size.width(), size.height()); + if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) { + LOG_ID(ERROR, player_id_) + << "esplusplayer_set_video_frame_buffer_scale_resolution " + "failed, error code " + << player_error; + pending_cb_frame_width_ = size.width(); + pending_cb_frame_height_ = size.height(); + return; + } + LOG_ID(INFO, player_id_) + << "callback frame size successfully set to:" << size.width() << "x" + << size.height(); + cb_frame_width_ = size.width(); + cb_frame_height_ = size.height(); + pending_cb_frame_width_ = 0; + pending_cb_frame_height_ = 0; + } else { + LOG_ID(INFO, player_id_) + << "callback frame size setting will handled later: " << size.width() + << "x" << size.height(); + pending_cb_frame_width_ = size.width(); + pending_cb_frame_height_ = size.height(); + } +#endif +} + +bool MediaPlayerESPlusPlayerTV::RequestVideoDecodedBuffer() { NOTIMPLEMENTED(); } @@ -334,6 +474,12 @@ void MediaPlayerESPlusPlayerTV::OnVideoFrameDropped( NOTIMPLEMENTED(); } +void MediaPlayerESPlusPlayerTV::OnEos() { + MediaPlayerESPlusPlayer::OnEos(); + if (GetMediaPlayerClient()) + GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackFinish, player_id_); +} + void MediaPlayerESPlusPlayerTV::OnPrepareComplete(bool result) { if (!task_runner_->BelongsToCurrentThread()) { task_runner_->PostTask( @@ -342,13 +488,13 @@ void MediaPlayerESPlusPlayerTV::OnPrepareComplete(bool result) { return; } - return MediaPlayerESPlusPlayer::OnPrepareComplete(result); -} + if (result && is_video_low_latency_ && IsValid(DemuxerStream::VIDEO) && + !ReadRequested(DemuxerStream::VIDEO)) { + SetShouldFeed(DemuxerStream::VIDEO, true); + ReadBuffer(DemuxerStream::VIDEO); + } -void MediaPlayerESPlusPlayerTV::OnEos() { - MediaPlayerESPlusPlayer::OnEos(); - if (GetMediaPlayerClient()) - GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackFinish, player_id_); + return MediaPlayerESPlusPlayer::OnPrepareComplete(result); } void ReleaseTzHandle(int tz_handle, int size) { diff --git a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.h b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.h index 4a9d6c6..0a23727 100644 --- a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.h +++ b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.h @@ -24,6 +24,13 @@ void ReleaseTzHandle(int tz_handle, int size); class MEDIA_EXPORT MediaPlayerESPlusPlayerTV : public MediaPlayerESPlusPlayer { public: + enum { + kDefaultCallBackFrameHeight = 540, + kDefaultCallBackFrameWidth = 960, + kMaxCallBackFrameHeight = 720, + kMaxCallBackFrameWidth = 1280, + }; + MediaPlayerESPlusPlayerTV(); ~MediaPlayerESPlusPlayerTV() override; @@ -35,12 +42,13 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayerTV : public MediaPlayerESPlusPlayer { void EnableLowLatencyMode() override; void SetHardwareResource(int config) override; void EnableTbmBufferCallback(bool enable) override; + void SetCallBackFrameSize(const gfx::Size& size) override; + bool RequestVideoDecodedBuffer() override; void SetAppInfo() override; void OnVideoFrameDropped(const uint64_t dropped_count); void OnPrepareComplete(bool result) override; void OnEos() override; - #if defined(TIZEN_VIDEO_HOLE) void ToggleFullscreenMode(bool is_fullscreen) override {} #endif @@ -91,7 +99,8 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayerTV : public MediaPlayerESPlusPlayer { #endif bool SetVideoSubmitDataType(const media::VideoDecoderConfig& video_config); void SetAudioSubmitDataType(); - bool SetSubmitDataType(const bool is_drm_eme, const bool single_process_mode); + bool SetSubmitDataType(const bool& is_drm_eme, + const bool& single_process_mode); void SetAudioDecoderTypeIfNeeded(const media::AudioCodec& codec); bool is_drm_eme_{false}; @@ -109,6 +118,15 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayerTV : public MediaPlayerESPlusPlayer { bool is_hdr_changed_{false}; esplusplayer_matroska_color matroska_color_; + bool is_video_low_latency_{false}; + esplusplayer_decoded_video_frame_buffer_type decoded_frame_buffer_type_{ + ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_NONE}; + bool enable_tbm_buffer_callback_{false}; + int cb_frame_width_{0}; + int cb_frame_height_{0}; + int pending_cb_frame_width_{0}; + int pending_cb_frame_height_{0}; + base::WeakPtrFactory weak_factory_{this}; }; } // namespace media diff --git a/tizen_src/chromium_impl/media/filters/media_player_tizen.h b/tizen_src/chromium_impl/media/filters/media_player_tizen.h index 3caf276..63194a9 100644 --- a/tizen_src/chromium_impl/media/filters/media_player_tizen.h +++ b/tizen_src/chromium_impl/media/filters/media_player_tizen.h @@ -8,6 +8,7 @@ #include "base/memory/unsafe_shared_memory_region.h" #include "base/task/single_thread_task_runner.h" #include "media/base/demuxer_stream.h" +#include "media/base/renderer.h" #include "media/filters/flags.h" #include "third_party/blink/public/platform/web_application_type.h" #include "third_party/blink/public/platform/web_media_player.h" @@ -97,6 +98,8 @@ class MEDIA_EXPORT MediaPlayerTizen { virtual void SetMediaGeometry(const gfx::Rect& viewport_rect, const gfx::RectF& rect) = 0; virtual void PrepareVideoHole() {} + virtual void SetPlayerVideoAbove(int32_t other_id) {} + virtual void UseSubsurfaceController() {} #endif virtual void RequestSuspend(bool resource_conflicted = false) = 0; @@ -107,6 +110,8 @@ class MEDIA_EXPORT MediaPlayerTizen { virtual void EnableLowLatencyMode() {} virtual void SetHardwareResource(int config) {} virtual void EnableTbmBufferCallback(bool enable) {} + virtual void SetCallBackFrameSize(const gfx::Size& size) {} + virtual bool RequestVideoDecodedBuffer() { return false; } virtual void SetAppInfo() {} virtual int GetPlayerId() { return -1; } virtual void SetContentMimeType(const std::string& mime_type) {} diff --git a/tizen_src/chromium_impl/media/media_efl.gni b/tizen_src/chromium_impl/media/media_efl.gni index 7b41f67..5abc8b7 100644 --- a/tizen_src/chromium_impl/media/media_efl.gni +++ b/tizen_src/chromium_impl/media/media_efl.gni @@ -19,6 +19,9 @@ if (use_ozone) { external_media_efl_deps += [ "//tizen_src/chromium_impl/ui/ozone:ozone_efl" ] } +external_media_efl_blink_config = [] +external_media_efl_blink_sources = [] + if (tizen_multimedia) { external_media_video_decode_config += [ "//tizen_src/build:esplusplayer", @@ -127,6 +130,15 @@ if (tizen_multimedia) { ] } + if(tizen_product_tv) { + if(tizen_video_hole) { + external_media_efl_blink_sources += [ + "//tizen_src/chromium_impl/media/blink/renderer/tizen_esplusplayer_renderer.cc", + "//tizen_src/chromium_impl/media/blink/renderer/tizen_esplusplayer_renderer.h", + ] + } + } + external_media_capture_config += [ "//tizen_src/build:capi-media-camera", "//tizen_src/build:libcapi-media-camera", -- 2.7.4 From e0640adc00b71f4210eed2f90001b9b2ebea727a Mon Sep 17 00:00:00 2001 From: zhaodan Date: Sun, 7 Apr 2024 18:14:30 +0800 Subject: [PATCH 04/16] [M120 Migration]Define correct type as gfx::AcceleratedWidget for arch64 Issue: gfx::AcceleratedWidget was defined as uint32_t while using OZone, so when cast Window pointer to gfx::AcceleratedWidget on 64bit build, the address will lose higher bits and become invalid. Then when EGL APIs accessing the window pointer, the process will crash. Ref: https://review.tizen.org/gerrit/#/c/294274 Change-Id: I2a843f63bae185122a02a75d198cdd929ee23247 Signed-off-by: zhaodan --- ui/gfx/native_widget_types.h | 4 ++++ ui/linux/linux_ui_delegate.h | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/ui/gfx/native_widget_types.h b/ui/gfx/native_widget_types.h index 8cdd0cb..d558d12 100644 --- a/ui/gfx/native_widget_types.h +++ b/ui/gfx/native_widget_types.h @@ -270,7 +270,11 @@ constexpr AcceleratedWidget kNullAcceleratedWidget = 0; using AcceleratedWidget = ANativeWindow*; constexpr AcceleratedWidget kNullAcceleratedWidget = nullptr; #elif BUILDFLAG(IS_OZONE) +#if defined(ARCH_CPU_64_BITS) +using AcceleratedWidget = uint64_t; +#else using AcceleratedWidget = uint32_t; +#endif constexpr AcceleratedWidget kNullAcceleratedWidget = 0; #else #error unknown platform diff --git a/ui/linux/linux_ui_delegate.h b/ui/linux/linux_ui_delegate.h index e86644e9..9742960 100644 --- a/ui/linux/linux_ui_delegate.h +++ b/ui/linux/linux_ui_delegate.h @@ -10,9 +10,14 @@ #include "base/component_export.h" #include "base/functional/callback_forward.h" +#include "build/build_config.h" namespace gfx { +#if defined(ARCH_CPU_64_BITS) +using AcceleratedWidget = uint64_t; +#else using AcceleratedWidget = uint32_t; +#endif } namespace ui { -- 2.7.4 From 757a5cf97a546e04cb74a2e9423e0b1043a391a8 Mon Sep 17 00:00:00 2001 From: wangjing Date: Sun, 7 Apr 2024 10:26:26 +0800 Subject: [PATCH 05/16] Fix for emulator build error need to modify header file fix patch: https://review.tizen.org/gerrit/#/c/308930/ Change-Id: I22f1f88b86a68059b1ef1b490b8862a77f413ea7 Signed-off-by: wangjing --- content/browser/renderer_host/render_widget_host_view_aura.cc | 2 +- content/browser/renderer_host/render_widget_host_view_aura.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 8dc88b6..d8f0ffd 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -487,7 +487,6 @@ bool RenderWidgetHostViewAura::IsMultiviewMode() { return false; } -#endif void RenderWidgetHostViewAura::DidMoveWebView() { #if defined(TIZEN_VIDEO_HOLE) @@ -495,6 +494,7 @@ void RenderWidgetHostViewAura::DidMoveWebView() { on_webview_moved_callback_.Run(); #endif } +#endif void RenderWidgetHostViewAura::SetSize(const gfx::Size& size) { // For a SetSize operation, we don't care what coordinate system the origin diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index fa133fa..24d4f17 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h @@ -197,6 +197,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura // Sets rotation degrees. Expected values are one of { 0, 90, 180, 270 }. void UpdateRotationDegrees(int rotation_degrees); bool IsMultiviewMode(); + void DidMoveWebView(); #endif base::flat_map GetKeyboardLayoutMap() override; void InvalidateLocalSurfaceIdAndAllocationGroup() override; @@ -228,7 +229,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAura #endif ) override; #if defined(TIZEN_VIDEO_HOLE) - void DidMoveWebView(); void SetWebViewMovedCallback(const base::RepeatingClosure on_webview_moved); #endif -- 2.7.4 From 30296629f566e905cb739beec5c6a41d33b85479 Mon Sep 17 00:00:00 2001 From: wangjing Date: Mon, 8 Apr 2024 14:28:13 +0800 Subject: [PATCH 06/16] [M120 Migration] Disable badge service As badge is not enable on TV, so we need to disable it. Or it will cause js error ref: https://review.tizen.org/gerrit/#/c/276311/ Change-Id: Ic87ce222c90d33206ccfef335f5e8e10469d1557 Signed-off-by: wangjing --- third_party/blink/renderer/modules/badging/navigator_badge.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/third_party/blink/renderer/modules/badging/navigator_badge.cc b/third_party/blink/renderer/modules/badging/navigator_badge.cc index bc722ad..a832ce4 100644 --- a/third_party/blink/renderer/modules/badging/navigator_badge.cc +++ b/third_party/blink/renderer/modules/badging/navigator_badge.cc @@ -93,6 +93,9 @@ ScriptPromise NavigatorBadge::SetAppBadgeHelper( ScriptState* script_state, mojom::blink::BadgeValuePtr badge_value, ExceptionState& exception_state) { +#if BUILDFLAG(IS_TIZEN_TV) + return ScriptPromise::CastUndefined(script_state); +#endif if (badge_value->is_number() && badge_value->get_number() == 0) return ClearAppBadgeHelper(script_state, exception_state); @@ -122,7 +125,7 @@ ScriptPromise NavigatorBadge::ClearAppBadgeHelper( return ScriptPromise(); } -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA) +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA) && !BUILDFLAG(IS_TIZEN_TV) // TODO(crbug.com/1413916): The service is implemented in Chrome, so it may // not be provided in other embedders. Ensure that case is handled properly. From(script_state).badge_service()->ClearBadge(); -- 2.7.4 From b8dc205f59d302c3e279b11261d2958f43411f18 Mon Sep 17 00:00:00 2001 From: Akshay Kanagali Date: Thu, 4 Apr 2024 13:21:23 +0530 Subject: [PATCH 07/16] fixup! [NUI] NUI implementation for |SkiaRenderer| Replacing gl_image_egl with scoped_egl_image. Change-Id: Iaa7f75b1704d9d156db00f68e82d092c7c156867 Signed-off-by: Akshay Kanagali --- .../skia_output_device_offscreen_tbm.cc | 20 +++++++------------- .../skia_output_device_offscreen_tbm.h | 7 ++----- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/tizen_src/chromium_impl/components/viz/service/display_embedder/skia_output_device_offscreen_tbm.cc b/tizen_src/chromium_impl/components/viz/service/display_embedder/skia_output_device_offscreen_tbm.cc index a1e20db..e0aaea9 100644 --- a/tizen_src/chromium_impl/components/viz/service/display_embedder/skia_output_device_offscreen_tbm.cc +++ b/tizen_src/chromium_impl/components/viz/service/display_embedder/skia_output_device_offscreen_tbm.cc @@ -8,7 +8,6 @@ #include "third_party/skia/include/core/SkSurface.h" #include "ui/gl/gl_bindings.h" -#include "ui/gl/gl_image_egl.h" namespace viz { @@ -34,30 +33,25 @@ void SkiaOutputDeviceOffscreenTBM::EnsureBackbuffer() { size_.width(), size_.height(), TBM_FORMAT_ARGB8888); EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; - image_egl_ = base::MakeRefCounted(size_); - if (!image_egl_->Initialize(EGL_NATIVE_SURFACE_TIZEN, - static_cast(tbm_surface_), - attrs, 0, 0)) { - return; - } + egl_image_ = + gl::MakeScopedEGLImage(EGL_NO_CONTEXT, EGL_NATIVE_SURFACE_TIZEN, + static_cast(tbm_surface_), attrs); GLuint texture_id = 0; glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - image_egl_->BindTexImage(GL_TEXTURE_2D); - gpu::GetGrBackendTexture(context_state_->feature_info(), GL_TEXTURE_2D, - size_, texture_id, RGBA_8888, + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_.get()); + + gpu::GetGrBackendTexture(context_state_->feature_info(), GL_TEXTURE_2D, size_, + texture_id, kRGBA_8888_SkColorType, context_state_->gr_context()->threadSafeProxy(), &backend_texture_); } void SkiaOutputDeviceOffscreenTBM::DiscardBackbuffer() { - if (image_egl_) - image_egl_.release(); - if (tbm_surface_) { if (tbm_surface_destroy(tbm_surface_) != TBM_SURFACE_ERROR_NONE) LOG(ERROR) << "Failed to destroy tbm surface."; diff --git a/tizen_src/chromium_impl/components/viz/service/display_embedder/skia_output_device_offscreen_tbm.h b/tizen_src/chromium_impl/components/viz/service/display_embedder/skia_output_device_offscreen_tbm.h index b600f4a..a816992 100644 --- a/tizen_src/chromium_impl/components/viz/service/display_embedder/skia_output_device_offscreen_tbm.h +++ b/tizen_src/chromium_impl/components/viz/service/display_embedder/skia_output_device_offscreen_tbm.h @@ -7,10 +7,7 @@ #include "components/viz/service/display_embedder/skia_output_device_offscreen.h" #include "ui/gfx/tbm_buffer_handle.h" - -namespace gl { -class GLImageEGL; -} +#include "ui/gl/scoped_egl_image.h" namespace viz { @@ -34,7 +31,7 @@ class SkiaOutputDeviceOffscreenTBM : public SkiaOutputDeviceOffscreen { private: tbm_surface_h tbm_surface_ = 0; - scoped_refptr image_egl_; + gl::ScopedEGLImage egl_image_; }; } // namespace viz -- 2.7.4 From effde2838f04f5a8f36335cd44dd7fd9f331d91a Mon Sep 17 00:00:00 2001 From: jinbei09 Date: Wed, 27 Mar 2024 14:54:32 +0800 Subject: [PATCH 08/16] [M120 Migration][NaCl][PPFwk]Use GetWaylandWindowId to get window id For chromium aura, Previously the 'GetWaylandWindowId' api can't return window id normally, so use ecore_evas_gl_x11_window_get instead. This will lead to the app can not get the window id correctly. For latest chromium aura, 'GetWaylandWindowId' can return window id normally, so use it to fix the issue Migrated from tizen 8.0: https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/304538/ Change-Id: Iac8cf838da27e55dc11710cd79b8583ef48891cb Signed-off-by: jinbei09 --- tizen_src/ewk/efl_integration/ewk_extension_system_delegate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tizen_src/ewk/efl_integration/ewk_extension_system_delegate.cc b/tizen_src/ewk/efl_integration/ewk_extension_system_delegate.cc index 1eefb1a..48c3c73 100644 --- a/tizen_src/ewk/efl_integration/ewk_extension_system_delegate.cc +++ b/tizen_src/ewk/efl_integration/ewk_extension_system_delegate.cc @@ -252,7 +252,7 @@ void EwkExtensionSystemDelegate::SetWindowId(const Evas_Object* main_window) { LOG(ERROR) << "Ecore_Evas can`t be acquired from main window Evas"; return; } -#if defined(USE_WAYLAND)&&!defined(USE_AURA) +#if defined(USE_WAYLAND) #if TIZEN_VERSION_AT_LEAST(5, 0, 0) Ecore_Wl2_Window* ww = ecore_evas_wayland2_window_get(ee); #else -- 2.7.4 From d770c486fd14d09491571f9f35d44c60534eb372 Mon Sep 17 00:00:00 2001 From: "peng.yin" Date: Tue, 6 Jun 2023 14:47:24 +0800 Subject: [PATCH 09/16] [M120 Migration][WebRTC] Tbm mapping buffer support in webrtc video sink video frame with PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER format is not correctly handled in webrtc video sink pipe, this format is same as NV12 actually, so add same logic as NV12 format to handle it. Change-Id: Id54be9723f86910c397aea8ecc9bfece25070fe0 Signed-off-by: peng.yin --- media/base/video_util.cc | 16 ++++++++-- .../webrtc/convert_to_webrtc_video_frame_buffer.cc | 35 +++++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/media/base/video_util.cc b/media/base/video_util.cc index aa61c52..d21b1d2 100644 --- a/media/base/video_util.cc +++ b/media/base/video_util.cc @@ -811,7 +811,12 @@ EncoderStatus ConvertAndScaleFrame(const VideoFrame& src_frame, VideoPixelFormatToString(src_frame.format()), "dst_format", VideoPixelFormatToString(dst_frame.format())); constexpr auto kDefaultFiltering = libyuv::kFilterBox; - if (!src_frame.IsMappable() || !dst_frame.IsMappable()) + if ((!src_frame.IsMappable() +#if defined(TIZEN_TBM_SUPPORT) + && src_frame.format() != PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER +#endif + ) || + !dst_frame.IsMappable()) return EncoderStatus::Codes::kUnsupportedFrameFormat; if ((dst_frame.format() == PIXEL_FORMAT_I420A || @@ -952,6 +957,9 @@ EncoderStatus ConvertAndScaleFrame(const VideoFrame& src_frame, if ((dst_frame.format() == PIXEL_FORMAT_NV12 || dst_frame.format() == PIXEL_FORMAT_NV12A) && (src_frame.format() == PIXEL_FORMAT_NV12 || +#if defined(TIZEN_TBM_SUPPORT) + src_frame.format() == PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER || +#endif src_frame.format() == PIXEL_FORMAT_NV12A)) { if (dst_frame.format() == PIXEL_FORMAT_NV12A) { libyuv::ScalePlane( @@ -981,7 +989,11 @@ EncoderStatus ConvertAndScaleFrame(const VideoFrame& src_frame, } if (dst_frame.format() == PIXEL_FORMAT_I420 && - src_frame.format() == PIXEL_FORMAT_NV12) { + ( +#if defined(TIZEN_TBM_SUPPORT) + src_frame.format() == PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER || +#endif + src_frame.format() == PIXEL_FORMAT_NV12)) { if (src_frame.visible_rect().size() == dst_frame.visible_rect().size()) { // Both frames have the same size, only NV12-to-I420 conversion is // required. diff --git a/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc b/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc index 770f54b..7fc4d98 100644 --- a/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc +++ b/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc @@ -181,6 +181,11 @@ rtc::scoped_refptr MakeFrameAdapter( case media::PIXEL_FORMAT_NV12: return rtc::scoped_refptr( new rtc::RefCountedObject(std::move(video_frame))); +#if defined(TIZEN_TBM_SUPPORT) + case media::PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER: + return rtc::scoped_refptr( + new rtc::RefCountedObject(std::move(video_frame))); +#endif default: NOTREACHED(); return nullptr; @@ -195,7 +200,9 @@ scoped_refptr MakeScaledVideoFrame( media::VideoPixelFormat dst_format = media::PIXEL_FORMAT_UNKNOWN; bool tmp_buffer_needed = false; if (source_is_nv12) { +#if !defined(TIZEN_TBM_SUPPORT) DCHECK_EQ(source_frame->format(), media::PIXEL_FORMAT_NV12); +#endif dst_format = media::PIXEL_FORMAT_NV12; } else { // ARGB pixel format may be produced by readback of texture backed frames. @@ -253,6 +260,10 @@ scoped_refptr MaybeConvertAndScaleFrame( source_frame->format() == media::PIXEL_FORMAT_ARGB || source_frame->format() == media::PIXEL_FORMAT_XRGB || source_frame->format() == media::PIXEL_FORMAT_ABGR || +#if defined(TIZEN_TBM_SUPPORT) + source_frame->format() == + media::PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER || +#endif source_frame->format() == media::PIXEL_FORMAT_XBGR); RTC_DCHECK(shared_resources); @@ -260,6 +271,9 @@ scoped_refptr MaybeConvertAndScaleFrame( source_frame->format() == media::PIXEL_FORMAT_I420 || source_frame->format() == media::PIXEL_FORMAT_I420A; const bool source_is_nv12 = +#if defined(TIZEN_TBM_SUPPORT) + source_frame->format() == media::PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER || +#endif source_frame->format() == media::PIXEL_FORMAT_NV12; const bool no_scaling_needed = source_frame->natural_size() == source_frame->visible_rect().size(); @@ -288,7 +302,14 @@ bool CanConvertToWebRtcVideoFrameBuffer(const media::VideoFrame* frame) { #if defined(TIZEN_VIDEO_HOLE) frame->storage_type() == media::VideoFrame::STORAGE_HOLE || #endif - frame->format() == media::PIXEL_FORMAT_ENCODED || frame->HasTextures(); +#if BUILDFLAG(IS_TIZEN) + frame->format() == media::PIXEL_FORMAT_ENCODED || +#if defined(TIZEN_TBM_SUPPORT) + frame->format() == + media::VideoPixelFormat::PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER || +#endif +#endif + frame->HasTextures(); } // static @@ -324,6 +345,18 @@ rtc::scoped_refptr ConvertToWebRtcVideoFrameBuffer( video_frame->timestamp())); } return MakeFrameAdapter(std::move(converted_frame)); +#if defined(TIZEN_TBM_SUPPORT) + } else if (video_frame->format() == + media::VideoPixelFormat::PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER) { + // the video frame with tbm buffer type is native, handle it here + scoped_refptr scaled_frame = + MaybeConvertAndScaleFrame(video_frame, shared_resources); + if (!scaled_frame) { + DLOG(ERROR) << "Make scaled frame failed."; + return MakeFrameAdapter(std::move(video_frame)); + } + return MakeFrameAdapter(std::move(scaled_frame)); +#endif } else if (video_frame->HasTextures()) { auto converted_frame = shared_resources -- 2.7.4 From c5b20b17413fabb6821e5f10fe144cbd66ed40a7 Mon Sep 17 00:00:00 2001 From: jiangyuwei Date: Mon, 8 Apr 2024 16:34:14 +0800 Subject: [PATCH 10/16] [M120 Migration] Add error check when get system info Add error check when get system info. References: - https://review.tizen.org/gerrit/#/c/295962/ Change-Id: I8fdf2e49049ee3c05802b63dc6dfe9443170704b Signed-off-by: jiangyuwei --- tizen_src/chromium_impl/tizen/system_info.cc | 56 +++++++++++++++------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/tizen_src/chromium_impl/tizen/system_info.cc b/tizen_src/chromium_impl/tizen/system_info.cc index 30223cd..569ee0d 100644 --- a/tizen_src/chromium_impl/tizen/system_info.cc +++ b/tizen_src/chromium_impl/tizen/system_info.cc @@ -26,8 +26,19 @@ void GetProfile(void) { return; #if BUILDFLAG(IS_TIZEN) - char *profileName; - system_info_get_platform_string("http://tizen.org/feature/profile", &profileName); + char* profileName = nullptr; + int result = system_info_get_platform_string( + "http://tizen.org/feature/profile", &profileName); + + if (result != SYSTEM_INFO_ERROR_NONE || !profileName) { +#if (IS_TIZEN_TV) + g_profile__ = PROFILE_TV; +#else + g_profile__ = PROFILE_COMMON; +#endif + free(profileName); + return; + } #if defined(ARCH_CPU_RISCV_FAMILY) if (const char* env_profile = std::getenv(PROFILE_ENV_STRING)) { @@ -97,30 +108,23 @@ void GetArch(void) { if (g_arch__ != ARCH_UNKNOWN) return; - char *archName; - system_info_get_platform_string("http://tizen.org/feature/platform.core.cpu.arch", &archName); - - int archNamelen = strlen(archName); - if (strncmp(archName, "armv7", archNamelen) == 0) { - g_arch__ = ARCH_ARMV7; - } - else if (strncmp(archName, "aarch64", archNamelen) == 0) { - g_arch__ = ARCH_AARCH64; - } - else if (strncmp(archName, "x86", archNamelen) == 0) { - g_arch__ = ARCH_X86; - } - else if (strncmp(archName, "x86_64", archNamelen) == 0) { - g_arch__ = ARCH_X86_64; - } - else if (strncmp(archName, "rv32", archNamelen) == 0) { - g_arch__ = ARCH_RV32; - } - else if (strncmp(archName, "rv64", archNamelen) == 0) { - g_arch__ = ARCH_RV64; - } - else { - g_arch__ = ARCH_UNKNOWN; + char* archName = nullptr; + int result = system_info_get_platform_string( + "http://tizen.org/feature/platform.core.cpu.arch", &archName); + + if (result == SYSTEM_INFO_ERROR_NONE && archName) { + int archNamelen = strlen(archName); + if (strncmp(archName, "armv7", archNamelen) == 0) { + g_arch__ = ARCH_ARMV7; + } else if (strncmp(archName, "aarch64", archNamelen) == 0) { + g_arch__ = ARCH_AARCH64; + } else if (strncmp(archName, "x86", archNamelen) == 0) { + g_arch__ = ARCH_X86; + } else if (strncmp(archName, "x86_64", archNamelen) == 0) { + g_arch__ = ARCH_X86_64; + } else { + g_arch__ = ARCH_UNKNOWN; + } } free(archName); #endif -- 2.7.4 From db6f0fd85ee8ecac255b0975cd6bdca6d66996fc Mon Sep 17 00:00:00 2001 From: "peng.yin" Date: Mon, 8 Apr 2024 09:20:13 +0800 Subject: [PATCH 11/16] [M120 Migration][WebRTC] Merge fixup patches fixup!fixup![M108 Aura Migration][MM][WebRtc] New implementation for local stream renderer https://review.tizen.org/gerrit/#/c/293279/ Fixup! [M108 Migration] Support camera to canvas feature https://review.tizen.org/gerrit/#/c/292855/ Optimize video hole frame updates https://review.tizen.org/gerrit/#/c/291925/ fixup! [VD][MM] Get H264 max_res from RS on M108 https://review.tizen.org/gerrit/#/c/301521/ [MM] Do not perform operation by buffering state during in low latency mode. https://review.tizen.org/gerrit/#/c/301932/ Change-Id: I4046fb2ebee17c9305f1d7c38e21841398bce2b4 Signed-off-by: peng.yin --- gpu/ipc/client/command_buffer_proxy_impl.cc | 1 + media/base/video_frame.h | 3 + media/mojo/mojom/media_types.mojom | 2 + .../mojom/video_decoder_config_mojom_traits.cc | 6 ++ .../mojo/mojom/video_decoder_config_mojom_traits.h | 7 ++ .../modules/mediastream/webmediaplayer_ms.cc | 49 ++++++++++++ .../mediastream/webmediaplayer_ms_compositor.cc | 53 ++++++++++++- .../mediastream/webmediaplayer_ms_compositor.h | 6 +- .../media/filters/media_player_esplusplayer.cc | 48 ++++++++++-- .../media/filters/media_player_esplusplayer.h | 3 +- .../filters/media_player_esplusplayer_common.cc | 3 +- .../filters/media_player_esplusplayer_common.h | 2 +- .../media/filters/media_player_esplusplayer_tv.cc | 86 +++++++++++++++++++--- .../media/filters/media_player_esplusplayer_tv.h | 4 +- tizen_src/chromium_impl/ui/gfx/tbm_buffer_handle.h | 12 +++ ui/gfx/gpu_memory_buffer.h | 5 ++ ui/gfx/mojom/BUILD.gn | 4 + ui/gfx/mojom/buffer_types.mojom | 13 ++++ ui/gfx/mojom/buffer_types_mojom_traits.cc | 2 + ui/gfx/mojom/buffer_types_mojom_traits.h | 38 +++++++++- 20 files changed, 320 insertions(+), 27 deletions(-) diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc index 7c88a96..e820e74 100644 --- a/gpu/ipc/client/command_buffer_proxy_impl.cc +++ b/gpu/ipc/client/command_buffer_proxy_impl.cc @@ -447,6 +447,7 @@ int32_t CommandBufferProxyImpl::CreateEGLImage( } handle.width = width; handle.height = height; + handle.tbm_destroy_type = buffer_handle.tbm_destroy_type; params->gpu_memory_buffer = std::move(handle); command_buffer_->CreateImage(std::move(params)); diff --git a/media/base/video_frame.h b/media/base/video_frame.h index f31ae5b..d47128e 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h @@ -416,6 +416,9 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe { scoped_refptr context_provider) { context_provider_ = context_provider; } + void SetTbmDestroyType(gfx::TbmDestroyType type) { + buffer_handle_.tbm_destroy_type = type; + } #endif // Creates a frame which indicates end-of-stream. diff --git a/media/mojo/mojom/media_types.mojom b/media/mojo/mojom/media_types.mojom index 7ea0505..7da8210 100644 --- a/media/mojo/mojom/media_types.mojom +++ b/media/mojo/mojom/media_types.mojom @@ -197,6 +197,8 @@ struct VideoDecoderConfig { VideoColorSpace color_space_info; gfx.mojom.HDRMetadata? hdr_metadata; bool is_rtc; + [EnableIf=tizen_multimedia] + gfx.mojom.Size max_coded_size; [EnableIf=is_tizen_tv] string hdr_info; [EnableIf=is_tizen_tv] diff --git a/media/mojo/mojom/video_decoder_config_mojom_traits.cc b/media/mojo/mojom/video_decoder_config_mojom_traits.cc index dcf30fa..160c7fd 100644 --- a/media/mojo/mojom/video_decoder_config_mojom_traits.cc +++ b/media/mojo/mojom/video_decoder_config_mojom_traits.cc @@ -75,6 +75,12 @@ bool StructTraitsset_framerate_den(input.framerate_den()); #endif +#if defined(TIZEN_MULTIMEDIA) + gfx::Size max_coded_size; + input.ReadMaxCodedSize(&max_coded_size); + output->set_max_coded_size(max_coded_size); +#endif + if (!output->IsValidConfig()) return false; diff --git a/media/mojo/mojom/video_decoder_config_mojom_traits.h b/media/mojo/mojom/video_decoder_config_mojom_traits.h index 204c0ab..8046361 100644 --- a/media/mojo/mojom/video_decoder_config_mojom_traits.h +++ b/media/mojo/mojom/video_decoder_config_mojom_traits.h @@ -92,6 +92,13 @@ struct StructTraits decoded_frame) { + base::AutoLock auto_lock(request_frame_lock_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + // update decoded frame + decoded_video_frame_ = decoded_frame; + request_frame_waiter_.Signal(); +} +#endif + void WebMediaPlayerMS::Paint(cc::PaintCanvas* canvas, const gfx::Rect& rect, cc::PaintFlags& flags) { DVLOG(3) << __func__; DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_TBM_SUPPORT) && \ + defined(TIZEN_MULTIMEDIA) + LOG(INFO) << __func__ << ", rect " << rect.ToString(); + scoped_refptr decoded_frame = + compositor_->GetCurrentFrame(); + + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + if (command_line.HasSwitch(switches::kEnableFrameRawDataCopy) && + (!decoded_frame || + decoded_frame->storage_type() == media::VideoFrame::STORAGE_HOLE)) { + frame_deliverer_->RequestVideoDecodedBuffer(); + for (int i = 0; i < 3; ++i) { + SendVideoDecodedBufferRequest(); + // need to wait some time to ensure decoded frame have return. + bool signaled = + request_frame_waiter_.TimedWait( // FIXME: will block UI thread + base::Milliseconds(22)); // wait max 22ms + if (signaled) { + break; + } + } + base::AutoLock auto_lock(request_frame_lock_); + decoded_frame = decoded_video_frame_; + + // Prevent to paint a black screen when a decoded frame is not prepared. + if (!decoded_frame) + return; + } + + const scoped_refptr frame = decoded_frame; +#else const scoped_refptr frame = compositor_->GetCurrentFrame(); +#endif scoped_refptr provider; if (frame && frame->HasTextures()) { @@ -1167,6 +1211,11 @@ void WebMediaPlayerMS::Paint(cc::PaintCanvas* canvas, const gfx::RectF dest_rect(rect); video_renderer_.Paint(frame, canvas, dest_rect, flags, GetFrameTransformation(frame), provider.get()); +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_TBM_SUPPORT) + // Do not keep decoded video frame resource here, + // renderer will paint black rectangle if no new decoded frame + decoded_video_frame_ = nullptr; +#endif } scoped_refptr WebMediaPlayerMS::GetCurrentFrameThenUpdate() { diff --git a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc index 337cf39..d4938d9 100644 --- a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc +++ b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc @@ -63,7 +63,13 @@ scoped_refptr CopyFrame( scoped_refptr frame, media::PaintCanvasVideoRenderer* video_renderer) { scoped_refptr new_frame; +#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE) + if (frame->storage_type() == media::VideoFrame::STORAGE_HOLE) { + new_frame = media::VideoFrame::CreateHoleFrame(frame->natural_size()); + } else if (frame->HasTextures()) { +#else if (frame->HasTextures()) { +#endif DCHECK(frame->format() == media::PIXEL_FORMAT_ARGB || frame->format() == media::PIXEL_FORMAT_XRGB || frame->format() == media::PIXEL_FORMAT_ABGR || @@ -367,6 +373,9 @@ void WebMediaPlayerMSCompositor::SetVideoFrameProviderClient( video_frame_provider_client_->StopUsingProvider(); video_frame_provider_client_ = client; +#if defined(TIZEN_VIDEO_HOLE) + video_frame_provider_client_changed_ = true; +#endif if (video_frame_provider_client_ && !stopped_) video_frame_provider_client_->StartRendering(); } @@ -440,6 +449,15 @@ void WebMediaPlayerMSCompositor::EnqueueFrame( return; } +#if defined(TIZEN_VIDEO_HOLE) + // Turn off rendering algorithm for pure video-hole frames + if (frame->storage_type() == media::VideoFrame::STORAGE_HOLE) { + rendering_frame_buffer_.reset(); + RenderWithoutAlgorithm(std::move(frame), is_copy); + return; + } +#endif + // This is a signal frame saying that the stream is stopped. if (frame->metadata().end_of_stream) { rendering_frame_buffer_.reset(); @@ -707,6 +725,14 @@ void WebMediaPlayerMSCompositor::RenderWithoutAlgorithmOnCompositor( scoped_refptr frame, bool is_copy) { DCHECK(video_frame_compositor_task_runner_->BelongsToCurrentThread()); + bool frame_size_changed = true; + bool is_video_hole = false; + bool provider_changed = true; +#if defined(TIZEN_VIDEO_HOLE) + is_video_hole = frame->storage_type() == media::VideoFrame::STORAGE_HOLE; + provider_changed = video_frame_provider_client_changed_; +#endif + { base::AutoLock auto_lock(current_frame_lock_); // Last timestamp in the stream might not have timestamp. @@ -714,13 +740,22 @@ void WebMediaPlayerMSCompositor::RenderWithoutAlgorithmOnCompositor( frame->timestamp() > current_frame_->timestamp()) { last_render_length_ = frame->timestamp() - current_frame_->timestamp(); } - SetCurrentFrame(std::move(frame), is_copy, absl::nullopt); + frame_size_changed = + SetCurrentFrame(std::move(frame), is_copy, absl::nullopt); } - if (video_frame_provider_client_) + + if (is_video_hole && !frame_size_changed && !provider_changed) + return; + + if (video_frame_provider_client_) { video_frame_provider_client_->DidReceiveFrame(); + } +#if defined(TIZEN_VIDEO_HOLE) + video_frame_provider_client_changed_ = false; +#endif } -void WebMediaPlayerMSCompositor::SetCurrentFrame( +bool WebMediaPlayerMSCompositor::SetCurrentFrame( scoped_refptr frame, bool is_copy, absl::optional expected_display_time) { @@ -732,12 +767,14 @@ void WebMediaPlayerMSCompositor::SetCurrentFrame( if (!current_frame_rendered_) ++dropped_frame_count_; + bool previous_frame_rendered = current_frame_rendered_; current_frame_rendered_ = false; // Compare current frame with |frame|. Initialize values as if there is no // current frame. bool is_first_frame = true; bool has_frame_size_changed = false; + bool frame_content_did_not_change = false; absl::optional new_transform = media::kNoTransformation; @@ -764,8 +801,17 @@ void WebMediaPlayerMSCompositor::SetCurrentFrame( if (*new_opacity == media::IsOpaque(current_frame_->format())) new_opacity.reset(); +#if defined(TIZEN_VIDEO_HOLE) + if (frame->storage_type() == media::VideoFrame::STORAGE_HOLE && + current_frame_->storage_type() == media::VideoFrame::STORAGE_HOLE && + !has_frame_size_changed) { + frame_content_did_not_change = true; + } +#endif } + if (frame_content_did_not_change) + current_frame_rendered_ = previous_frame_rendered; current_frame_ = std::move(frame); current_frame_is_copy_ = is_copy; SetMetadata(); @@ -802,6 +848,7 @@ void WebMediaPlayerMSCompositor::SetCurrentFrame( CrossThreadBindOnce(&WebMediaPlayerMSCompositor::CheckForFrameChanges, weak_this_, is_first_frame, has_frame_size_changed, std::move(new_transform), std::move(new_opacity))); + return has_frame_size_changed || is_first_frame; } void WebMediaPlayerMSCompositor::CheckForFrameChanges( diff --git a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h index 9b81ccb..ec68749 100644 --- a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h +++ b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h @@ -199,7 +199,7 @@ class MODULES_EXPORT WebMediaPlayerMSCompositor bool is_copy); // Update |current_frame_| and |dropped_frame_count_| - void SetCurrentFrame( + bool SetCurrentFrame( scoped_refptr frame, bool is_copy, absl::optional expected_presentation_time); @@ -248,6 +248,10 @@ class MODULES_EXPORT WebMediaPlayerMSCompositor raw_ptr video_frame_provider_client_; +#if defined(TIZEN_VIDEO_HOLE) + bool video_frame_provider_client_changed_{false}; +#endif + // |current_frame_| is updated only on compositor thread. The object it // holds can be freed on the compositor thread if it is the last to hold a // reference but media::VideoFrame is a thread-safe ref-pointer. It is diff --git a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer.cc b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer.cc index 6b1d9f3..af00b63 100644 --- a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer.cc +++ b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer.cc @@ -245,7 +245,7 @@ void MediaPlayerESPlusPlayer::Initialize(VideoRendererSink* sink) { LOG(INFO) << "(" << static_cast(this) << ") " << __func__ << " state:" << GetString(GetPlayerState()); - if (!SetBufferType()) + if (!SetBufferType(VideoDecoderConfig{})) return; sink_ = sink; @@ -653,8 +653,11 @@ player_buffer_size_t MediaPlayerESPlusPlayer::GetMaxVideoBufferSize( int MediaPlayerESPlusPlayer::SetVideoStreamInfo( const media::VideoDecoderConfig& video_config, esplusplayer_video_stream_info& video_stream_info) { - video_stream_info.width = video_config.coded_size().width(); - video_stream_info.height = video_config.coded_size().height(); + if (!SetBufferType(video_config)) { + LOG_ID(ERROR, player_id_) << "SetBufferType failed."; + return ESPLUSPLAYER_ERROR_TYPE_UNKNOWN; + } + video_stream_info.mime_type = ConvertToESPlusVideoMimeType(video_config.codec()); @@ -668,12 +671,36 @@ int MediaPlayerESPlusPlayer::SetVideoStreamInfo( } else { video_stream_info.codec_data = nullptr; } - auto max_resolution = + auto ri_max_resolution = GetMaxResolution(video_stream_info.mime_type, is_video_hole_); - LOG(INFO) << "max resolution: " << max_resolution.ToString(); - - video_stream_info.max_width = max_resolution.width(); - video_stream_info.max_height = max_resolution.height(); + // |video_resolution| is the current video size, |video_max_resolution| + // is the potential max video size, it to say that the video source + // size may be changed to that size in playback state dynamically. + // for every video playback scenarios, the caller should set it to a + // suitable value to |video_max_resolution| to avoid decoder resource + // waste or resource conflicts. + auto video_max_resolution = video_config.max_coded_size(); + auto video_resolution = video_config.coded_size(); + LOG_ID(INFO, player_id_) << "Available max resolution from resource manager:" + << ri_max_resolution.ToString() + << " video max resolution:" + << video_max_resolution.ToString() + << " video resolution:" + << video_resolution.ToString(); + + // Correct the video max resolution if it is smaller than video resolution. + video_max_resolution.SetToMax(video_resolution); + + // Constrain the video resolution within the ri max resolution. + video_resolution.SetToMin(ri_max_resolution); + + // Constrain the video max resolution within the ri max resolution. + video_max_resolution.SetToMin(ri_max_resolution); + + video_stream_info.max_width = video_max_resolution.width(); + video_stream_info.max_height = video_max_resolution.height(); + video_stream_info.width = video_resolution.width(); + video_stream_info.height = video_resolution.height(); return ESPLUSPLAYER_ERROR_TYPE_NONE; } @@ -990,6 +1017,11 @@ void MediaPlayerESPlusPlayer::ReportBufferingStateIfNeeded( } void MediaPlayerESPlusPlayer::PerformOperationForData() { + // The low latency mode doesn't buffer packets. It decodes and renders + // a packet at once. WebRtc uses this feature. + if (is_video_low_latency_) + return; + if (is_seeking_ || is_preparing_) return; diff --git a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer.h b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer.h index ec62e6b..8e8a9bc 100644 --- a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer.h +++ b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer.h @@ -139,12 +139,13 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayer : public MediaPlayerTizen { void SetShouldFeed(DemuxerStream::Type type, bool value); bool ReadRequested(DemuxerStream::Type type) const; void ReadBuffer(DemuxerStream::Type type); - virtual bool SetBufferType() = 0; + virtual bool SetBufferType(const media::VideoDecoderConfig&) = 0; #if defined(TIZEN_VIDEO_HOLE) void PrepareVideoHole() override; #endif bool is_video_hole_ = false; + bool is_video_low_latency_ = false; int player_id_ = 0; // first -> pts, second -> duration base::StaticMap(this) << ") " << __func__; } -bool MediaPlayerESPlusPlayerCommon::SetBufferType() { +bool MediaPlayerESPlusPlayerCommon::SetBufferType( + const media::VideoDecoderConfig&) { if (GetPlayerState() != ESPLUSPLAYER_STATE_IDLE) return true; diff --git a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_common.h b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_common.h index 48eb779..3d2fd6e 100644 --- a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_common.h +++ b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_common.h @@ -15,7 +15,7 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayerCommon MediaPlayerESPlusPlayerCommon(); ~MediaPlayerESPlusPlayerCommon() override; - bool SetBufferType() override; + bool SetBufferType(const media::VideoDecoderConfig&) override; void ToggleFullscreenMode(bool is_fullscreen) override; #if defined(TIZEN_VIDEO_HOLE) void PrepareVideoHole() override; diff --git a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.cc b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.cc index a56e135..f76d963 100644 --- a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.cc +++ b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.cc @@ -219,17 +219,85 @@ player_buffer_size_t MediaPlayerESPlusPlayerTV::GetMaxVideoBufferSize( return total_buffer_size - kPlayerAudioBufferSize; } -bool MediaPlayerESPlusPlayerTV::SetBufferType() { - esplusplayer_decoded_video_frame_buffer_type video_frame_buffer_type = - is_video_hole_ ? ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_NONE - : ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_COPY; +void MediaPlayerESPlusPlayerTV::SetTbmCallbackPolicy( + const media::VideoDecoderConfig& video_config) { + auto policy = ESPLUSPLAYER_RSC_ALLOC_EXCLUSIVE; +#if TIZEN_VERSION_AT_LEAST(8, 0, 0) + // Although we set the decoder config to fit the spec of mfc decoder in + // hopes of getting its priority, some other tizen apps (e.g. live TV) may + // still hold the mfc even they go into background. so it requires us to set + // proper RM policy to force ESPP to acquire a mfc decoder ownership from + // these apps. + policy = ESPLUSPLAYER_RSC_ALLOC_EXCLUSIVE_MFC_FORCED; +#endif // TIZEN_VERSION_AT_LEAST(8, 0, 0) + +#if defined(TIZEN_MULTIMEDIA_MJPEG_SUPPORT) + if (video_config.codec() == VideoCodec::kMJPEG) { + policy = ESPLUSPLAYER_RSC_ALLOC_EXCLUSIVE; + } +#endif // defined(TIZEN_MULTIMEDIA_MJPEG_SUPPORT) + LOG_ID(INFO, player_id_) << " Set RM policy for Tbm:" + << static_cast(policy); + + auto error = esplusplayer_set_resource_allocate_policy(esplayer_, policy); + if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) { + LOG_ID(ERROR, player_id_) + << "esplusplayer_set_resource_allocate_policy failed. error #" + << esplusplayer_get_error_string( + static_cast(error)); + } +} - int error = esplusplayer_set_video_frame_buffer_type(esplayer_, - video_frame_buffer_type); +bool MediaPlayerESPlusPlayerTV::SetBufferType( + const media::VideoDecoderConfig& video_config) { + if (!video_config.IsValidConfig()) { + LOG_ID(INFO, player_id_) << "Invalid video config."; + return false; + } + + if (enable_tbm_buffer_callback_) { + LOG_ID(INFO, player_id_) << "Recall EnableTbmBufferCallback."; + SetTbmCallbackPolicy(video_config); + EnableTbmBufferCallback(true); + return true; + } + + if (!is_video_hole_) { + decoded_frame_buffer_type_ = + ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_COPY; + } + +#if defined(TIZEN_VIDEO_HOLE) && defined(TIZEN_TBM_SUPPORT) && \ + TIZEN_VERSION_AT_LEAST(6, 5, 0) + bool enable_frame_raw_data_copy = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableFrameRawDataCopy); + LOG_ID(INFO, player_id_) << "(" << static_cast(this) << ") " + << __func__ << ", kEnableFrameRawDataCopy: " + << enable_frame_raw_data_copy; + + if (video_config.enable_manual_copy()) { + // `enable_manual_copy` means there is a potential requirement to enable + // TBM decoded data return, but this function is only available on mfc & + // mjpeg decoders. + SetTbmCallbackPolicy(video_config); + + if (is_video_hole_ && !is_video_drm_eme_ && enable_frame_raw_data_copy) { + // should ensure App can get frame buffer by canvas2d API drawImage and + // getImageData + decoded_frame_buffer_type_ = + ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_MANUAL_COPY; + } + } +#endif + + int error = esplusplayer_set_video_frame_buffer_type( + esplayer_, decoded_frame_buffer_type_); if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) { - LOG(ERROR) << "esplusplayer_set_video_frame_buffer_type failed. error #" - << esplusplayer_get_error_string( - static_cast(error)); + LOG_ID(ERROR, player_id_) + << "esplusplayer_set_video_frame_buffer_type failed. error #" + << esplusplayer_get_error_string( + static_cast(error)); return false; } diff --git a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.h b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.h index 0a23727..8aa5b27 100644 --- a/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.h +++ b/tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.h @@ -66,9 +66,10 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayerTV : public MediaPlayerESPlusPlayer { DemuxerStream::Type type, scoped_refptr buffer) override; void InitializeStreamConfig(DemuxerStream::Type type) override; - bool SetBufferType() override; + bool SetBufferType(const media::VideoDecoderConfig& video_config) override; player_buffer_size_t GetMaxVideoBufferSize( const media::VideoDecoderConfig& video_config) override; + void SetTbmCallbackPolicy(const media::VideoDecoderConfig& video_config); private: #if TIZEN_VERSION_AT_LEAST(6, 0, 0) @@ -118,7 +119,6 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayerTV : public MediaPlayerESPlusPlayer { bool is_hdr_changed_{false}; esplusplayer_matroska_color matroska_color_; - bool is_video_low_latency_{false}; esplusplayer_decoded_video_frame_buffer_type decoded_frame_buffer_type_{ ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_NONE}; bool enable_tbm_buffer_callback_{false}; diff --git a/tizen_src/chromium_impl/ui/gfx/tbm_buffer_handle.h b/tizen_src/chromium_impl/ui/gfx/tbm_buffer_handle.h index 1bef1ed..ea7dab6 100644 --- a/tizen_src/chromium_impl/ui/gfx/tbm_buffer_handle.h +++ b/tizen_src/chromium_impl/ui/gfx/tbm_buffer_handle.h @@ -15,12 +15,24 @@ #endif namespace gfx { +#if defined(TIZEN_TBM_SUPPORT) +// There are 2 flows could trigger TBM destroy: GLImageEGL::~GLImageEGL() +// and TizenEsPlusPlayerRenderer::ReleaseTbmBuffer; +// Define a type to specify how to destroy TBM. +enum TbmDestroyType { + // triggered by GLImageEGL::~GLImageEGL() + kDestroyTbmByEgl = 0, + // triggered by video frame DestructionObserver + kDestroyTbmByVideoFrame = 1, +}; +#endif struct GFX_EXPORT TbmBufferHandle { TbmBufferHandle() {} #if defined(TIZEN_TBM_SUPPORT) size_t tbm_surface{0}; size_t media_packet{0}; + TbmDestroyType tbm_destroy_type = kDestroyTbmByEgl; int32_t player_id = 0; int32_t key_num = 0; int32_t key[4]; diff --git a/ui/gfx/gpu_memory_buffer.h b/ui/gfx/gpu_memory_buffer.h index 74be880..56272bb 100644 --- a/ui/gfx/gpu_memory_buffer.h +++ b/ui/gfx/gpu_memory_buffer.h @@ -27,6 +27,10 @@ #include "base/android/scoped_hardware_buffer_handle.h" #endif +#if defined(TIZEN_TBM_SUPPORT) +#include "ui/gfx/tbm_buffer_handle.h" +#endif + namespace base { namespace trace_event { class ProcessMemoryDump; @@ -88,6 +92,7 @@ struct GFX_EXPORT GpuMemoryBufferHandle { #if defined(TIZEN_TBM_SUPPORT) size_t tbm_surface{0}; size_t media_packet{0}; + TbmDestroyType tbm_destroy_type = kDestroyTbmByEgl; int32_t player_id = 0; int32_t key_num = 0; int32_t key[4]; diff --git a/ui/gfx/mojom/BUILD.gn b/ui/gfx/mojom/BUILD.gn index 2a5a793..bbfb870 100644 --- a/ui/gfx/mojom/BUILD.gn +++ b/ui/gfx/mojom/BUILD.gn @@ -88,6 +88,10 @@ mojom("mojom") { copyable_pass_by_value = true }, { + mojom = "gfx.mojom.TbmDestroyType" + cpp = "::gfx::TbmDestroyType" + }, + { mojom = "gfx.mojom.GpuMemoryBufferType" cpp = "::gfx::GpuMemoryBufferType" }, diff --git a/ui/gfx/mojom/buffer_types.mojom b/ui/gfx/mojom/buffer_types.mojom index c285550..88c3c04 100644 --- a/ui/gfx/mojom/buffer_types.mojom +++ b/ui/gfx/mojom/buffer_types.mojom @@ -62,6 +62,13 @@ struct GpuMemoryBufferId { int32 id; }; +// gfx::TbmDestroyType +[EnableIf=tizen_tbm_support] +enum TbmDestroyType { + kDestroyTbmByEgl = 0, + kDestroyTbmByVideoFrame = 1, +}; + // gfx::GpuMemoryBufferHandle struct GpuMemoryBufferHandle { GpuMemoryBufferId id; @@ -75,6 +82,9 @@ struct GpuMemoryBufferHandle { uint64 media_packet; [EnableIf=tizen_tbm_support] + TbmDestroyType tbm_destroy_type; + + [EnableIf=tizen_tbm_support] int32 player_id; [EnableIf=tizen_tbm_support] @@ -104,6 +114,9 @@ struct TbmBufferHandle { uint32 media_packet; [EnableIf=tizen_tbm_support] + TbmDestroyType tbm_destroy_type; + + [EnableIf=tizen_tbm_support] int32 player_id; [EnableIf=tizen_tbm_support] diff --git a/ui/gfx/mojom/buffer_types_mojom_traits.cc b/ui/gfx/mojom/buffer_types_mojom_traits.cc index 5f95c30..d990b94 100644 --- a/ui/gfx/mojom/buffer_types_mojom_traits.cc +++ b/ui/gfx/mojom/buffer_types_mojom_traits.cc @@ -105,6 +105,7 @@ bool StructTraitskey_num = data.key_num(); out->width = data.width(); out->height = data.height(); + data.ReadTbmDestroyType(&out->tbm_destroy_type); base::span key(out->key); if (!data.ReadKey(&key)) return false; @@ -206,6 +207,7 @@ bool StructTraits:: out->key_num = data.key_num(); out->width = data.width(); out->height = data.height(); + data.ReadTbmDestroyType(&out->tbm_destroy_type); base::span key(out->key); if (!data.ReadKey(&key)) return false; diff --git a/ui/gfx/mojom/buffer_types_mojom_traits.h b/ui/gfx/mojom/buffer_types_mojom_traits.h index 609f420..2146030 100644 --- a/ui/gfx/mojom/buffer_types_mojom_traits.h +++ b/ui/gfx/mojom/buffer_types_mojom_traits.h @@ -266,6 +266,10 @@ struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS) static int32_t height(const gfx::GpuMemoryBufferHandle& handle) { return handle.height; } + static gfx::TbmDestroyType tbm_destroy_type( + const gfx::GpuMemoryBufferHandle& handle) { + return handle.tbm_destroy_type; + } #endif static mojo::StructPtr platform_handle(gfx::GpuMemoryBufferHandle& handle); @@ -300,10 +304,42 @@ struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS) static int32_t height(const gfx::TbmBufferHandle& handle) { return handle.height; } - + static gfx::TbmDestroyType tbm_destroy_type( + const gfx::TbmBufferHandle& handle) { + return handle.tbm_destroy_type; + } static bool Read(gfx::mojom::TbmBufferHandleDataView data, gfx::TbmBufferHandle* handle); }; + +template <> +struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS) + EnumTraits { + static gfx::mojom::TbmDestroyType ToMojom(gfx::TbmDestroyType type) { + switch (type) { + case gfx::TbmDestroyType::kDestroyTbmByVideoFrame: + return gfx::mojom::TbmDestroyType::kDestroyTbmByVideoFrame; + case gfx::TbmDestroyType::kDestroyTbmByEgl: + return gfx::mojom::TbmDestroyType::kDestroyTbmByEgl; + } + NOTREACHED(); + return gfx::mojom::TbmDestroyType::kDestroyTbmByVideoFrame; + } + + static bool FromMojom(gfx::mojom::TbmDestroyType input, + gfx::TbmDestroyType* out) { + switch (input) { + case gfx::mojom::TbmDestroyType::kDestroyTbmByVideoFrame: + *out = gfx::TbmDestroyType::kDestroyTbmByVideoFrame; + return true; + case gfx::mojom::TbmDestroyType::kDestroyTbmByEgl: + *out = gfx::TbmDestroyType::kDestroyTbmByEgl; + return true; + } + NOTREACHED(); + return false; + } +}; #endif template <> -- 2.7.4 From 5f24c2b5019bc78ec0f7954e0084d9bc3c7be741 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Fri, 10 Nov 2023 09:28:31 +0900 Subject: [PATCH 12/16] [WRTjs][VD] Introduce in-process VideoSplashScreen From Tizen 5.5 VideoSplashScreen has been introduced, which is running on amd process as amd-extension. Recently, amd process had some performance issues due to video playing, so we had decided to move VSS feature to WRT side. This patch MUST be released with AppFW team's changes, wich disable VSS feature on their side. Change-Id: I0d564941628c883d644d1a89e0a46a0d06eb45e2 Signed-off-by: DongHyun Song --- packaging/chromium-efl.spec | 1 - tizen_src/build/BUILD.gn | 3 - wrt/BUILD.gn | 1 - wrt/filenames.gni | 5 + wrt/src/browser/basic_splash_screen.cc | 11 +- wrt/src/browser/basic_splash_screen.h | 7 +- wrt/src/browser/basic_splash_screen_off_screen.cc | 4 - wrt/src/browser/basic_splash_screen_off_screen.h | 2 +- wrt/src/browser/basic_splash_screen_on_screen.cc | 6 +- wrt/src/browser/basic_splash_screen_on_screen.h | 2 +- wrt/src/browser/splash_screen.cc | 25 +- wrt/src/browser/splash_screen.h | 18 +- .../browser/tv/native_web_runtime_delegate_tv.cc | 17 +- .../browser/tv/native_web_runtime_delegate_tv.h | 1 + wrt/src/browser/tv/splash_screen_delegate_tv.cc | 17 +- wrt/src/browser/tv/splash_screen_delegate_tv.h | 5 +- wrt/src/browser/tv/video_splash_amd_player.cc | 143 ++++++++ wrt/src/browser/tv/video_splash_amd_player.h | 32 ++ wrt/src/browser/tv/video_splash_player.cc | 375 +++++++++++++++++++++ wrt/src/browser/tv/video_splash_player.h | 75 +++++ wrt/src/browser/tv/video_splash_screen.cc | 181 ++++------ wrt/src/browser/tv/video_splash_screen.h | 16 +- wrt/src/browser/tv/wrt_native_window_tv.cc | 4 +- wrt/src/browser/wrt_native_window.cc | 1 + wrt/src/common/application_data_wrapper.h | 15 +- wrt/src/common/splash_screen_delegate.cc | 19 ++ wrt/src/common/splash_screen_delegate.h | 3 +- wrt/src/common/tv/wrt_lib_wrapper.cc | 42 +++ wrt/src/common/tv/wrt_lib_wrapper.h | 22 ++ 29 files changed, 865 insertions(+), 188 deletions(-) create mode 100644 wrt/src/browser/tv/video_splash_amd_player.cc create mode 100644 wrt/src/browser/tv/video_splash_amd_player.h create mode 100644 wrt/src/browser/tv/video_splash_player.cc create mode 100644 wrt/src/browser/tv/video_splash_player.h create mode 100644 wrt/src/common/splash_screen_delegate.cc diff --git a/packaging/chromium-efl.spec b/packaging/chromium-efl.spec index f6624ae..f2dc9b0 100644 --- a/packaging/chromium-efl.spec +++ b/packaging/chromium-efl.spec @@ -198,7 +198,6 @@ BuildRequires: pkgconfig(xtst) %endif %if "%{?tizen_profile_name}" == "tv" -BuildRequires: pkgconfig(aul-extension) BuildRequires: pkgconfig(capi-media-sound-manager) BuildRequires: pkgconfig(capi-stt-wrapper-tv) BuildRequires: pkgconfig(capi-system-display-rotator) diff --git a/tizen_src/build/BUILD.gn b/tizen_src/build/BUILD.gn index 4721b99..ff72301 100644 --- a/tizen_src/build/BUILD.gn +++ b/tizen_src/build/BUILD.gn @@ -931,9 +931,6 @@ if (enable_wrt_js) { } if (tizen_product_tv) { - tizen_pkg_config("aul-extension") { - packages = [ "aul-extension" ] - } tizen_pkg_config("autoinput") { packages = [ "autoinput" ] } diff --git a/wrt/BUILD.gn b/wrt/BUILD.gn index b6ba21d..8fb2b68 100644 --- a/wrt/BUILD.gn +++ b/wrt/BUILD.gn @@ -275,7 +275,6 @@ config("wrt_config") { } if (tizen_product_tv) { configs += [ - "//tizen_src/build:aul-extension", "//tizen_src/build:autoinput", "//tizen_src/build:libcapi-media-camera", "//tizen_src/build:capi-screensaver", diff --git a/wrt/filenames.gni b/wrt/filenames.gni index 4fbf198..d04f234 100644 --- a/wrt/filenames.gni +++ b/wrt/filenames.gni @@ -133,6 +133,7 @@ wrt_lib_sources = [ "src/common/privilege.h", "src/common/resource_manager.cc", "src/common/resource_manager.h", + "src/common/splash_screen_delegate.cc", "src/common/splash_screen_delegate.h", "src/common/wrt_application_info.cc", "src/common/wrt_content_client.cc", @@ -204,6 +205,10 @@ wrt_lib_sources_tv = [ "src/browser/tv/splash_screen_delegate_tv.h", "src/browser/tv/tv_window_manager.cc", "src/browser/tv/tv_window_manager.h", + "src/browser/tv/video_splash_amd_player.cc", + "src/browser/tv/video_splash_amd_player.h", + "src/browser/tv/video_splash_player.cc", + "src/browser/tv/video_splash_player.h", "src/browser/tv/video_splash_screen.cc", "src/browser/tv/video_splash_screen.h", "src/browser/tv/widget_state.cc", diff --git a/wrt/src/browser/basic_splash_screen.cc b/wrt/src/browser/basic_splash_screen.cc index 26f5fcb..82f7900 100644 --- a/wrt/src/browser/basic_splash_screen.cc +++ b/wrt/src/browser/basic_splash_screen.cc @@ -23,18 +23,13 @@ namespace wrt { // static -SplashScreen* BasicSplashScreen::Create( - std::unique_ptr delegate) { +SplashScreen* BasicSplashScreen::Create() { if (WRTNativeWindow::UseOnscreenRendering()) - return new BasicSplashScreenOnScreen(std::move(delegate)); + return new BasicSplashScreenOnScreen(); else - return new BasicSplashScreenOffScreen(std::move(delegate)); + return new BasicSplashScreenOffScreen(); } -BasicSplashScreen::BasicSplashScreen( - std::unique_ptr delegate) - : delegate_(std::move(delegate)) {} - wgt::parse::ReadyWhen BasicSplashScreen::GetReadyWhen() { auto& app_data = ApplicationData::GetInstance(); return app_data.launch_screen_info().ready_when(); diff --git a/wrt/src/browser/basic_splash_screen.h b/wrt/src/browser/basic_splash_screen.h index 0b2e733..b1e36a1 100644 --- a/wrt/src/browser/basic_splash_screen.h +++ b/wrt/src/browser/basic_splash_screen.h @@ -25,14 +25,13 @@ namespace wrt { class BasicSplashScreen : public SplashScreen { public: - static SplashScreen* Create(std::unique_ptr delegate); + static SplashScreen* Create(); ~BasicSplashScreen() override = default; protected: - BasicSplashScreen(std::unique_ptr delegate); + BasicSplashScreen() = default; - void BeforeHide() override {} wgt::parse::ReadyWhen GetReadyWhen() override; using SplashScreenData = const wgt::parse::LaunchScreenData; @@ -42,8 +41,6 @@ class BasicSplashScreen : public SplashScreen { gfx::Insets ParseImageBorder(const std::vector& borders, std::vector* border_options); std::string GetImagePath(SplashScreenData* splash_screen_data); - - std::unique_ptr delegate_; }; } // namespace wrt diff --git a/wrt/src/browser/basic_splash_screen_off_screen.cc b/wrt/src/browser/basic_splash_screen_off_screen.cc index be0fa4b..7d5d903 100644 --- a/wrt/src/browser/basic_splash_screen_off_screen.cc +++ b/wrt/src/browser/basic_splash_screen_off_screen.cc @@ -32,10 +32,6 @@ gfx::Size GetWindowSize(Evas_Object* window) { } // namespace -BasicSplashScreenOffScreen::BasicSplashScreenOffScreen( - std::unique_ptr delegate) - : BasicSplashScreen(std::move(delegate)) {} - void BasicSplashScreenOffScreen::Init() { auto* window = WRTNativeWindow::GetTopWindow(); auto size = GetWindowSize(window); diff --git a/wrt/src/browser/basic_splash_screen_off_screen.h b/wrt/src/browser/basic_splash_screen_off_screen.h index a8118ab..6d465f2 100644 --- a/wrt/src/browser/basic_splash_screen_off_screen.h +++ b/wrt/src/browser/basic_splash_screen_off_screen.h @@ -26,7 +26,7 @@ namespace wrt { class BasicSplashScreenOffScreen : public BasicSplashScreen { public: - BasicSplashScreenOffScreen(std::unique_ptr delegate); + BasicSplashScreenOffScreen() = default; ~BasicSplashScreenOffScreen() override = default; protected: diff --git a/wrt/src/browser/basic_splash_screen_on_screen.cc b/wrt/src/browser/basic_splash_screen_on_screen.cc index 8aac890..4c35fc7 100644 --- a/wrt/src/browser/basic_splash_screen_on_screen.cc +++ b/wrt/src/browser/basic_splash_screen_on_screen.cc @@ -20,10 +20,8 @@ namespace wrt { -BasicSplashScreenOnScreen::BasicSplashScreenOnScreen( - std::unique_ptr delegate) - : BasicSplashScreen(std::move(delegate)), - widget_delegate_(new SplashScreenWidgetDelegate) {} +BasicSplashScreenOnScreen::BasicSplashScreenOnScreen() + : widget_delegate_(new SplashScreenWidgetDelegate) {} void BasicSplashScreenOnScreen::Init() { auto* host = widget_delegate_->host(); diff --git a/wrt/src/browser/basic_splash_screen_on_screen.h b/wrt/src/browser/basic_splash_screen_on_screen.h index 969758d..9d8c783 100644 --- a/wrt/src/browser/basic_splash_screen_on_screen.h +++ b/wrt/src/browser/basic_splash_screen_on_screen.h @@ -25,7 +25,7 @@ class SplashScreenWidgetDelegate; class BasicSplashScreenOnScreen : public BasicSplashScreen { public: - BasicSplashScreenOnScreen(std::unique_ptr delegate); + BasicSplashScreenOnScreen(); ~BasicSplashScreenOnScreen() override = default; protected: diff --git a/wrt/src/browser/splash_screen.cc b/wrt/src/browser/splash_screen.cc index 15c5cef..e382439 100644 --- a/wrt/src/browser/splash_screen.cc +++ b/wrt/src/browser/splash_screen.cc @@ -19,7 +19,6 @@ #include "base/logging.h" #include "base/task/single_thread_task_runner.h" #include "wrt/src/browser/basic_splash_screen.h" -#include "wrt/src/browser/wrt_native_window.h" #if BUILDFLAG(IS_TIZEN_TV) #include "wrt/src/browser/tv/splash_screen_delegate_tv.h" @@ -46,17 +45,15 @@ bool SplashScreen::ShowSplashScreen() { delegate = std::make_unique(); #elif BUILDFLAG(IS_TIZEN_DA) delegate = std::make_unique(); +#else + delegate = std::make_unique(); #endif - auto& app_data = ApplicationData::GetInstance(); - if (delegate && delegate->IsVideoPlaying()) - splash_screen.reset(delegate->CreateVideoSplashScreen()); - else if (app_data.launch_screen_info().HasLaunchScreenData()) - splash_screen.reset(BasicSplashScreen::Create(std::move(delegate))); - + splash_screen.reset(delegate->CreateSplashScreen()); if (!splash_screen) return false; + splash_screen->SetDelegate(std::move(delegate)); splash_screen->Init(); return true; } @@ -84,7 +81,6 @@ bool SplashScreen::HideSplashScreen(HideReason reason) { } hidden_reason = reason; - splash_screen->BeforeHide(); LOG(INFO) << "Will HideSplashScreen reason by " << reason; return true; } @@ -99,10 +95,17 @@ bool SplashScreen::IsShowing() { return !!splash_screen && hidden_reason == HideReason::UNDECIDED; } +// static +void SplashScreen::AddObserver(WRTNativeWindow* native_window) { + // Because SplashScreen can be created before NativeWindow created, + // - i.e., VideoSplashScreen + // AddObserver should be called on NativeWindow created time. + if (splash_screen) + native_window->AddObserver(splash_screen.get()); +} + SplashScreen::SplashScreen() { - auto main_native_window = WRTNativeWindow::GetMainNativeWindow(); - if (main_native_window) - main_native_window->AddObserver(this); + LOG(INFO) << "SplashScreen is created"; } SplashScreen::~SplashScreen() { diff --git a/wrt/src/browser/splash_screen.h b/wrt/src/browser/splash_screen.h index ff453e7..c58da29 100644 --- a/wrt/src/browser/splash_screen.h +++ b/wrt/src/browser/splash_screen.h @@ -18,20 +18,17 @@ #define BROWSER_SPLASH_SCREEN_H_ #include "electron/shell/browser/native_window_observer.h" +#include "wrt/src/browser/wrt_native_window.h" #include "wrt/src/common/application_data.h" +#include "wrt/src/common/splash_screen_delegate.h" namespace wrt { -enum HideReason { - RENDERED, - LOADFINISHED, - CUSTOM, - VIDEOFINISHED, - UNDECIDED, -}; +enum HideReason { RENDERED, LOADFINISHED, CUSTOM, VIDEOFINISHED, UNDECIDED }; class SplashScreen : public electron::NativeWindowObserver { public: + static void AddObserver(WRTNativeWindow* native_window); static bool ShowSplashScreen(); static bool HideSplashScreen(HideReason reason); static bool IsShowing(); @@ -43,12 +40,17 @@ class SplashScreen : public electron::NativeWindowObserver { SplashScreen(); virtual void Init() = 0; - virtual void BeforeHide() = 0; virtual void Hide() = 0; virtual wgt::parse::ReadyWhen GetReadyWhen() = 0; + void SetDelegate(std::unique_ptr delegate) { + delegate_ = std::move(delegate); + } + // electron::NativeWindowObserver void OnWindowShow() override; + + std::unique_ptr delegate_; }; } // namespace wrt diff --git a/wrt/src/browser/tv/native_web_runtime_delegate_tv.cc b/wrt/src/browser/tv/native_web_runtime_delegate_tv.cc index 675bb13..9ca79eb3 100644 --- a/wrt/src/browser/tv/native_web_runtime_delegate_tv.cc +++ b/wrt/src/browser/tv/native_web_runtime_delegate_tv.cc @@ -278,14 +278,20 @@ void NativeWebRuntimeDelegateTV::Initialize(void* data) { auto extension_manager = XWalkExtensionManager::GetInstance(); extension_manager->RegisterUpgradableExtensions(); + EarlyPlayVideoSplashScreen(); SetAllowedPath(); SetFileRequestIntercepter(base::BindRepeating( &NativeWebRuntimeDelegateTV::IsAllowedPath, base::Unretained(this))); SetEncryptedFileUrlCallbacks(); - initialized_ = true; } +void NativeWebRuntimeDelegateTV::EarlyPlayVideoSplashScreen() { + auto& app_data = ApplicationDataTV::GetInstance(); + if (app_data.video_splash_screen_info().HasVideoSplashScreenData()) + SplashScreen::ShowSplashScreen(); +} + void NativeWebRuntimeDelegateTV::EarlyLoadUrlIfHostedApp() { auto& app_data = ApplicationData::GetInstance(); if (!app_data.IsHostedApp() || has_payload_data_) @@ -299,7 +305,6 @@ void NativeWebRuntimeDelegateTV::EarlyLoadUrlIfHostedApp() { } void NativeWebRuntimeDelegateTV::DidInitialized() { - VideoSplashScreen::InitializeVSS(); EarlyLoadUrlIfHostedApp(); SetD2dServiceMessageListener(); SubscribePowerState(); @@ -643,7 +648,13 @@ void NativeWebRuntimeDelegateTV::PepperUpdatePluginService() { // static void NativeWebRuntimeDelegateTV::PreSetupOnWorker() { LOG(INFO) << "PreSetupOnWorker"; - if (!ApplicationData::GetInstance().IsHostedApp()) + auto& app_data = ApplicationDataTV::GetInstance(); + auto is_local_app = !app_data.IsHostedApp(); + auto has_splash_screen = + app_data.launch_screen_info().HasLaunchScreenData() || + app_data.video_splash_screen_info().HasVideoSplashScreenData(); + + if (is_local_app || has_splash_screen) GetInstance().TryMount(); GetInstance().PepperUpdatePluginService(); } diff --git a/wrt/src/browser/tv/native_web_runtime_delegate_tv.h b/wrt/src/browser/tv/native_web_runtime_delegate_tv.h index a6a658d..d35e30a 100644 --- a/wrt/src/browser/tv/native_web_runtime_delegate_tv.h +++ b/wrt/src/browser/tv/native_web_runtime_delegate_tv.h @@ -78,6 +78,7 @@ class NativeWebRuntimeDelegateTV : public WRTProfileDelegate { void ApplyHalfWindow(std::string half_window_option); void ClearTmpFolder(); void EarlyLoadUrlIfHostedApp(); + void EarlyPlayVideoSplashScreen(); bool IsAllowedPath(const base::FilePath& path); void SetAllowedPath(); void SetD2dServiceMessageListener(); diff --git a/wrt/src/browser/tv/splash_screen_delegate_tv.cc b/wrt/src/browser/tv/splash_screen_delegate_tv.cc index b2b459a..4c3bae9 100755 --- a/wrt/src/browser/tv/splash_screen_delegate_tv.cc +++ b/wrt/src/browser/tv/splash_screen_delegate_tv.cc @@ -7,6 +7,7 @@ #include #include "tizen_src/chromium_impl/tizen/vconf_handle.h" +#include "wrt/src/browser/tv/native_web_runtime_delegate_tv.h" #include "wrt/src/browser/tv/video_splash_screen.h" #include "wrt/src/common/tv/application_data_tv.h" @@ -19,6 +20,10 @@ const char* kVconfRotationState = "db/sysman/rotation_state"; } // namespace +SplashScreenDelegateTV::SplashScreenDelegateTV() { + NativeWebRuntimeDelegateTV::GetInstance().TryMount(); +} + wgt::parse::ScreenOrientation SplashScreenDelegateTV::GetScreenOrientation() { int rotation_state = VconfHandle(kVconfRotationState).Int(); if (rotation_state == DISPLAY_ROTATOR_ORIENTATION_PORTRAIT || @@ -38,14 +43,12 @@ std::string SplashScreenDelegateTV::ConvertAliasPath(std::string& image_path) { } } -bool SplashScreenDelegateTV::IsVideoPlaying() { +SplashScreen* SplashScreenDelegateTV::CreateSplashScreen() { auto& app_data = ApplicationDataTV::GetInstance(); - return app_data.video_splash_screen_info().HasVideoSplashScreenData() && - VideoSplashScreen::IsVSSPlaying(); -} - -SplashScreen* SplashScreenDelegateTV::CreateVideoSplashScreen() { - return new VideoSplashScreen; + if (app_data.video_splash_screen_info().HasVideoSplashScreenData()) + return VideoSplashScreen::Create(); + else + return SplashScreenDelegate::CreateSplashScreen(); } } // namespace wrt diff --git a/wrt/src/browser/tv/splash_screen_delegate_tv.h b/wrt/src/browser/tv/splash_screen_delegate_tv.h index 2f2e5d5..b3770ea 100644 --- a/wrt/src/browser/tv/splash_screen_delegate_tv.h +++ b/wrt/src/browser/tv/splash_screen_delegate_tv.h @@ -11,14 +11,13 @@ namespace wrt { class SplashScreenDelegateTV : public SplashScreenDelegate { public: - SplashScreenDelegateTV() {} + SplashScreenDelegateTV(); ~SplashScreenDelegateTV() override {} private: - bool IsVideoPlaying() override; std::string ConvertAliasPath(std::string& image_path) override; - SplashScreen* CreateVideoSplashScreen() override; wgt::parse::ScreenOrientation GetScreenOrientation() override; + SplashScreen* CreateSplashScreen() override; }; } // namespace wrt diff --git a/wrt/src/browser/tv/video_splash_amd_player.cc b/wrt/src/browser/tv/video_splash_amd_player.cc new file mode 100644 index 0000000..5303072 --- /dev/null +++ b/wrt/src/browser/tv/video_splash_amd_player.cc @@ -0,0 +1,143 @@ +// Copyright 2024 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "wrt/src/browser/tv/video_splash_amd_player.h" + +#include "wrt/src/browser/native_web_runtime.h" +#include "wrt/src/browser/splash_screen.h" +#include "wrt/src/browser/tv/widget_state.h" +#include "wrt/src/common/tv/application_data_tv.h" +#include "wrt/src/common/tv/wrt_lib_wrapper.h" + +namespace wrt { + +namespace { + +const char* kSplashScreenAulAppCom = "crosswalk.splashscreen.player."; +aul_app_com_connection_h aul_app_com_connection_ = nullptr; + +const char* HideReasonToString(HideReason reason) { + switch (reason) { + case HideReason::UNDECIDED: + return "UNDECIDED"; + case HideReason::CUSTOM: + return "CUSTOM"; + case HideReason::RENDERED: + return "FIRST_PAINT"; + case HideReason::LOADFINISHED: + return "COMPLETE"; + case HideReason::VIDEOFINISHED: + return "VIDEO_FINISHED"; + } + return "UNKNOWN"; +} + +void HideVSSPlayer(std::string hide_reason) { + if (hide_reason != "VIDEOFINISHED") { + int error_code = aul_extension_splash_screen_tv_event(hide_reason.c_str()); + LOG(INFO) << "Hide AUL SplashScreen msg send with " << error_code << " [" + << hide_reason << "]"; + } else { + LOG(INFO) << "Hide AUL SplashScreen msg send with --- [" << hide_reason + << "]"; + } +} + +bool ReleaseVSSCom() { + auto& app_data = ApplicationDataTV::GetInstance(); + return (app_data.video_splash_screen_info().HasVideoSplashScreenData() && + !!aul_app_com_connection_ && + !aul_extension_splash_screen_tv_event("ISVIDEO")); +} + +int OnSplashScreenMessage(const char* endpoint, + aul_app_com_result_e e, + bundle* envelope, + void* user_data) { + char* tmp = nullptr; + bundle_get_str(envelope, "EVENT", &tmp); + if (!tmp) + return -1; + std::string msg(tmp); + LOG(INFO) << "Get msg from splash screen: " << msg; + if ("VIDEOFINISHED" == msg || "PLAYERERROR" == msg) { + HideVSSPlayer("VIDEOFINISHED"); + std::vector params = {"video-finished"}; + NativeWebRuntime::GetInstance().NotifyMessage("hideSplashScreen", params); + } else if ("TERMINATE" == msg) { + NativeWebRuntime::GetInstance().RequestQuit(); + } else if ("INTERRUPT" == msg) { + VideoSplashAmdPlayer::Finalize(); + NativeWebRuntime::GetInstance().NotifySuspend(); + WidgetStateProvider::OnStatusChanged("pause"); + } else { + return -1; + } + return 0; +} + +} // namespace + +VideoSplashAmdPlayer::VideoSplashAmdPlayer() { + if (aul_app_com_connection_) + return; + + if (!aul_extension_splash_screen_tv_event("ISVIDEO")) { + LOG(ERROR) << "Failed to send ISVIDEO to VSS"; + return; + } + + auto& app_data = ApplicationDataTV::GetInstance(); + std::string com_endpoint = kSplashScreenAulAppCom + app_data.app_id(); + if (aul_app_com_create(com_endpoint.c_str(), nullptr, OnSplashScreenMessage, + nullptr, &aul_app_com_connection_)) { + LOG(ERROR) << "Failed to initialize AUL APP COM"; + } else { + LOG(ERROR) << "Initialized AUL APP COM with " << com_endpoint; + } +} + +VideoSplashAmdPlayer::~VideoSplashAmdPlayer() {} + +// static +void VideoSplashAmdPlayer::Finalize() { + if (!ReleaseVSSCom()) + return; + + LOG(INFO) << "Finalize AUL APP COM and VSS"; + aul_app_com_leave(aul_app_com_connection_); + aul_app_com_connection_ = nullptr; + aul_extension_splash_screen_tv_reset(); +} + +void VideoSplashAmdPlayer::Hide() { + if (was_hidden_) + return; + + if (IsPlayerPlaying()) { + auto hidden_reason = SplashScreen::GetHiddenReason(); + const char* hide_reason = HideReasonToString(hidden_reason); + HideVSSPlayer(hide_reason); + was_hidden_ = true; + } + Finalize(); +} + +bool VideoSplashAmdPlayer::Initialize() { + return true; +} + +bool VideoSplashAmdPlayer::PreparePlayer() { + return true; +} + +bool VideoSplashAmdPlayer::PlayerStart(const std::string& video_src) { + return true; +} + +bool VideoSplashAmdPlayer::IsPlayerPlaying() { + return !!aul_app_com_connection_; +} + +} // namespace wrt diff --git a/wrt/src/browser/tv/video_splash_amd_player.h b/wrt/src/browser/tv/video_splash_amd_player.h new file mode 100644 index 0000000..1dc642e --- /dev/null +++ b/wrt/src/browser/tv/video_splash_amd_player.h @@ -0,0 +1,32 @@ +// Copyright 2024 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BROWSER_VIDEO_SPLASH_AMD_PLAYER_H_ +#define BROWSER_VIDEO_SPLASH_AMD_PLAYER_H_ + +#include "wrt/src/browser/tv/video_splash_player.h" +#include "wrt/src/common/application_data.h" + +namespace wrt { + +class VideoSplashAmdPlayer : public VideoSplashPlayer { + public: + static void Finalize(); + + VideoSplashAmdPlayer(); + ~VideoSplashAmdPlayer() override; + + private: + void Hide() override; + bool Initialize() override; + bool PreparePlayer() override; + bool PlayerStart(const std::string& video_src) override; + bool IsPlayerPlaying() override; + + bool was_hidden_ = false; +}; + +} // namespace wrt + +#endif // BROWSER_VIDEO_SPLASH_AMD_PLAYER_H_ \ No newline at end of file diff --git a/wrt/src/browser/tv/video_splash_player.cc b/wrt/src/browser/tv/video_splash_player.cc new file mode 100644 index 0000000..dc96a75 --- /dev/null +++ b/wrt/src/browser/tv/video_splash_player.cc @@ -0,0 +1,375 @@ +// Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "wrt/src/browser/tv/video_splash_player.h" + +#include + +#include + +#include "base/logging.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "ui/ozone/platform/efl/efl_window.h" +#include "wrt/src/browser/native_web_runtime.h" +#include "wrt/src/browser/tv/widget_state.h" +#include "wrt/src/browser/tv/wrt_native_window_tv.h" +#include "wrt/src/common/application_data.h" + +namespace wrt { + +namespace { + +#define ADD_CASE(type) \ + case type: \ + return #type + +#define CAPI_CHECK(test, msg) \ + do { \ + auto const result = static_cast(test); \ + if (result != PLAYER_ERROR_NONE) { \ + LOG(ERROR) << "CAPI " << msg << " failed with " \ + << GetPlayerErrorString(result); \ + return result; \ + } \ + } while (0) + +const char* kKeyBack = "XF86Back"; +const char* kKeyExit = "XF86Exit"; +const char* kElmWindowName = "VSSPlayer"; + +inline bool IsKeySameAs(const char* key, const char* event_key) { + return strcmp(key, event_key) == 0; +} + +const char* GetPlayerErrorString(player_error_e type) { + switch (type) { + ADD_CASE(PLAYER_ERROR_NONE); + ADD_CASE(PLAYER_ERROR_OUT_OF_MEMORY); + ADD_CASE(PLAYER_ERROR_INVALID_PARAMETER); + ADD_CASE(PLAYER_ERROR_NO_SUCH_FILE); + ADD_CASE(PLAYER_ERROR_INVALID_OPERATION); + ADD_CASE(PLAYER_ERROR_FILE_NO_SPACE_ON_DEVICE); + ADD_CASE(PLAYER_ERROR_FEATURE_NOT_SUPPORTED_ON_DEVICE); + ADD_CASE(PLAYER_ERROR_SEEK_FAILED); + ADD_CASE(PLAYER_ERROR_INVALID_STATE); + ADD_CASE(PLAYER_ERROR_NOT_SUPPORTED_FILE); + ADD_CASE(PLAYER_ERROR_INVALID_URI); + ADD_CASE(PLAYER_ERROR_SOUND_POLICY); + ADD_CASE(PLAYER_ERROR_CONNECTION_FAILED); + ADD_CASE(PLAYER_ERROR_VIDEO_CAPTURE_FAILED); + ADD_CASE(PLAYER_ERROR_DRM_EXPIRED); + ADD_CASE(PLAYER_ERROR_DRM_NO_LICENSE); + ADD_CASE(PLAYER_ERROR_DRM_FUTURE_USE); + ADD_CASE(PLAYER_ERROR_DRM_NOT_PERMITTED); + ADD_CASE(PLAYER_ERROR_RESOURCE_LIMIT); + ADD_CASE(PLAYER_ERROR_PERMISSION_DENIED); + ADD_CASE(PLAYER_ERROR_SERVICE_DISCONNECTED); + ADD_CASE(PLAYER_ERROR_BUFFER_SPACE); + ADD_CASE(PLAYER_ERROR_NOT_SUPPORTED_AUDIO_CODEC); + ADD_CASE(PLAYER_ERROR_NOT_SUPPORTED_VIDEO_CODEC); + ADD_CASE(PLAYER_ERROR_NOT_SUPPORTED_SUBTITLE); + ADD_CASE(PLAYER_ERROR_AUDIO_CODEC_NOT_SUPPORTED); + ADD_CASE(PLAYER_ERROR_VIDEO_CODEC_NOT_SUPPORTED); + ADD_CASE(PLAYER_ERROR_NO_AUTH); + ADD_CASE(PLAYER_ERROR_GENEREIC); + ADD_CASE(PLAYER_ERROR_DRM_INFO); + ADD_CASE(PLAYER_ERROR_SYNC_PLAY_NETWORK_EXCEPTION); + ADD_CASE(PLAYER_ERROR_SYNC_PLAY_SERVER_DOWN); + ADD_CASE(PLAYER_ERROR_NOT_SUPPORTED_FORMAT); + ADD_CASE(PLAYER_ERROR_STREAMING_PLAYER); + ADD_CASE(PLAYER_ERROR_DTCP_FSK); + ADD_CASE(PLAYER_ERROR_PRE_LOADING_TIME_OUT); + ADD_CASE(PLAYER_ERROR_NETWORK_ERROR); + ADD_CASE(PLAYER_ERROR_CHANNEL_SURFING_FAILED); + default: + return "UNKNOWN ERROR"; + } +} + +std::string ConvertMessage(VideoSplashPlayer::SplashScreenMsgType msg) { + switch (msg) { + case VideoSplashPlayer::SplashScreenMsgType::VIDEOFINISHED: + return "VIDEOFINISHED"; + case VideoSplashPlayer::SplashScreenMsgType::TERMINATE: + return "TERMINATE"; + case VideoSplashPlayer::SplashScreenMsgType::PLAYERERROR: + return "PLAYERERROR"; + case VideoSplashPlayer::SplashScreenMsgType::NOVIDEO: + return "NOVIDEO"; + default: + return "NONE"; + } +} + +} // namespace + +void VideoSplashPlayer::CapiPlayer::Show() { + LOG(INFO) << "will show VSSPlayer window"; + if (vss_window_) { + evas_object_show(vss_window_); + elm_win_raise(vss_window_); + } +} + +void VideoSplashPlayer::CapiPlayer::Hide() { + DestroyPlayer(); + + if (vss_window_) { + LOG(INFO) << "will hide VSSPlayer window"; + + evas_object_smart_callback_del(vss_window_, "visibility,changed", + VisibilityChangeEvent); + elm_win_lower(vss_window_); + evas_object_hide(vss_window_); + evas_object_del(vss_window_); + vss_window_ = nullptr; + } +} + +bool VideoSplashPlayer::CapiPlayer::CreateElmWindow() { + vss_window_ = elm_win_add(nullptr, "player", ELM_WIN_BASIC); + if (!vss_window_) { + LOG(ERROR) << "elm_win_add failed"; + return false; + } + + elm_win_title_set(vss_window_, kElmWindowName); + elm_win_borderless_set(vss_window_, EINA_TRUE); + elm_win_indicator_mode_set(vss_window_, ELM_WIN_INDICATOR_HIDE); + + int window_width, window_height; + elm_win_screen_size_get(vss_window_, nullptr, nullptr, &window_width, + &window_height); + evas_object_resize(vss_window_, window_width, window_height); + LOG(INFO) << "Screen size : " << window_width << "x" << window_height; + + return true; +} + +VideoSplashPlayer::CapiPlayer::CapiPlayer() { + LOG(INFO) << "New CapiPlayer is created"; +} + +VideoSplashPlayer::CapiPlayer::~CapiPlayer() { + LOG(INFO) << "CapiPlayer is destroying"; + DestroyPlayer(); + Hide(); +} + +player_state_e VideoSplashPlayer::CapiPlayer::GetPlayerState() { + player_state_e state = PLAYER_STATE_NONE; + if (!player_ || PLAYER_ERROR_NONE != player_get_state(player_, &state)) + LOG(ERROR) << "player_get_state failed"; + return state; +} + +bool VideoSplashPlayer::CapiPlayer::Initialize() { + if (key_handler_) { + ecore_event_handler_del(key_handler_); + key_handler_ = nullptr; + } + + if (!CreateElmWindow()) + return false; + + evas_object_smart_callback_add(vss_window_, "visibility,changed", + VisibilityChangeEvent, this); + + return true; +} + +int VideoSplashPlayer::CapiPlayer::PreparePlayerGreedy() { + CAPI_CHECK(player_create(&(player_)), "player_create"); + CAPI_CHECK(player_set_error_cb(player_, &OnCapiPlayerError, this), + "player_set_error_cb"); + CAPI_CHECK(player_set_completed_cb(player_, &OnCapiPlayerCompleted, this), + "player_set_completed_cb"); + CAPI_CHECK( + player_set_display(player_, PLAYER_DISPLAY_TYPE_OVERLAY, vss_window_), + "player_set_display"); + + LOG(INFO) << "PreparePlayerGreedy for player finished : " << player_; + return PLAYER_ERROR_NONE; +} + +int VideoSplashPlayer::CapiPlayer::ReportError(int error, const char* func) { + SendMessage(SplashScreenMsgType::PLAYERERROR); + auto error_string = GetPlayerErrorString((player_error_e)error); + LOG(ERROR) << func << " failed : " << error_string; + return error; +} + +int VideoSplashPlayer::CapiPlayer::PreparePlayerLazy(const char* url) { + int error = PLAYER_ERROR_NONE; + + error = player_set_video_still(player_, PLAYER_STILL_MODE_ON); + if (error != PLAYER_ERROR_NONE) { + return ReportError(error, "player_set_video_still"); + } + if ((error = player_set_uri(player_, url)) != PLAYER_ERROR_NONE) { + return ReportError(error, "player_set_uri"); + } + if ((error = player_prepare(player_)) != PLAYER_ERROR_NONE) { + return ReportError(error, "player_prepare"); + } + + Show(); + if ((error = player_start(player_)) != PLAYER_ERROR_NONE) { + return ReportError(error, "player_start"); + } + key_handler_ = + ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, OnKeyPressCb, this); + + LOG(INFO) << "PreparePlayerLazy for player finished : " << player_; + return error; +} + +bool VideoSplashPlayer::CapiPlayer::RelaunchPlayer() { + if (DestroyPlayer() != PLAYER_ERROR_NONE) + return false; + PreparePlayerGreedy(); + return true; +} + +bool VideoSplashPlayer::CapiPlayer::IsPlayerPlaying() { + return (player_ && GetPlayerState() == PLAYER_STATE_PLAYING); +} + +void VideoSplashPlayer::CapiPlayer::SendMessage(SplashScreenMsgType msg) { + auto callback = [](SplashScreenMsgType msg) { + LOG(INFO) << "Handle SendMessage - " << ConvertMessage(msg); + if (msg == SplashScreenMsgType::PLAYERERROR || + msg == SplashScreenMsgType::NOVIDEO || + msg == SplashScreenMsgType::VIDEOFINISHED) { + std::vector params = {"video-finished"}; + NativeWebRuntime::GetInstance().NotifyMessage("hideSplashScreen", params); + } else if (msg == SplashScreenMsgType::TERMINATE) { + NativeWebRuntime::GetInstance().RequestQuit(); + } + }; + content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, + base::BindOnce(callback, msg)); +} + +void VideoSplashPlayer::CapiPlayer::VisibilityChangeEvent(void* data, + Evas_Object* obj, + void* event) { + CapiPlayer* cp = static_cast(data); + if (!cp) + return; + + uintptr_t visibility = reinterpret_cast(event); + if (!visibility) { + LOG(INFO) << "VSS is hidden by another window, will terminate the app"; + cp->Hide(); + cp->SendMessage(SplashScreenMsgType::TERMINATE); + } +} + +int VideoSplashPlayer::CapiPlayer::DestroyPlayer() { + if (player_) { + player_set_error_cb(player_, nullptr, nullptr); + player_set_completed_cb(player_, nullptr, nullptr); + + if (GetPlayerState() > PLAYER_STATE_READY) { + CAPI_CHECK(player_stop(player_), "player_stop"); + CAPI_CHECK(player_unprepare(player_), "player_unprepare"); + } + + // Log was moved before the actual player_destroy, as using + // "player_" after the player_destroy is going to be flagged + // as use-after-free by the SVACE + LOG(INFO) << "DestroyPlayer for player finish : " << player_; + CAPI_CHECK(player_destroy(player_), "player_destroy"); + player_ = nullptr; + } + return PLAYER_ERROR_NONE; +} + +void VideoSplashPlayer::CapiPlayer::OnCapiPlayerCompleted(void* user_data) { + auto cp = static_cast(user_data); + if (!cp) { + LOG(ERROR) << "No CapiPlayer"; + return; + } + LOG(INFO) << "CAPI PLAYER COMPLETED"; + cp->SendMessage(SplashScreenMsgType::VIDEOFINISHED); +} + +void VideoSplashPlayer::CapiPlayer::OnCapiPlayerError(int error_code, + void* user_data) { + auto cp = static_cast(user_data); + if (!cp) { + LOG(ERROR) << "No CapiPlayer"; + return; + } + cp->SendMessage(SplashScreenMsgType::PLAYERERROR); +} + +Eina_Bool VideoSplashPlayer::CapiPlayer::OnKeyPressCb(void* data, + int type, + void* event) { + Ecore_Event_Key* ev = static_cast(event); + CapiPlayer* cp = static_cast(data); + if (!ev || !cp) + return ECORE_CALLBACK_CANCEL; + + LOG(INFO) << "Received key press : " << ev->key; + + if (IsKeySameAs(kKeyBack, ev->key) || IsKeySameAs(kKeyExit, ev->key)) { + cp->SendMessage(SplashScreenMsgType::TERMINATE); + } + + return ECORE_CALLBACK_PASS_ON; +} + +VideoSplashPlayer::VideoSplashPlayer() { + capi_player_ = std::make_unique(); +} + +VideoSplashPlayer::~VideoSplashPlayer() { + LOG(INFO) << "VideoSplashPlayer is destroying"; +} + +bool VideoSplashPlayer::PreparePlayer() { + if (!capi_player_) { + LOG(ERROR) << "There is no capi_player_ yet"; + return false; + } + return (capi_player_->PreparePlayerGreedy()) == PLAYER_ERROR_NONE; +} + +bool VideoSplashPlayer::PlayerStart(const std::string& video_src) { + if (!capi_player_) { + LOG(ERROR) << "There is no capi_player_ yet"; + return false; + } + + if (capi_player_->IsPlayerPlaying()) + capi_player_->RelaunchPlayer(); + + LOG(INFO) << "video_src : " << video_src; + if (video_src.empty()) { + capi_player_->SendMessage(SplashScreenMsgType::NOVIDEO); + return false; + } + + auto play_prepared = capi_player_->PreparePlayerLazy(video_src.c_str()); + return play_prepared == PLAYER_ERROR_NONE; +} + +bool VideoSplashPlayer::IsPlayerPlaying() { + return capi_player_->IsPlayerPlaying(); +} + +void VideoSplashPlayer::Hide() { + capi_player_->Hide(); +} + +bool VideoSplashPlayer::Initialize() { + return capi_player_->Initialize(); +} + +} // namespace wrt diff --git a/wrt/src/browser/tv/video_splash_player.h b/wrt/src/browser/tv/video_splash_player.h new file mode 100644 index 0000000..8714991 --- /dev/null +++ b/wrt/src/browser/tv/video_splash_player.h @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BROWSER_VIDEO_SPLASH_PLAYER_H_ +#define BROWSER_VIDEO_SPLASH_PLAYER_H_ + +#include + +#include +#include + +#include "wrt/src/browser/tv/video_splash_screen.h" + +namespace wrt { + +class VideoSplashPlayer { + public: + enum class SplashScreenMsgType { + VIDEOFINISHED, + TERMINATE, + PLAYERERROR, + NOVIDEO + }; + + VideoSplashPlayer(); + virtual ~VideoSplashPlayer(); + + virtual void Hide(); + virtual bool Initialize(); + virtual bool PreparePlayer(); + virtual bool PlayerStart(const std::string& video_src); + virtual bool IsPlayerPlaying(); + + class CapiPlayer { + public: + CapiPlayer(); + ~CapiPlayer(); + + void Show(); + void Hide(); + bool Initialize(); + int PreparePlayerGreedy(); + int PreparePlayerLazy(const char* url); + + bool RelaunchPlayer(); + bool IsPlayerPlaying(); + void SendMessage(SplashScreenMsgType msg); + + private: + static void OnCapiPlayerCompleted(void* user_data); + static void OnCapiPlayerError(int error_code, void* user_data); + static Eina_Bool OnKeyPressCb(void* data, int type, void* event); + static void VisibilityChangeEvent(void* data, + Evas_Object* obj, + void* event); + + player_state_e GetPlayerState(); + bool CreateElmWindow(); + int DestroyPlayer(); + int ReportError(int error, const char* func); + + Evas_Object* vss_window_ = nullptr; + Ecore_Event_Handler* key_handler_ = nullptr; + + player_h player_ = nullptr; + }; + + private: + std::unique_ptr capi_player_; +}; + +} // namespace wrt + +#endif // BROWSER_VIDEO_SPLASH_PLAYER_H_ diff --git a/wrt/src/browser/tv/video_splash_screen.cc b/wrt/src/browser/tv/video_splash_screen.cc index 63849eb..8ce4089 100644 --- a/wrt/src/browser/tv/video_splash_screen.cc +++ b/wrt/src/browser/tv/video_splash_screen.cc @@ -4,141 +4,68 @@ #include "wrt/src/browser/tv/video_splash_screen.h" -#include -#include - -#include "wrt/src/browser/native_web_runtime.h" -#include "wrt/src/browser/tv/widget_state.h" +#include "base/base_switches.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "chromium_impl/build/tizen_version.h" +#include "wrt/src/browser/tv/native_web_runtime_delegate_tv.h" #include "wrt/src/browser/tv/wrt_native_window_tv.h" +#include "wrt/src/browser/wrt_native_widget.h" #include "wrt/src/common/tv/application_data_tv.h" +#if TIZEN_VERSION_AT_LEAST(9, 0, 0) +#include "wrt/src/browser/tv/video_splash_player.h" +#else +#include "wrt/src/browser/tv/video_splash_amd_player.h" +#endif + namespace wrt { namespace { -const char* kSplashScreenAulAppCom = "crosswalk.splashscreen.player."; -aul_app_com_connection_h aul_app_com_connection_ = nullptr; - -const char* HideReasonToString(HideReason reason) { - switch (reason) { - case HideReason::UNDECIDED: - return "UNDECIDED"; - case HideReason::CUSTOM: - return "CUSTOM"; - case HideReason::RENDERED: - return "FIRST_PAINT"; - case HideReason::LOADFINISHED: - return "COMPLETE"; - case HideReason::VIDEOFINISHED: - return "VIDEO_FINISHED"; - } - return "UNKNOWN"; -} - -void HideVSSPlayer(std::string hide_reason) { - if (hide_reason != "VIDEOFINISHED") { - int error_code = aul_extension_splash_screen_tv_event(hide_reason.c_str()); - LOG(INFO) << "Hide AUL SplashScreen msg send with " << error_code << " [" - << hide_reason << "]"; - } else { - LOG(INFO) << "Hide AUL SplashScreen msg send with --- [" << hide_reason - << "]"; - } -} - -int OnSplashScreenMessage(const char* endpoint, - aul_app_com_result_e e, - bundle* envelope, - void* user_data) { - char* tmp = nullptr; - bundle_get_str(envelope, "EVENT", &tmp); - if (!tmp) - return -1; - std::string msg(tmp); - LOG(INFO) << "Get msg from splash screen: " << msg; - if ("VIDEOFINISHED" == msg || "PLAYERERROR" == msg) { - HideVSSPlayer("VIDEOFINISHED"); - std::vector params = {"video-finished"}; - NativeWebRuntime::GetInstance().NotifyMessage("hideSplashScreen", params); - } else if ("TERMINATE" == msg) { - NativeWebRuntime::GetInstance().RequestQuit(); - } else if ("INTERRUPT" == msg) { - VideoSplashScreen::FinalizeVSS(); - NativeWebRuntime::GetInstance().NotifySuspend(); - WidgetStateProvider::OnStatusChanged("pause"); - } else { - return -1; - } - return 0; -} - -bool ReleaseVSSCom() { - auto& app_data = ApplicationDataTV::GetInstance(); - - return (app_data.video_splash_screen_info().HasVideoSplashScreenData() && - !!aul_app_com_connection_ && - !aul_extension_splash_screen_tv_event("ISVIDEO")); -} +std::unique_ptr video_player; } // namespace -VideoSplashScreen::~VideoSplashScreen() { - FinalizeVSS(); -} - // static -bool VideoSplashScreen::IsVSSPlaying() { - return !!aul_app_com_connection_; +SplashScreen* VideoSplashScreen::Create() { + return new VideoSplashScreen(); } // static -void VideoSplashScreen::FinalizeVSS() { - if (!ReleaseVSSCom()) - return; +bool VideoSplashScreen::IsPlayerPlaying() { + auto& app_data = ApplicationDataTV::GetInstance(); + return app_data.video_splash_screen_info().HasVideoSplashScreenData() && + video_player && video_player->IsPlayerPlaying(); +} - LOG(INFO) << "Finalize AUL APP COM and VSS"; - aul_app_com_leave(aul_app_com_connection_); - aul_app_com_connection_ = nullptr; - aul_extension_splash_screen_tv_reset(); +VideoSplashScreen::VideoSplashScreen() { +#if TIZEN_VERSION_AT_LEAST(9, 0, 0) + video_player = std::make_unique(); +#else + video_player = std::make_unique(); +#endif } -// static -void VideoSplashScreen::InitializeVSS() { - auto& app_data = ApplicationDataTV::GetInstance(); - if (!app_data.video_splash_screen_info().HasVideoSplashScreenData()) - return; +VideoSplashScreen::~VideoSplashScreen() { + video_player.reset(); +} - if (aul_app_com_connection_) +void VideoSplashScreen::Init() { + if (!video_player->Initialize()) return; - - if (!aul_extension_splash_screen_tv_event("ISVIDEO")) { - LOG(ERROR) << "Failed to send ISVIDEO to VSS"; + if (!video_player->PreparePlayer()) return; - } - std::string com_endpoint = kSplashScreenAulAppCom + app_data.app_id(); - if (aul_app_com_create(com_endpoint.c_str(), nullptr, OnSplashScreenMessage, - nullptr, &aul_app_com_connection_)) { - LOG(ERROR) << "Failed to initialize AUL APP COM"; - } else { - LOG(ERROR) << "Initialized AUL APP COM with " << com_endpoint; - } -} - -void VideoSplashScreen::BeforeHide() { - Hide(); + auto video_src = GetVideoSrc(); + if (!video_player->PlayerStart(video_src)) + LOG(ERROR) << "VSS playing is failed"; + else + LOG(INFO) << "VSS is now playing"; } void VideoSplashScreen::Hide() { - if (was_hidden_) - return; - - if (VideoSplashScreen::IsVSSPlaying()) { - auto hidden_reason = SplashScreen::GetHiddenReason(); - const char* hide_reason = HideReasonToString(hidden_reason); - HideVSSPlayer(hide_reason); - was_hidden_ = true; - } + video_player->Hide(); } wgt::parse::ReadyWhen VideoSplashScreen::GetReadyWhen() { @@ -146,4 +73,36 @@ wgt::parse::ReadyWhen VideoSplashScreen::GetReadyWhen() { return app_data.video_splash_screen_info().ready_when(); } +std::string VideoSplashScreen::GetVideoSrc() { + auto default_orientation = wgt::parse::ScreenOrientation::AUTO; + auto orientation = + delegate_ ? delegate_->GetScreenOrientation() : default_orientation; + + auto& app_data = ApplicationDataTV::GetInstance(); + auto& vss_info = app_data.video_splash_screen_info(); + auto video_src = vss_info.GetVideoSrc(orientation); + if (video_src.empty()) + video_src = vss_info.GetVideoSrc(default_orientation); + + if (video_src.empty()) + return {}; + + auto backup_path = + base::FilePath("/opt/share/webappservice/videoSplashScreen/") + .Append(app_data.GetPackageID()) + .Append(video_src); + if (base::PathExists(backup_path)) { + LOG(INFO) << "backup_path src : " << backup_path; + return backup_path.value(); + } + + auto video_absolute_path = + base::FilePath(app_data.application_path()).Append(video_src); + if (base::PathExists(video_absolute_path)) { + return video_absolute_path.value(); + } + + return {}; +} + } // namespace wrt diff --git a/wrt/src/browser/tv/video_splash_screen.h b/wrt/src/browser/tv/video_splash_screen.h index 661419f..f74e9bf 100644 --- a/wrt/src/browser/tv/video_splash_screen.h +++ b/wrt/src/browser/tv/video_splash_screen.h @@ -9,25 +9,25 @@ #include "wrt/src/browser/splash_screen.h" #include "wrt/src/common/application_data.h" +#include "wrt/src/common/splash_screen_delegate.h" namespace wrt { class VideoSplashScreen : public SplashScreen { public: - VideoSplashScreen() = default; - ~VideoSplashScreen(); + static SplashScreen* Create(); + static bool IsPlayerPlaying(); - static void InitializeVSS(); - static bool IsVSSPlaying(); - static void FinalizeVSS(); + VideoSplashScreen(); + ~VideoSplashScreen() override; private: - void Init() override {} - void BeforeHide() override; + // SplashScreen + void Init() override; void Hide() override; wgt::parse::ReadyWhen GetReadyWhen() override; - bool was_hidden_ = false; + std::string GetVideoSrc(); }; } // namespace wrt diff --git a/wrt/src/browser/tv/wrt_native_window_tv.cc b/wrt/src/browser/tv/wrt_native_window_tv.cc index 5684d27..e6107c2 100644 --- a/wrt/src/browser/tv/wrt_native_window_tv.cc +++ b/wrt/src/browser/tv/wrt_native_window_tv.cc @@ -4,7 +4,6 @@ #include "wrt/src/browser/tv/wrt_native_window_tv.h" -#include #include #include #include @@ -1154,12 +1153,11 @@ void WRTNativeWindowTV::VisibilityChangedAsBackground() { SuspendMedia(true); DisableVisibilitySetting(); - if (visibility_state_.empty() && !VideoSplashScreen::IsVSSPlaying()) + if (visibility_state_.empty() && !VideoSplashScreen::IsPlayerPlaying()) WidgetStateProvider::OnStatusChanged("behind"); visibility_state_ = "hidden"; OnVisibilityChange(false); - VideoSplashScreen::FinalizeVSS(); } void WRTNativeWindowTV::VisibilityChangedAsForeground() { diff --git a/wrt/src/browser/wrt_native_window.cc b/wrt/src/browser/wrt_native_window.cc index dd83f27..b8bdeb8 100644 --- a/wrt/src/browser/wrt_native_window.cc +++ b/wrt/src/browser/wrt_native_window.cc @@ -506,6 +506,7 @@ WRTNativeWindow::WRTNativeWindow(const gin_helper::Dictionary& options, if (is_main_native_window_) { EnsurePlatformWindow(); InitializePlatformEventListeners(); + SplashScreen::AddObserver(this); // TODO: Find a way to avoid using elementary elm_app_name_set(ApplicationData::GetInstance().app_id().c_str()); } diff --git a/wrt/src/common/application_data_wrapper.h b/wrt/src/common/application_data_wrapper.h index c98f864..ccdfb28 100755 --- a/wrt/src/common/application_data_wrapper.h +++ b/wrt/src/common/application_data_wrapper.h @@ -214,12 +214,19 @@ class AddonInfo : public Wrapper { class VideoSplashScreenInfo : public Wrapper { public: + const std::string GetVideoSrc( + wgt::parse::ScreenOrientation orientation) const { + if (!impl_) + return nullptr; + + auto& screen_data = impl_->launch_screen_data(); + auto iter = screen_data.find(orientation); + if (iter != screen_data.end()) + return iter->second.video; + return {}; + } bool HasVideoSplashScreenData() const { -#if TIZEN_VERSION_AT_LEAST(6, 0, 0) if (!impl_ || impl_->launch_screen_data().empty()) -#else - if (!impl_ || impl_->screen_data().empty()) -#endif return false; return true; } diff --git a/wrt/src/common/splash_screen_delegate.cc b/wrt/src/common/splash_screen_delegate.cc new file mode 100644 index 0000000..629e970 --- /dev/null +++ b/wrt/src/common/splash_screen_delegate.cc @@ -0,0 +1,19 @@ +// Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "wrt/src/common/splash_screen_delegate.h" + +#include "wrt/src/browser/basic_splash_screen.h" + +namespace wrt { + +SplashScreen* SplashScreenDelegate::CreateSplashScreen() { + auto& app_data = ApplicationData::GetInstance(); + if (app_data.launch_screen_info().HasLaunchScreenData()) + return BasicSplashScreen::Create(); + else + return nullptr; +} + +} // namespace wrt diff --git a/wrt/src/common/splash_screen_delegate.h b/wrt/src/common/splash_screen_delegate.h index 3accac3..b0f0405 100644 --- a/wrt/src/common/splash_screen_delegate.h +++ b/wrt/src/common/splash_screen_delegate.h @@ -26,9 +26,8 @@ class SplashScreenDelegate { return wgt::parse::ScreenOrientation::AUTO; } virtual void SetSplashImage(Evas_Object* image, Evas_Object* background) {} - virtual bool IsVideoPlaying() { return false; } virtual std::string ConvertAliasPath(std::string& image_path) { return {}; } - virtual SplashScreen* CreateVideoSplashScreen() { return nullptr; } + virtual SplashScreen* CreateSplashScreen(); }; class SplashScreenWidgetDelegate : public views::WidgetDelegate { diff --git a/wrt/src/common/tv/wrt_lib_wrapper.cc b/wrt/src/common/tv/wrt_lib_wrapper.cc index 45d4c55..0e576da 100644 --- a/wrt/src/common/tv/wrt_lib_wrapper.cc +++ b/wrt/src/common/tv/wrt_lib_wrapper.cc @@ -26,6 +26,7 @@ const char* kLibCapiUiEflUtil = LIB_PATH "/libcapi-ui-efl-util.so.0"; const char* kLibEflAssist = LIB_PATH "/libefl-assist.so.0"; const char* kLibTvControl = LIB_PATH "/libtv-control.so.0"; const char* kLibDeviced = LIB_PATH "/libdeviced.so.1"; +const char* kLibAulExtension = LIB_PATH "/libaul-extension.so.0"; base::Lock worker_thread_lock; @@ -208,4 +209,45 @@ ambient_mode_e device_power_get_ambient_mode(void) { return AMBIENT_MODE_OFF; } +int aul_extension_splash_screen_tv_event(const char* event) { + typedef int (*func_sig)(const char*); + auto* func = (func_sig)GetFunction(kLibAulExtension, __FUNCTION__); + if (func) + return func(event); + else + return -1; +} + +int aul_extension_splash_screen_tv_reset() { + typedef int (*func_sig)(); + auto* func = (func_sig)GetFunction(kLibAulExtension, __FUNCTION__); + if (func) + return func(); + else + return -1; +} + +int aul_app_com_create(const char* endpoint, + aul_app_com_permission_h permission, + app_com_cb callback, + void* user_data, + aul_app_com_connection_h* connection) { + typedef int (*func_sig)(const char*, aul_app_com_permission_h, app_com_cb, + void*, aul_app_com_connection_h*); + auto* func = (func_sig)GetFunction(kLibAulExtension, __FUNCTION__); + if (func) + return func(endpoint, permission, callback, user_data, connection); + else + return -1; +} + +int aul_app_com_leave(aul_app_com_connection_h connection) { + typedef int (*func_sig)(aul_app_com_connection_h); + auto* func = (func_sig)GetFunction(kLibAulExtension, __FUNCTION__); + if (func) + return func(connection); + else + return -1; +} + } // namespace wrt diff --git a/wrt/src/common/tv/wrt_lib_wrapper.h b/wrt/src/common/tv/wrt_lib_wrapper.h index ef919e6..dc79b5a 100644 --- a/wrt/src/common/tv/wrt_lib_wrapper.h +++ b/wrt/src/common/tv/wrt_lib_wrapper.h @@ -6,6 +6,7 @@ #define COMMON_TV_WRT_LIB_WRAPPER_H_ #include +#include namespace wrt { @@ -85,6 +86,27 @@ int device_power_subscribe_state_changed_event(device_state_changed_cb cb, int device_power_unsubscribe_state_changed_event(device_state_changed_cb cb); ambient_mode_e device_power_get_ambient_mode(void); +// aul-extension + +typedef void* aul_app_com_result_e; + +typedef int (*app_com_cb)(const char* endpoint, + aul_app_com_result_e result, + bundle* envelope, + void* user_data); + +typedef void* aul_app_com_connection_h; +typedef void* aul_app_com_permission_h; + +int aul_extension_splash_screen_tv_event(const char* event); +int aul_extension_splash_screen_tv_reset(); +int aul_app_com_create(const char* endpoint, + aul_app_com_permission_h permission, + app_com_cb callback, + void* user_data, + aul_app_com_connection_h* connection); +int aul_app_com_leave(aul_app_com_connection_h connection); + } // namespace wrt #endif // COMMON_TV_WRT_LIB_WRAPPER_H_ -- 2.7.4 From d94b2bd1fe63eca58eb650f04884bb62d5dd4ee5 Mon Sep 17 00:00:00 2001 From: jiangyuwei Date: Mon, 8 Apr 2024 18:42:45 +0800 Subject: [PATCH 13/16] [M120 Migration][VD] Support custom context menu When a user long click on the link in webpage, context menu should popup. Reference : - https://review.tizen.org/gerrit/#/c/291848/ Change-Id: Id307f33fdcc3bbda45c2c0feec1bdff3adcde14c Signed-off-by: jiangyuwei --- .../renderer_host/rwhv_aura_common_helper_efl.cc | 26 ++++++++ .../renderer_host/rwhv_aura_common_helper_efl.h | 10 ++++ .../ui/ozone/platform/efl/efl_event_handler.cc | 35 +++++++++++ .../ui/ozone/platform/efl/efl_event_handler.h | 10 ++++ .../efl_integration/context_menu_controller_efl.cc | 70 +++++++++++++++------- .../efl_integration/context_menu_controller_efl.h | 3 + tizen_src/ewk/efl_integration/eweb_view.cc | 49 +++++++++++++++ tizen_src/ewk/efl_integration/eweb_view.h | 7 ++- .../ewk/efl_integration/eweb_view_callbacks.h | 8 +++ .../ewk/efl_integration/popup_controller_efl.cc | 8 +-- .../private/ewk_context_menu_item_private.h | 3 - .../private/ewk_context_menu_private.h | 67 ++++++++++++++------- .../ewk/efl_integration/public/ewk_context_menu.cc | 27 +++++---- 13 files changed, 261 insertions(+), 62 deletions(-) diff --git a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc index e9192bc..b314e4f 100644 --- a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc +++ b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc @@ -532,6 +532,32 @@ void RWHVAuraCommonHelperEfl::SetMouseEventsEnabled(bool enable) { if (auto* event_handler = GetEventHandler()) event_handler->SetMouseEventsEnabled(enable); } + +void RWHVAuraCommonHelperEfl::SetMouseEventCallbacks( + const base::RepeatingCallback& on_mouse_down, + const base::RepeatingCallback& on_mouse_up, + const base::RepeatingCallback& on_mouse_move) { + if (auto* event_handler = GetEventHandler()) + event_handler->SetMouseEventCallbacks(on_mouse_down, on_mouse_up, + on_mouse_move); +} + +void RWHVAuraCommonHelperEfl::MouseDownCallback(int x, int y) { + if (!on_mouse_down_callback_.is_null()) + on_mouse_down_callback_.Run(x, y); +} + +bool RWHVAuraCommonHelperEfl::MouseUpCallback() { + if (!on_mouse_up_callback_.is_null()) + return on_mouse_up_callback_.Run(); + + return false; +} + +void RWHVAuraCommonHelperEfl::MouseMoveCallback() { + if (!on_mouse_move_callback_.is_null()) + on_mouse_move_callback_.Run(); +} #endif void RWHVAuraCommonHelperEfl::OnGetMainFrameScrollbarVisible( diff --git a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h index 1c1ad6b..c0cf7ae 100644 --- a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h +++ b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h @@ -154,6 +154,13 @@ class CONTENT_EXPORT RWHVAuraCommonHelperEfl { // notify web browser video playing status void RequestVideoPlaying(int callback_id); void VideoPlayingStatusReceived(bool is_playing, int callback_id); + void SetMouseEventCallbacks( + const base::RepeatingCallback& on_mouse_down, + const base::RepeatingCallback& on_mouse_up, + const base::RepeatingCallback& on_mouse_move); + void MouseDownCallback(int x, int y); + bool MouseUpCallback(); + void MouseMoveCallback(); #endif void CompositingCompleteSwapWithNewSize(const gfx::Size& size) { @@ -215,6 +222,9 @@ class CONTENT_EXPORT RWHVAuraCommonHelperEfl { // When WebBrowser sets their own cursor, set the flag // not to set the WebPage cursor bool cursor_set_by_client_ = false; + base::RepeatingCallback on_mouse_down_callback_; + base::RepeatingCallback on_mouse_up_callback_; + base::RepeatingCallback on_mouse_move_callback_; #endif std::unique_ptr rwh_helper_; diff --git a/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_event_handler.cc b/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_event_handler.cc index 862e74a..bb873d8 100644 --- a/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_event_handler.cc +++ b/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_event_handler.cc @@ -77,6 +77,15 @@ bool IsRCDevice(Evas_Device_Class device_id, const std::string device_name) { enum { kLeftButton = 1, kMiddleButton = 2, kRightButton = 3 }; +#if BUILDFLAG(IS_TIZEN_TV) +static void TranslateEvasCoordToWebKitCoord(Evas_Object* web_view, + gfx::PointF* point) { + Evas_Coord tmpX, tmpY; + evas_object_geometry_get(web_view, &tmpX, &tmpY, 0, 0); + point->Offset(-tmpX, -tmpY); +} +#endif + EventFlags EvasToUIMouseButton(int button) { if (button == kLeftButton) return EF_LEFT_MOUSE_BUTTON; @@ -513,6 +522,14 @@ void EflEventHandler::OnMouseDown(void* data, MouseEvent event = MakeWebMouseEvent(ET_MOUSE_PRESSED, ev, thiz->GetTopControlsHeight()); EflPlatformEventSource::GetInstance()->DispatchEflEvent(&event); +#if BUILDFLAG(IS_TIZEN_TV) + if (!thiz->on_mouse_down_callback_.is_null()) { + const float sf = GetDeviceScaleFactor(); + gfx::PointF location(ev->canvas.x / sf, ev->canvas.y / sf); + TranslateEvasCoordToWebKitCoord(obj, &location); + thiz->on_mouse_down_callback_.Run(location.x(), location.y()); + } +#endif } } @@ -531,6 +548,11 @@ void EflEventHandler::OnMouseUp(void* data, MouseEvent event = MakeWebMouseEvent(ET_MOUSE_RELEASED, ev, thiz->GetTopControlsHeight()); EflPlatformEventSource::GetInstance()->DispatchEflEvent(&event); +#if BUILDFLAG(IS_TIZEN_TV) + if (!thiz->on_mouse_up_callback_.is_null() && + thiz->on_mouse_up_callback_.Run()) + return; +#endif } } @@ -557,6 +579,10 @@ void EflEventHandler::OnMouseMove(void* data, gfx::Vector2dF((ev->cur.canvas.x / sf - ev->prev.canvas.x / sf), (ev->cur.canvas.y / sf - ev->prev.canvas.y / sf))); EflPlatformEventSource::GetInstance()->DispatchEflEvent(&event); +#if BUILDFLAG(IS_TIZEN_TV) + if (!thiz->on_mouse_move_callback_.is_null()) + thiz->on_mouse_move_callback_.Run(); +#endif } } @@ -860,6 +886,15 @@ void EflEventHandler::SetKeyEventChecker( const base::RepeatingCallback& checker) { key_event_checker_ = checker; } + +void EflEventHandler::SetMouseEventCallbacks( + const base::RepeatingCallback& on_mouse_down, + const base::RepeatingCallback& on_mouse_up, + const base::RepeatingCallback& on_mouse_move) { + on_mouse_down_callback_ = on_mouse_down; + on_mouse_up_callback_ = on_mouse_up; + on_mouse_move_callback_ = on_mouse_move; +} #endif void EflEventHandler::OnMultiTouchDownEvent(void* data, diff --git a/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_event_handler.h b/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_event_handler.h index 7bda5e8..af5a56e 100644 --- a/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_event_handler.h +++ b/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_event_handler.h @@ -42,6 +42,13 @@ class EflEventHandler { EflEventHandler(const EflEventHandler&) = delete; EflEventHandler& operator=(const EflEventHandler&) = delete; +#if BUILDFLAG(IS_TIZEN_TV) + void SetMouseEventCallbacks( + const base::RepeatingCallback& on_mouse_down, + const base::RepeatingCallback& on_mouse_up, + const base::RepeatingCallback& on_mouse_move); +#endif + void SetMouseEventsEnabled(bool enabled); bool MouseEventsEnabled() const { return mouse_events_enabled_; } void SetTouchEventsEnabled(bool enabled); @@ -120,6 +127,9 @@ class EflEventHandler { #if BUILDFLAG(IS_TIZEN_TV) base::RepeatingCallback key_event_checker_; + base::RepeatingCallback on_mouse_down_callback_; + base::RepeatingCallback on_mouse_up_callback_; + base::RepeatingCallback on_mouse_move_callback_; #endif }; diff --git a/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc b/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc index 8519b73..a58e573 100644 --- a/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc +++ b/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc @@ -44,6 +44,7 @@ ContextMenuControllerEfl::ContextMenuControllerEfl(EWebView* wv, WebContents& web_contents) : ContextMenuControllerBase(web_contents), webview_(wv), + menu_items_parent_(nullptr), weak_ptr_factory_(this) {} ContextMenuControllerEfl::~ContextMenuControllerEfl() { @@ -76,16 +77,32 @@ bool ContextMenuControllerEfl::PopulateAndShowContextMenu(const ContextMenuParam return false; params_ = params; + +#if BUILDFLAG(IS_TIZEN_TV) + if (params_.link_url.is_empty()) { + LOG(INFO) << "link url is empty"; + return false; + } +#endif is_text_selection_ = params_.is_editable || (params_.link_url.is_empty() && params_.src_url.is_empty() && params_.media_type == ContextMenuDataMediaType::kNone); + menu_items_parent_.reset(new _Ewk_Context_Menu(this)); +#if BUILDFLAG(IS_TIZEN_TV) + menu_items_parent_.get()->SetPosition(params_.x, params_.y); +#endif GetProposedContextMenu(); - menu_items_parent_.reset(new _Ewk_Context_Menu(menu_items_)); +#if BUILDFLAG(IS_TIZEN_TV) + LOG(INFO) << "Context Menu Show"; + webview_->SmartCallback().call( + menu_items_parent_.get()); + return true; +#endif + LOG(INFO) << "Context Menu Customize"; webview_->SmartCallback().call( menu_items_parent_.get()); - menu_items_ = menu_items_parent_->TakeMenuList(); if (!CreateContextMenu(params)) return false; @@ -113,17 +130,21 @@ void ContextMenuControllerEfl::AddItemToProposedList(Ewk_Context_Menu_Item_Type void ContextMenuControllerEfl::GetProposedContextMenu() { if (!params_.link_url.is_empty()) { AddItemToProposedList(EWK_CONTEXT_MENU_ITEM_TYPE_ACTION, - EWK_CONTEXT_MENU_ITEM_TAG_OPEN_LINK, - dgettext("WebKit", - "IDS_WEBVIEW_OPT_OPEN_LINK_IN_CURRENT_TAB_ABB"), - params_.link_url.spec(), - params_.link_url.spec()); - AddItemToProposedList(EWK_CONTEXT_MENU_ITEM_TYPE_ACTION, + EWK_CONTEXT_MENU_ITEM_TAG_OPEN_LINK, + dgettext("WebKit", +#if BUILDFLAG(IS_TIZEN_TV) + "IDS_WEBVIEW_OPEN"), +#else + "IDS_WEBVIEW_OPT_OPEN_LINK_IN_CURRENT_TAB_" + "ABB"), +#endif + params_.link_url.spec(), params_.link_url.spec()); + AddItemToProposedList( + EWK_CONTEXT_MENU_ITEM_TYPE_ACTION, EWK_CONTEXT_MENU_ITEM_TAG_OPEN_LINK_IN_NEW_WINDOW, - std::string(dgettext("WebKit", - "IDS_WEBVIEW_OPT_OPEN_LINK_IN_NEW_TAB_ABB")), - params_.link_url.spec(), - params_.link_url.spec()); + std::string( + dgettext("WebKit", "IDS_TPLATFORM_OPT_OPEN_LINK_IN_NEW_TAB_ABB")), + params_.link_url.spec(), params_.link_url.spec()); AddItemToProposedList(EWK_CONTEXT_MENU_ITEM_TYPE_ACTION, EWK_CONTEXT_MENU_ITEM_TAG_COPY_LINK_DATA, std::string(dgettext("WebKit", @@ -169,13 +190,12 @@ void ContextMenuControllerEfl::GetProposedContextMenu() { } if (params_.has_image_contents && !params_.src_url.is_empty()) { - AddItemToProposedList(EWK_CONTEXT_MENU_ITEM_TYPE_ACTION, + AddItemToProposedList( + EWK_CONTEXT_MENU_ITEM_TYPE_ACTION, EWK_CONTEXT_MENU_ITEM_TAG_OPEN_IMAGE_IN_CURRENT_WINDOW, - std::string(dgettext( - "WebKit", - "IDS_WEBVIEW_OPT_OPEN_IMAGE_IN_CURRENT_TAB_ABB")), - params_.src_url.spec(), - params_.src_url.spec()); + std::string( + dgettext("WebKit", "IDS_WEBVIEW_OPT_OPEN_IMAGE_IN_CURRENT_TAB")), + params_.src_url.spec(), params_.src_url.spec()); AddItemToProposedList(EWK_CONTEXT_MENU_ITEM_TYPE_ACTION, EWK_CONTEXT_MENU_ITEM_TAG_OPEN_IMAGE_IN_NEW_WINDOW, std::string(dgettext("WebKit", @@ -294,8 +314,7 @@ void ContextMenuControllerEfl::OnDiskDownload( if (!item) { save_fail_dialog_.reset(JavaScriptModalDialogEfl::CreateDialogAndShow( &web_contents_, JavaScriptModalDialogEfl::ALERT, - base::UTF8ToUTF16( - std::string(dgettext("WebKit", "IDS_WEBVIEW_POP_FAIL"))), + base::UTF8ToUTF16(std::string(dgettext("WebKit", "IDS_BR_POP_FAIL"))), std::u16string(), base::BindOnce(&EmptyDialogClosedCallback))); return; } @@ -318,7 +337,7 @@ void ContextMenuControllerEfl::OnDownloadUpdated( file_saved_dialog_.reset(JavaScriptModalDialogEfl::CreateDialogAndShow( &web_contents_, JavaScriptModalDialogEfl::ALERT, base::UTF8ToUTF16( - std::string(dgettext("WebKit", "IDS_WEBVIEW_POP_SAVED"))), + std::string(dgettext("WebKit", "IDS_BR_POP_SAVED"))), std::u16string(), base::BindOnce(&EmptyDialogClosedCallback))); download->RemoveObserver(this); disk_download_items_.erase(download); @@ -653,4 +672,13 @@ void ContextMenuControllerEfl::Resize(const gfx::Rect& webview_rect) { ContextMenuControllerBase::Resize(webview_rect); } + +void ContextMenuControllerEfl::AppendItem(const _Ewk_Context_Menu_Item* item) { + menu_items_ = eina_list_append(menu_items_, item); +} + +void ContextMenuControllerEfl::RemoveItem(const _Ewk_Context_Menu_Item* item) { + menu_items_ = eina_list_remove(menu_items_, item); + delete item; +} } diff --git a/tizen_src/ewk/efl_integration/context_menu_controller_efl.h b/tizen_src/ewk/efl_integration/context_menu_controller_efl.h index a9115cb..cd9af34 100644 --- a/tizen_src/ewk/efl_integration/context_menu_controller_efl.h +++ b/tizen_src/ewk/efl_integration/context_menu_controller_efl.h @@ -32,6 +32,9 @@ class ContextMenuControllerEfl : public ContextMenuControllerBase, void MenuItemSelected(ContextMenuItemEfl* menu_item) override; gfx::Point GetContextMenuShowPos() const { return context_menu_show_pos_; }; void Resize(const gfx::Rect& webview_rect) override; + Eina_List* GetMenuItems() const { return menu_items_; } + void AppendItem(const _Ewk_Context_Menu_Item* item); + void RemoveItem(const _Ewk_Context_Menu_Item* item); private: // ContextMenuControllerBase diff --git a/tizen_src/ewk/efl_integration/eweb_view.cc b/tizen_src/ewk/efl_integration/eweb_view.cc index ce6088c..20fa95d 100644 --- a/tizen_src/ewk/efl_integration/eweb_view.cc +++ b/tizen_src/ewk/efl_integration/eweb_view.cc @@ -136,6 +136,9 @@ const base::FilePath::CharType kDefaultFileName[] = FILE_PATH_LITERAL("saved_page"); const char kReplaceChars[] = " "; const char kReplaceWith[] = "_"; +#if BUILDFLAG(IS_TIZEN_TV) +static const int kMousePressAndHoldTimeout = 500; // long press: 500ms +#endif static const char* kRendererCrashedHTMLMessage = "

Renderer process has crashed!

"; @@ -368,6 +371,7 @@ EWebView::EWebView(Ewk_Context* context, Evas_Object* ewk_view) is_processing_edge_scroll_(false), use_early_rwi_(false), rwi_info_showed_(false), + context_menu_show_(false), #endif #if defined(TIZEN_PEPPER_EXTENSIONS) render_frame_id_{0, 0}, @@ -1934,6 +1938,14 @@ void EWebView::RenderViewReady() { host->AddFilter(new WebViewBrowserMessageFilter(content)); } } +#if BUILDFLAG(IS_TIZEN_TV) + if (rwhva() && IsWebBrowser()) { + rwhva()->aura_efl_helper()->SetMouseEventCallbacks( + base::BindRepeating(&EWebView::OnMouseDown, base::Unretained(this)), + base::BindRepeating(&EWebView::OnMouseUp, base::Unretained(this)), + base::BindRepeating(&EWebView::OnMouseMove, base::Unretained(this))); + } +#endif } void EWebView::SetQuotaPermissionRequestCallback( @@ -2902,6 +2914,43 @@ void EWebView::InitInspectorServer() { } } } + +void EWebView::OnMouseLongPressed(int x, int y) { + RenderViewHost* render_view_host = web_contents_->GetRenderViewHost(); + if (!render_view_host) + return; + + LOG(INFO) << __FUNCTION__; + RenderWidgetHostImpl* render_wiget_host_impl = + static_cast(render_view_host)->GetWidget(); + if (!render_wiget_host_impl) + return; + + render_wiget_host_impl->ShowContextMenuAtPoint( + gfx::Point(x, y), ui::MenuSourceType::MENU_SOURCE_MOUSE); + context_menu_show_ = true; +} + +void EWebView::OnMouseDown(int x, int y) { + mouse_long_press_timer_.Start( + FROM_HERE, base::Milliseconds(kMousePressAndHoldTimeout), + base::BindRepeating(&EWebView::OnMouseLongPressed, base::Unretained(this), + x, y)); +} + +bool EWebView::OnMouseUp() { + LOG(INFO) << __FUNCTION__; + mouse_long_press_timer_.Stop(); + if (context_menu_show_) { + context_menu_show_ = false; + return true; + } + return false; +} + +void EWebView::OnMouseMove() { + mouse_long_press_timer_.Stop(); +} #endif #if defined(TIZEN_TBM_SUPPORT) diff --git a/tizen_src/ewk/efl_integration/eweb_view.h b/tizen_src/ewk/efl_integration/eweb_view.h index fbd8004..0d50a4d 100644 --- a/tizen_src/ewk/efl_integration/eweb_view.h +++ b/tizen_src/ewk/efl_integration/eweb_view.h @@ -837,6 +837,10 @@ class EWebView { void SetTranslatedURL(const char* url); void NotifyParentalRatingInfo(const char* info, const char* url); void SetParentalRatingResult(const char* info, bool is_pass); + void OnMouseLongPressed(int x, int y); + void OnMouseDown(int x, int y); + bool OnMouseUp(); + void OnMouseMove(); #endif // IS_TIZEN_TV void SetDidChangeThemeColorCallback( @@ -1037,7 +1041,8 @@ class EWebView { bool rwi_info_showed_; GURL rwi_gurl_; bool is_high_bitrate_ = false; - + bool context_menu_show_; + base::OneShotTimer mouse_long_press_timer_; base::OnceClosure pending_setfocus_closure_; enum PlaybackState { diff --git a/tizen_src/ewk/efl_integration/eweb_view_callbacks.h b/tizen_src/ewk/efl_integration/eweb_view_callbacks.h index 06ed6a5..6830c60 100644 --- a/tizen_src/ewk/efl_integration/eweb_view_callbacks.h +++ b/tizen_src/ewk/efl_integration/eweb_view_callbacks.h @@ -121,6 +121,8 @@ enum CallbackType { EdgeScrollLeft, EdgeScrollRight, EdgeScrollTop, + ContextMenuShow, + ContextMenuHide, DeviceConnectionChanged, PlaybackLoad, PlaybackVideoReady, @@ -310,6 +312,12 @@ DECLARE_EWK_VIEW_CALLBACK(EdgeScrollTop, "edge,scroll,top", bool*); DECLARE_EWK_VIEW_CALLBACK(DeviceConnectionChanged, "device,connection,changed", int*); +DECLARE_EWK_VIEW_CALLBACK(ContextMenuShow, + "contextmenu,show", + _Ewk_Context_Menu*); +DECLARE_EWK_VIEW_CALLBACK(ContextMenuHide, + "contextmenu,hide", + _Ewk_Context_Menu*); DECLARE_EWK_VIEW_CALLBACK(PlaybackLoad, "notification,playback,load", void*); DECLARE_EWK_VIEW_CALLBACK(PlaybackVideoReady, "notification,playback,videoready", diff --git a/tizen_src/ewk/efl_integration/popup_controller_efl.cc b/tizen_src/ewk/efl_integration/popup_controller_efl.cc index 6f12082..1b8dd83 100644 --- a/tizen_src/ewk/efl_integration/popup_controller_efl.cc +++ b/tizen_src/ewk/efl_integration/popup_controller_efl.cc @@ -152,13 +152,13 @@ char* PopupControllerEfl::contextMenuGenlistTextSet( char* label = NULL; if (options_[index] == CALL) - label = strdup(dgettext("WebKit","IDS_WEBVIEW_OPT_CALL")); + label = strdup(dgettext("WebKit", "IDS_BR_OPT_CALL")); else if (options_[index] == SEND_EMAIL) - label = strdup(dgettext("WebKit","IDS_WEBVIEW_OPT_SEND_EMAIL")); + label = strdup(dgettext("WebKit", "IDS_BR_OPT_SEND_EMAIL")); else if (options_[index] == SEND_MESSAGE) - label = strdup(dgettext("WebKit","IDS_WEBVIEW_OPT_SEND_MESSAGE")); + label = strdup(dgettext("WebKit", "IDS_COM_BODY_OPT_SEND_MESSAGE")); else if (options_[index] == ADD_CONTACT) - label = strdup(dgettext("WebKit","IDS_WEBVIEW_BODY_ADD_TO_CONTACT")); + label = strdup(dgettext("WebKit", "IDS_BR_BODY_ADD_TO_CONTACT")); else if (options_[index] == COPY) label = strdup(dgettext("WebKit","IDS_WEBVIEW_OPT_COPY")); diff --git a/tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h b/tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h index b12fc72..8c3df5a 100644 --- a/tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h +++ b/tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h @@ -20,9 +20,6 @@ class _Ewk_Context_Menu_Item { menu_item_ = nullptr; } - _Ewk_Context_Menu_Item(const _Ewk_Context_Menu_Item&) = delete; - _Ewk_Context_Menu_Item& operator=(const _Ewk_Context_Menu_Item&) = delete; - content::ContextMenuItemEfl* GetMenuItem() const { return menu_item_; } _Ewk_Context_Menu* ParentMenu() const { return parent_menu_; } diff --git a/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h b/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h index 216b29d..55aebcc 100644 --- a/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h +++ b/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h @@ -11,44 +11,67 @@ #include "context_menu_controller_efl.h" #include "ewk_context_menu_item_private.h" +#if BUILDFLAG(IS_TIZEN_TV) +#include "ui/display/screen.h" +#endif + // Wrapper for context_menu_controller items class _Ewk_Context_Menu { public: - _Ewk_Context_Menu(Eina_List* menu_list) - : menu_list_(menu_list) { + _Ewk_Context_Menu(content::ContextMenuControllerEfl* controller) +#if BUILDFLAG(IS_TIZEN_TV) + : controller_(controller), position_(0, 0) { +#else + : controller_(controller) { +#endif } - ~_Ewk_Context_Menu() { - if (menu_list_) { - void* data; - EINA_LIST_FREE(menu_list_, data) { - _Ewk_Context_Menu_Item *item = static_cast<_Ewk_Context_Menu_Item*> (data); - delete item; - } - } + const Eina_List* GetMenuList() const { + if (controller_) + return controller_->GetMenuItems(); // LCOV_EXCL_LINE + else + return nullptr; // LCOV_EXCL_LINE } - const Eina_List* GetMenuList() const { - return menu_list_; + content::ContextMenuControllerEfl* GetController() const { + return controller_; // LCOV_EXCL_LINE + } + + void AppendItem(const _Ewk_Context_Menu_Item* item) { + if (controller_) + controller_->AppendItem(item); + } + + void RemoveItem(const _Ewk_Context_Menu_Item* item) { + if (controller_) + controller_->RemoveItem(item); } - Eina_List* TakeMenuList() { - Eina_List* ptr = menu_list_; - menu_list_ = NULL; - return ptr; + void MenuItemSelected(const _Ewk_Context_Menu_Item* item) { + content::ContextMenuItemEfl* info_item = item->GetMenuItem(); + if (controller_) + controller_->MenuItemSelected(info_item); } - void AppendItem(const void* item) { - menu_list_ = eina_list_append(menu_list_, item); + void HideContextMenu() { + if (controller_) + controller_->HideContextMenu(); } - void RemoveItem(_Ewk_Context_Menu_Item* item) { - menu_list_ = eina_list_remove(menu_list_, item); - delete item; +#if BUILDFLAG(IS_TIZEN_TV) + void SetPosition(int x, int y) { + position_.set_x(x); + position_.set_y(y); } + gfx::Point GetPosition() { return position_; } // LCOV_EXCL_LINE +#endif + private: - Eina_List* menu_list_; + content::ContextMenuControllerEfl* controller_; +#if BUILDFLAG(IS_TIZEN_TV) + gfx::Point position_; +#endif }; #endif // ewk_context_menu_private_h diff --git a/tizen_src/ewk/efl_integration/public/ewk_context_menu.cc b/tizen_src/ewk/efl_integration/public/ewk_context_menu.cc index d52ec97..a747125 100644 --- a/tizen_src/ewk/efl_integration/public/ewk_context_menu.cc +++ b/tizen_src/ewk/efl_integration/public/ewk_context_menu.cc @@ -105,7 +105,9 @@ const char* ewk_context_menu_item_image_url_get(Ewk_Context_Menu_Item* item) const char* ewk_context_menu_item_title_get(const Ewk_Context_Menu_Item* item) { - LOG_EWK_API_MOCKUP(); + EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL); + if (item->GetMenuItem()) + return item->GetMenuItem()->Title().c_str(); return NULL; } @@ -123,8 +125,8 @@ Ewk_Context_Menu* ewk_context_menu_item_submenu_get(const Ewk_Context_Menu_Item* const Eina_List* ewk_context_menu_items_get(const Ewk_Context_Menu* menu) { - LOG_EWK_API_MOCKUP(); - return NULL; + EINA_SAFETY_ON_NULL_RETURN_VAL(menu, NULL); + return menu->GetMenuList(); } Ewk_Context_Menu* ewk_context_menu_item_parent_menu_get(const Ewk_Context_Menu_Item* item) @@ -135,21 +137,24 @@ Ewk_Context_Menu* ewk_context_menu_item_parent_menu_get(const Ewk_Context_Menu_I Eina_Bool ewk_context_menu_item_select(Ewk_Context_Menu* menu, Ewk_Context_Menu_Item* item) { - LOG_EWK_API_MOCKUP(); - return false; + EINA_SAFETY_ON_NULL_RETURN_VAL(menu, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(item, EINA_FALSE); + menu->MenuItemSelected(item); + return EINA_TRUE; } Eina_Bool ewk_context_menu_hide(Ewk_Context_Menu* menu) { - LOG_EWK_API_MOCKUP(); - return false; + EINA_SAFETY_ON_NULL_RETURN_VAL(menu, EINA_FALSE); + menu->HideContextMenu(); + return EINA_TRUE; } int ewk_context_menu_pos_x_get(Ewk_Context_Menu* menu) { #if BUILDFLAG(IS_TIZEN_TV) - LOG_EWK_API_MOCKUP(); - return 0; + EINA_SAFETY_ON_NULL_RETURN_VAL(menu, 0); + return menu->GetPosition().x(); #else LOG_EWK_API_MOCKUP("Only for Tizen TV."); return 0; @@ -159,8 +164,8 @@ int ewk_context_menu_pos_x_get(Ewk_Context_Menu* menu) int ewk_context_menu_pos_y_get(Ewk_Context_Menu* menu) { #if BUILDFLAG(IS_TIZEN_TV) - LOG_EWK_API_MOCKUP(); - return 0; + EINA_SAFETY_ON_NULL_RETURN_VAL(menu, 0); + return menu->GetPosition().y(); #else LOG_EWK_API_MOCKUP("Only for Tizen TV."); return 0; -- 2.7.4 From 6974036e9cc4f37c8ca9a795d6edc81a21c79301 Mon Sep 17 00:00:00 2001 From: Akshay Kanagali Date: Mon, 13 Mar 2023 08:29:17 -0700 Subject: [PATCH 14/16] [M120 Migration][NUI][Rendering] Support ecore_evas sw backend To support the SW backend, modified to perform GL related initialization operation only in the HW backend. It also resolves the build errors after TBM is enabled. References : https://review.tizen.org/gerrit/306447/ https://review.tizen.org/gerrit/295785/ Change-Id: I3f18a7a0f4f71654227dbad7a505154955da2694 Signed-off-by: Akshay Kanagali --- .../skia_output_surface_impl_on_gpu.cc | 2 +- .../skia_output_surface_impl_on_gpu.h | 2 +- content/browser/web_contents/web_contents_impl.cc | 11 +++- content/browser/web_contents/web_contents_impl.h | 3 ++ .../rwhv_aura_offscreen_helper_efl.cc | 63 ++++++++++++++-------- .../renderer_host/rwhv_aura_offscreen_helper_efl.h | 2 + 6 files changed, 57 insertions(+), 26 deletions(-) diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc index 81a6d79..5421423 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc @@ -2755,7 +2755,7 @@ void SkiaOutputSurfaceImplOnGpu::DestroySharedImage(gpu::Mailbox mailbox) { } #if BUILDFLAG(IS_EFL) -uint32_t SkiaOutputSurfaceImplOnGpu::GetTextureID() { +size_t SkiaOutputSurfaceImplOnGpu::GetTextureID() { if (output_device_) return output_device_->GetTextureID(); return 0; diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h index ac85ba3..d97a855 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h @@ -283,7 +283,7 @@ class SkiaOutputSurfaceImplOnGpu const gfx::ColorSpace& color_space); void DestroySharedImage(gpu::Mailbox mailbox); #if BUILDFLAG(IS_EFL) - uint32_t GetTextureID(); + size_t GetTextureID(); #endif // Called on the viz thread! diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 1863239..fc639cf 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -10676,9 +10676,16 @@ void WebContentsImpl::CreateEflMainLayout() { elm_layout_file_set(efl_main_layout_, main_edj.AsUTF8Unsafe().c_str(), "main_layout"); - GLSharedContextEfl::Initialize(root_window); - auto* ee = ecore_evas_ecore_evas_get(evas_object_evas_get(efl_main_layout_)); + const char* sw_engine = "wayland_shm"; + if (!strncmp(sw_engine, ecore_evas_engine_name_get(ee), strlen(sw_engine))) { + LOG(INFO) << "ecore_evsa engine Name : " << ecore_evas_engine_name_get(ee); + use_hw_backend_ = false; + } + if (use_hw_backend_) { + GLSharedContextEfl::Initialize(root_window); + } + ui::EflScreen::UpdateDisplayInfo(ee); } diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 475f3dd..3b10b27 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h @@ -238,6 +238,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents, Evas_Object* GetEflMainLayout() const { return efl_main_layout_; } void set_ewk_view(void* ewk_view) { ewk_view_ = ewk_view; } void* ewk_view() const { return ewk_view_; } + bool use_hw_backend() const { return use_hw_backend_; } void SetSpatialNavigationEnabled(bool enabled); void SetAtkEnabled(bool enabled); @@ -2479,6 +2480,8 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents, bool atk_enabled_ = false; bool spatial_navigation_enabled_ = false; + + bool use_hw_backend_ = true; #endif #if defined(TIZEN_VIDEO_HOLE) diff --git a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc index cfe14d5..37cd615 100644 --- a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc +++ b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc @@ -198,12 +198,19 @@ RWHVAuraOffscreenHelperEfl::~RWHVAuraOffscreenHelperEfl() { } void RWHVAuraOffscreenHelperEfl::Initialize() { - efl_main_layout_ = - static_cast(GetWebContents())->GetEflMainLayout(); + WebContentsImpl* wc = static_cast(GetWebContents()); + efl_main_layout_ = wc->GetEflMainLayout(); + use_hw_backend_ = wc->use_hw_backend(); evas_ = evas_object_evas_get(efl_main_layout_); - InitEvasGL(); - InitializeProgram(); + if (use_hw_backend_) { + InitEvasGL(); + InitializeProgram(); + } else { + LOG(INFO) << "use sw backend."; + CreateNativeSurface(); + } + evas_object_event_callback_add(efl_main_layout_, EVAS_CALLBACK_RESIZE, OnParentViewResize, this); evas_object_show(content_image_); @@ -248,10 +255,18 @@ void RWHVAuraOffscreenHelperEfl::OnParentViewResize(void* data, } bool RWHVAuraOffscreenHelperEfl::ClearCurrent() { + if (!use_hw_backend_) { + return true; + } + return evas_gl_make_current(evas_gl_, 0, 0); } bool RWHVAuraOffscreenHelperEfl::MakeCurrent() { + if (!use_hw_backend_) { + return true; + } + return evas_gl_make_current(evas_gl_, evas_gl_surface_, evas_gl_context_); } @@ -521,25 +536,29 @@ gfx::Size RWHVAuraOffscreenHelperEfl::CreateNativeSurface() { evas_object_geometry_set(content_image_, x, y, width, height); evas_object_geometry_set(content_image_elm_host_, x, y, width, height); - if (evas_gl_surface_) { - evas_object_image_native_surface_set(content_image_, NULL); - evas_gl_surface_destroy(evas_gl_, evas_gl_surface_); - ClearCurrent(); - } + if (use_hw_backend_) { + if (evas_gl_surface_) { + evas_object_image_native_surface_set(content_image_, NULL); + evas_gl_surface_destroy(evas_gl_, evas_gl_surface_); + ClearCurrent(); + } - evas_gl_surface_ = - evas_gl_surface_create(evas_gl_, evas_gl_config_, width, height); - if (!evas_gl_surface_) - LOG(FATAL) << "Failed to create evas gl surface"; - - Evas_Native_Surface nativeSurface; - if (evas_gl_native_surface_get(evas_gl_, evas_gl_surface_, &nativeSurface)) { - evas_object_image_native_surface_set(content_image_, &nativeSurface); - evas_object_image_pixels_get_callback_set( - content_image_, EvasObjectImagePixelsGetCallback, this); - evas_object_image_pixels_dirty_set(content_image_, true); - } else { - LOG(FATAL) << "Failed to get native surface"; + evas_gl_surface_ = + evas_gl_surface_create(evas_gl_, evas_gl_config_, width, height); + if (!evas_gl_surface_) { + LOG(FATAL) << "Failed to create evas gl surface"; + } + + Evas_Native_Surface nativeSurface; + if (evas_gl_native_surface_get(evas_gl_, evas_gl_surface_, + &nativeSurface)) { + evas_object_image_native_surface_set(content_image_, &nativeSurface); + evas_object_image_pixels_get_callback_set( + content_image_, EvasObjectImagePixelsGetCallback, this); + evas_object_image_pixels_dirty_set(content_image_, true); + } else { + LOG(FATAL) << "Failed to get native surface"; + } } return gfx::Size(width, height); diff --git a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.h b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.h index a7644fe..f9aa3ca 100644 --- a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.h +++ b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.h @@ -169,6 +169,8 @@ class CONTENT_EXPORT RWHVAuraOffscreenHelperEfl // we only care about the last one if they piled up - we can only display // one anyway. SnapshotTask magnifier_snapshot_request_; + + bool use_hw_backend_ = true; }; } // namespace content -- 2.7.4 From bb114c149627a79e20518a0721075a60df8ad726 Mon Sep 17 00:00:00 2001 From: fangfengrong Date: Tue, 2 Apr 2024 19:15:17 +0800 Subject: [PATCH 15/16] [M120 Migration] Support signal "tooltip,text,unset", "tooltip,text,set" When mouse move over some HTML element, we will notify WebBrowser about the tooltip information. When mouse move over HTML element, we will get related information form EventHandle. Extract the tooltip string. Send tooltip set notification when tooltip is not empty. Otherwise, send tooltip unset notification. Reference: https://review.tizen.org/gerrit/#/c/291995 Change-Id: I8d40ce93583036a05238b85d483dcc2d3fe045c9 Signed-off-by: fangfengrong --- .../browser/renderer_host/render_widget_host_view_aura.cc | 2 ++ content/public/browser/web_contents_delegate.h | 1 + third_party/blink/renderer/core/page/chrome_client_impl.cc | 6 ++++++ third_party/blink/renderer/core/page/chrome_client_impl.h | 1 + .../browser/renderer_host/rwhv_aura_common_helper_efl.cc | 5 +++++ .../browser/renderer_host/rwhv_aura_common_helper_efl.h | 1 + tizen_src/ewk/efl_integration/eweb_view.cc | 1 + tizen_src/ewk/efl_integration/eweb_view_callbacks.h | 2 +- tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc | 12 ++++++++++++ tizen_src/ewk/efl_integration/web_contents_delegate_efl.h | 2 ++ 10 files changed, 32 insertions(+), 1 deletion(-) diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index d8f0ffd..def9115 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -1074,6 +1074,8 @@ void RenderWidgetHostViewAura::Destroy() { void RenderWidgetHostViewAura::UpdateTooltipUnderCursor( const std::u16string& tooltip_text) { + if (efl_helper_) + efl_helper_->UpdateTooltipUnderCursor(tooltip_text); if (GetCursorManager()->IsViewUnderCursor(this)) UpdateTooltip(tooltip_text); } diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h index 57d3318..de949f9 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h @@ -412,6 +412,7 @@ class CONTENT_EXPORT WebContentsDelegate { virtual void MoveFocusToBrowser(int direction) {} virtual void ShowMicOpenedNotification(bool show) {} #endif + virtual void UpdateTooltipUnderCursor(const std::u16string& text) {} // Returns a pointer to a service to manage JavaScript dialogs. May return // nullptr in which case dialogs aren't shown. diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc index 2e1c196..ca16347 100644 --- a/third_party/blink/renderer/core/page/chrome_client_impl.cc +++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc @@ -657,6 +657,12 @@ void ChromeClientImpl::ShowMouseOverURL(const HitTestResult& result) { void ChromeClientImpl::UpdateTooltipUnderCursor(LocalFrame& frame, const String& tooltip_text, TextDirection dir) { + // Only set tool tip text if it has changed since the last time this function + // was called. + if (tooltip_text == cached_tooltip_text_) + return; + cached_tooltip_text_ = tooltip_text; + WebFrameWidgetImpl* widget = WebLocalFrameImpl::FromFrame(frame)->LocalRootFrameWidget(); if (!tooltip_text.empty()) { diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.h b/third_party/blink/renderer/core/page/chrome_client_impl.h index cd83178..f46329f 100644 --- a/third_party/blink/renderer/core/page/chrome_client_impl.h +++ b/third_party/blink/renderer/core/page/chrome_client_impl.h @@ -340,6 +340,7 @@ class CORE_EXPORT ChromeClientImpl final : public ChromeClient { bool did_request_non_empty_tool_tip_; absl::optional before_unload_confirm_panel_result_for_testing_; HeapHashSet> commit_observers_; + String cached_tooltip_text_; FRIEND_TEST_ALL_PREFIXES(FileChooserQueueTest, DerefQueuedChooser); }; diff --git a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc index b314e4f..f07a065 100644 --- a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc +++ b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.cc @@ -571,6 +571,11 @@ void RWHVAuraCommonHelperEfl::OnGetFocusedNodeBounds( web_contents_->GetDelegate()->OnDidChangeFocusedNodeBounds(rect); } +void RWHVAuraCommonHelperEfl::UpdateTooltipUnderCursor( + const std::u16string& text) { + web_contents_->GetDelegate()->UpdateTooltipUnderCursor(text); +} + void RWHVAuraCommonHelperEfl::BackgroundColorReceived( int callback_id, SkColor bg_color) { web_contents_->GetDelegate()->BackgroundColorReceived(callback_id, bg_color); diff --git a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h index c0cf7ae..55e9235 100644 --- a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h +++ b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_common_helper_efl.h @@ -181,6 +181,7 @@ class CONTENT_EXPORT RWHVAuraCommonHelperEfl { void OnGetMainFrameScrollbarVisible(int callback_id, bool visible); void TextInputStateChanged(const ui::mojom::TextInputState& params); void OnSelectionRectReceived(const gfx::Rect& selection_rect); + void UpdateTooltipUnderCursor(const std::u16string&); protected: void SetOffscreenMode() { is_offscreen_mode_ = true; } diff --git a/tizen_src/ewk/efl_integration/eweb_view.cc b/tizen_src/ewk/efl_integration/eweb_view.cc index 20fa95d..cd0e1b4 100644 --- a/tizen_src/ewk/efl_integration/eweb_view.cc +++ b/tizen_src/ewk/efl_integration/eweb_view.cc @@ -2705,6 +2705,7 @@ void EWebView::InvokeWebProcessCrashedCallback() { DCHECK_CURRENTLY_ON(BrowserThread::UI); const GURL last_url = GetURL(); bool callback_handled = false; + SmartCallback().call(); SmartCallback().call(&callback_handled); if (!callback_handled) LoadHTMLString(kRendererCrashedHTMLMessage, NULL, diff --git a/tizen_src/ewk/efl_integration/eweb_view_callbacks.h b/tizen_src/ewk/efl_integration/eweb_view_callbacks.h index 6830c60..623402b 100644 --- a/tizen_src/ewk/efl_integration/eweb_view_callbacks.h +++ b/tizen_src/ewk/efl_integration/eweb_view_callbacks.h @@ -248,7 +248,6 @@ DECLARE_EWK_VIEW_CALLBACK(FaviconChanged, "favicon,changed", void); DECLARE_EWK_VIEW_CALLBACK(ProvisionalLoadFailed, "load,provisional,failed", Ewk_Error*); DECLARE_EWK_VIEW_CALLBACK(NavigationPolicyDecision, "policy,decision,navigation", Ewk_Navigation_Policy_Decision*); DECLARE_EWK_VIEW_CALLBACK(TextFound, "text,found", unsigned*); -DECLARE_EWK_VIEW_CALLBACK(TooltipTextUnset, "tooltip,text,unset", void); DECLARE_EWK_VIEW_CALLBACK(Vibrate, "vibrate", uint32_t*); */ @@ -263,6 +262,7 @@ DECLARE_EWK_VIEW_CALLBACK(URLChanged, "url,changed", const char*); DECLARE_EWK_VIEW_CALLBACK(URIChanged, "uri,changed", const char*); DECLARE_EWK_VIEW_CALLBACK(LoadProgress, "load,progress", double*); DECLARE_EWK_VIEW_CALLBACK(TooltipTextSet, "tooltip,text,set", const char*); +DECLARE_EWK_VIEW_CALLBACK(TooltipTextUnset, "tooltip,text,unset", void); DECLARE_EWK_VIEW_CALLBACK(EnterFullscreen, "fullscreen,enterfullscreen", void); DECLARE_EWK_VIEW_CALLBACK(ExitFullscreen, "fullscreen,exitfullscreen", void); DECLARE_EWK_VIEW_CALLBACK(UserMediaPermission, "usermedia,permission,request", _Ewk_User_Media_Permission_Request*); diff --git a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc index 7eb7f0f..b2317f9 100644 --- a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc +++ b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc @@ -904,4 +904,16 @@ void WebContentsDelegateEfl::VideoPlayingStatusReceived(bool is_playing, LOG(INFO) << "web_view_ is null"; } #endif + +void WebContentsDelegateEfl::UpdateTooltipUnderCursor( + const std::u16string& text) { + std::string tooltip = base::UTF16ToUTF8(text); + LOG(INFO) << __func__ << " " << tooltip.c_str(); + if (tooltip.empty()) { + web_view_->SmartCallback().call(); + } else { + web_view_->SmartCallback().call( + tooltip.c_str()); + } +} } // namespace content diff --git a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h index 4e1b834..f1433cd 100644 --- a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h +++ b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h @@ -93,6 +93,8 @@ class WebContentsDelegateEfl : public WebContentsDelegate { const std::string& url) override; void WillDraw(int rotation, gfx::Size frame_data_output_size) override; #endif + void UpdateTooltipUnderCursor(const std::u16string& text) override; + void RequestCertificateConfirm( WebContents* web_contents, int cert_error, -- 2.7.4 From a7db805c05943d2c687896c63ca55e7c510133c9 Mon Sep 17 00:00:00 2001 From: fang fengrong Date: Tue, 2 Apr 2024 08:28:42 +0800 Subject: [PATCH 16/16] Fixup![M120 Migration][VD] Fix some focus issues for offscreen mode Keeps same with M94, register focusin/focusout for content_image_elm_host; when content_image_elm_host focusin/focusout, sync the focus to content_image. Change-Id: I4447858706b21a5721e166dcba68e4a746c40a69 Signed-off-by: fang fengrong --- .../browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc index 37cd615..c4368ce 100644 --- a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc +++ b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc @@ -235,6 +235,10 @@ void RWHVAuraOffscreenHelperEfl::AuraChildWindowAdded() { OnFocusIn, this); evas_object_event_callback_add(content_image_, EVAS_CALLBACK_FOCUS_OUT, OnFocusOut, this); + evas_object_smart_callback_add(content_image_elm_host_, "focused", + OnHostFocusIn, this); + evas_object_smart_callback_add(content_image_elm_host_, "unfocused", + OnHostFocusOut, this); } // static @@ -525,10 +529,6 @@ gfx::Size RWHVAuraOffscreenHelperEfl::CreateNativeSurface() { elm_object_part_content_set(content_image_elm_host_, "overlay", content_image_); elm_object_focus_allow_set(content_image_elm_host_, EINA_TRUE); - evas_object_smart_callback_add(content_image_elm_host_, "focused", - OnHostFocusIn, this); - evas_object_smart_callback_add(content_image_elm_host_, "unfocused", - OnHostFocusOut, this); evas_object_show(content_image_elm_host_); } -- 2.7.4