#include "base/time/time.h"
#include "cc/cc_export.h"
+#if defined(TIZEN_VIDEO_HOLE)
+#include "base/callback.h"
+
+namespace gfx {
+class Rect;
+}
+#endif
+
namespace media {
class VideoFrame;
}
namespace cc {
+#if defined(TIZEN_VIDEO_HOLE)
+using DrawableContentRectChangedCallback =
+ base::RepeatingCallback<void(gfx::Rect, bool)>;
+#endif
+
// VideoFrameProvider and VideoFrameProvider::Client define the relationship by
// which video frames are exchanged between a provider and client.
//
// the current frame if it's invald.
virtual void OnContextLost() = 0;
+#if defined(TIZEN_VIDEO_HOLE)
+ virtual void SetDrawableContentRectChangedCallback(
+ DrawableContentRectChangedCallback cb) = 0;
+
+ // Notifies the client of video plane geometry to be use.
+ virtual void OnDrawableContentRectChanged(const gfx::Rect&) = 0;
+#endif
+
protected:
virtual ~VideoFrameProvider() {}
};
needs_put_current_frame_ = false;
}
+#if defined(TIZEN_VIDEO_HOLE)
+void VideoFrameProviderClientImpl::OnDrawableContentRectChanged(
+ const gfx::Rect rect) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (provider_)
+ provider_->OnDrawableContentRectChanged(rect);
+}
+#endif
+
void VideoFrameProviderClientImpl::ReleaseLock() {
DCHECK(thread_checker_.CalledOnValidThread());
provider_lock_.Release();
void DidReceiveFrame() override;
bool IsDrivingFrameUpdates() const override;
+#if defined(TIZEN_VIDEO_HOLE)
+ void OnDrawableContentRectChanged(const gfx::Rect);
+#endif
+
const VideoFrameProvider* get_provider_for_testing() const {
return provider_;
}
visible_quad_rect, draw_properties().mask_filter_info,
clip_rect_opt, contents_opaque(), draw_opacity(),
GetSortingContextId());
+
+#if defined(TIZEN_VIDEO_HOLE)
+ const gfx::Rect video_rect =
+ cc::MathUtil::MapEnclosingClippedRect(transform, gfx::Rect(rotated_size));
+ if (previous_visible_rect_ != video_rect) {
+#if defined(USE_TTRACE)
+ TTRACE(TTRACE_TAG_WEB,
+ "VideoResourceUpdater::AppendQuads -> rect change start!");
+#endif
+ previous_visible_rect_ = video_rect;
+ provider_client_impl_->OnDrawableContentRectChanged(video_rect);
+ }
+#endif // defined(TIZEN_VIDEO_HOLE)
}
void VideoLayerImpl::DidDraw(viz::ClientResourceProvider* resource_provider) {
#if defined(TIZEN_TBM_SUPPORT)
#include "components/viz/common/gpu/context_provider.h"
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+#include "ui/gfx/geometry/rect.h"
+#endif
namespace media {
class VideoFrame;
const gpu::SyncToken& sync_token,
bool lost_resource);
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+ gfx::Rect previous_visible_rect_;
+#endif
scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl_;
owning_renderer_->MojoRendererSetCdm(cdm_id, std::move(callback));
}
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHole(bool is_video_hole) override {}
+ void SetMediaGeometry(const gfx::RectF& rect) override {}
+#endif
+
private:
PlaybackCommandForwardingRenderer* const owning_renderer_;
mojo::Receiver<media::mojom::Renderer> playback_controller_;
}
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+void RenderWidgetHostImpl::SetVideoHoleForRender(bool enable) {
+ blink_widget_->SetVideoHoleForRender(enable);
+}
+#endif
+
blink::VisualProperties RenderWidgetHostImpl::GetInitialVisualProperties() {
blink::VisualProperties initial_props = GetVisualProperties();
void PrintToPdf(int width, int height, const base::FilePath& filename);
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHoleForRender(bool enable);
+#endif
+
// Returns true if the RenderWidget is hidden.
bool is_hidden() const { return is_hidden_; }
const cc::LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner>
main_thread_compositor_task_runner,
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole,
+#endif
scoped_refptr<base::TaskRunner> compositor_worker_task_runner) {
blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
auto* delegate = GetWebMediaPlayerDelegate();
parent_frame_sink_id,
blink::WebSurfaceLayerBridge::ContainsVideo::kYes),
RenderThreadImpl::current()->SharedMainThreadContextProvider(),
+#if defined(TIZEN_VIDEO_HOLE)
+ is_video_hole,
+#endif
use_surface_layer,
render_frame_->GetRenderFrameMediaPlaybackOptions()
.is_background_suspend_enabled,
const cc::LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner>
main_thread_compositor_task_runner,
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole,
+#endif
scoped_refptr<base::TaskRunner> compositor_worker_task_runner);
// Provides an EncryptedMediaClient to connect blink's EME layer to media's
const blink::WebString& sink_id,
const cc::LayerTreeSettings& settings,
scoped_refptr<base::TaskRunner> compositor_worker_task_runner) {
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole = false;
+ if (frame_ && frame_->View())
+ is_video_hole = frame_->View()->IsVideoHoleForRender();
+#endif
+
return media_factory_.CreateMediaPlayer(
source, client, inspector_context, encrypted_client, initial_cdm, sink_id,
GetLocalRootWebFrameWidget()->GetFrameSinkId(), settings,
agent_scheduling_group_.agent_group_scheduler().CompositorTaskRunner(),
+#if defined(TIZEN_VIDEO_HOLE)
+ is_video_hole,
+#endif
std::move(compositor_worker_task_runner));
}
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/size.h"
+#if defined(TIZEN_VIDEO_HOLE)
+#include "ui/gfx/geometry/rect_f.h"
+#endif
+
namespace media {
class CdmContext;
using CdmAttachedCB = base::OnceCallback<void(bool)>;
virtual void SetCdm(CdmContext* cdm_context,
CdmAttachedCB cdm_attached_cb) = 0;
+
+#if defined(TIZEN_VIDEO_HOLE)
+ virtual void SetMediaGeometry(const gfx::RectF rect_f) = 0;
+#endif
};
} // namespace media
public:
RendererWrapper(scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole,
+#endif
MediaLog* media_log);
RendererWrapper(const RendererWrapper&) = delete;
PipelineStatistics GetStatistics() const;
void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb);
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetMediaGeometry(const gfx::RectF rect_f);
+#endif
+
// |enabled_track_ids| contains track ids of enabled audio tracks.
void OnEnabledAudioTracksChanged(
const std::vector<MediaTrack::Id>& enabled_track_ids,
// reset the pipeline state, and restore this to PIPELINE_OK.
PipelineStatus status_;
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole_;
+#endif
+
// Whether we've received the audio/video/text ended events.
bool renderer_ended_;
bool text_renderer_ended_;
PipelineImpl::RendererWrapper::RendererWrapper(
scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole,
+#endif
MediaLog* media_log)
: media_task_runner_(std::move(media_task_runner)),
main_task_runner_(std::move(main_task_runner)),
cdm_context_(nullptr),
state_(kCreated),
status_(PIPELINE_OK),
+#if defined(TIZEN_VIDEO_HOLE)
+ is_video_hole_(is_video_hole),
+#endif
renderer_ended_(false),
text_renderer_ended_(false) {}
CreateRendererInternal(std::move(create_renderer_done_cb_));
}
+#if defined(TIZEN_VIDEO_HOLE)
+void PipelineImpl::RendererWrapper::SetMediaGeometry(const gfx::RectF rect_f) {
+ LOG(INFO) << __func__;
+ if (shared_state_.renderer)
+ shared_state_.renderer->SetMediaGeometry(rect_f);
+}
+#endif
+
void PipelineImpl::RendererWrapper::CreateRendererInternal(
PipelineStatusCallback done_cb) {
DVLOG(1) << __func__;
was_played_with_user_activation_);
shared_state_.renderer->Initialize(demuxer_, this, std::move(done_cb));
+
+#if defined(TIZEN_VIDEO_HOLE)
+ LOG(INFO) << __func__ << " call SetVideoHole : " << is_video_hole_;
+ shared_state_.renderer->SetVideoHole(is_video_hole_);
+#endif
}
void PipelineImpl::RendererWrapper::DestroyRenderer() {
scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
CreateRendererCB create_renderer_cb,
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole,
+#endif
MediaLog* media_log)
: media_task_runner_(media_task_runner),
create_renderer_cb_(create_renderer_cb),
DCHECK(create_renderer_cb_);
renderer_wrapper_ = std::make_unique<RendererWrapper>(
- media_task_runner_, std::move(main_task_runner), media_log_);
+ media_task_runner_, std::move(main_task_runner),
+#if defined(TIZEN_VIDEO_HOLE)
+ is_video_hole,
+#endif
+ media_log_);
}
PipelineImpl::~PipelineImpl() {
BindToCurrentLoop(std::move(cdm_attached_cb))));
}
+#if defined(TIZEN_VIDEO_HOLE)
+void PipelineImpl::SetMediaGeometry(const gfx::RectF rect_f) {
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&RendererWrapper::SetMediaGeometry,
+ base::Unretained(renderer_wrapper_.get()), rect_f));
+}
+#endif
+
#define RETURN_STRING(state) \
case state: \
return #state;
PipelineImpl(scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
CreateRendererCB create_renderer_cb,
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole,
+#endif
MediaLog* media_log);
PipelineImpl(const PipelineImpl&) = delete;
PipelineStatistics GetStatistics() const override;
void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) override;
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetMediaGeometry(const gfx::RectF rect_f) override;
+#endif
+
// |enabled_track_ids| contains track ids of enabled audio tracks.
void OnEnabledAudioTracksChanged(
const std::vector<MediaTrack::Id>& enabled_track_ids,
#include "media/base/pipeline_status.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#if defined(TIZEN_VIDEO_HOLE)
+#include "ui/gfx/geometry/rect_f.h"
+#endif
+
namespace media {
class CdmContext;
// Discards any buffered data, executing |flush_cb| when completed.
virtual void Flush(base::OnceClosure flush_cb) = 0;
+#if defined(TIZEN_VIDEO_HOLE)
+ virtual void SetVideoHole(bool is_video_hole) {}
+ virtual void SetMediaGeometry(const gfx::RectF& rect) {}
+#endif
+
// Starts rendering from |time|.
virtual void StartPlayingFrom(base::TimeDelta time) = 0;
#if defined(TIZEN_TBM_SUPPORT)
case VideoFrame::STORAGE_TBM_SURFACE:
return "TBM_SURFACE";
+#endif
+#if defined(TIZEN_VIDEO_HOLE)
+ case VideoFrame::STORAGE_HOLE:
+ return "HOLE";
#endif
case VideoFrame::STORAGE_GPU_MEMORY_BUFFER:
return "GPU_MEMORY_BUFFER";
return frame;
}
+#if defined(TIZEN_VIDEO_HOLE)
+// This block and other blocks wrapped around #if defined(TIZEN_VIDEO_HOLE) is
+// not maintained by the general compositor team. Please contact
+// wonsik@chromium.org .
+
+// static
+scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame(
+ const gfx::Size& natural_size) {
+ auto layout = VideoFrameLayout::Create(PIXEL_FORMAT_UNKNOWN, natural_size);
+ scoped_refptr<VideoFrame> frame =
+ new VideoFrame(*layout, StorageType::STORAGE_HOLE,
+ gfx::Rect(natural_size), natural_size, base::TimeDelta());
+ return frame;
+}
+#endif // defined(TIZEN_VIDEO_HOLE)
+
// static
size_t VideoFrame::NumPlanes(VideoPixelFormat format) {
return VideoFrameLayout::NumPlanes(format);
// STORAGE_UNOWNED_MEMORY) and handle it appropriately in all cases.
STORAGE_DMABUFS = 5, // Each plane is stored into a DmaBuf.
#endif
- STORAGE_GPU_MEMORY_BUFFER = 6,
#if defined(TIZEN_TBM_SUPPORT)
- STORAGE_TBM_SURFACE = 7,
- STORAGE_MAX = STORAGE_TBM_SURFACE,
-#else
- STORAGE_MAX = STORAGE_GPU_MEMORY_BUFFER,
+ STORAGE_TBM_SURFACE = 6,
+#endif
+#if defined(TIZEN_VIDEO_HOLE)
+ // Indicates protected media that needs to be directly rendered to hw. It
+ // is, in principle, platform independent, see http://crbug.com/323157 and
+ // https://groups.google.com/a/google.com/d/topic/chrome-gpu/eIM1RwarUmk/discussion
+ STORAGE_HOLE = 7,
#endif
+ STORAGE_GPU_MEMORY_BUFFER = 8,
+ STORAGE_MAX = STORAGE_GPU_MEMORY_BUFFER,
};
// CB to be called on the mailbox backing this frame and its GpuMemoryBuffers
static scoped_refptr<VideoFrame> CreateTransparentFrame(
const gfx::Size& size);
+#if defined(TIZEN_VIDEO_HOLE)
+ // Allocates a hole frame.
+ static scoped_refptr<VideoFrame> CreateHoleFrame(const gfx::Size& size);
+#endif
+
static size_t NumPlanes(VideoPixelFormat format);
// Returns the required allocation size for a (tightly packed) frame of the
OnTrackChangeComplete();
}
+#if defined(TIZEN_VIDEO_HOLE)
+void PipelineController::SetMediaGeometry(gfx::RectF rect_f) {
+ pipeline_->SetMediaGeometry(rect_f);
+}
+#endif
+
void PipelineController::OnTrackChangeComplete() {
DCHECK(thread_checker_.CalledOnValidThread());
// OnceCallback, and doesn't play nicely with gmock.
void FireOnTrackChangeCompleteForTesting(State set_to);
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetMediaGeometry(gfx::RectF rect_f);
+#endif
+
private:
// Attempts to make progress from the current state to the target state.
void Dispatch();
return media_time_interpolator_.GetInterpolatedTime();
}
+#if defined(TIZEN_VIDEO_HOLE)
+void MojoRenderer::SetVideoHole(bool is_video_hole) {
+ if (remote_renderer_.is_bound())
+ remote_renderer_->SetVideoHole(is_video_hole);
+}
+
+void MojoRenderer::SetMediaGeometry(const gfx::RectF& rect) {
+ if (remote_renderer_.is_bound())
+ remote_renderer_->SetMediaGeometry(rect);
+}
+#endif
+
void MojoRenderer::OnTimeUpdate(base::TimeDelta time,
base::TimeDelta max_time,
base::TimeTicks capture_time) {
void SetVolume(float volume) override;
base::TimeDelta GetMediaTime() override;
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHole(bool is_video_hole) override;
+ void SetMediaGeometry(const gfx::RectF& rect) override;
+#endif
+
private:
// mojom::RendererClient implementation, dispatched on the |task_runner_|.
void OnTimeUpdate(base::TimeDelta time,
mojo_renderer_->SetLatencyHint(latency_hint);
}
+#if defined(TIZEN_VIDEO_HOLE)
+void MojoRendererWrapper::SetVideoHole(bool is_video_hole) {
+ mojo_renderer_->SetVideoHole(is_video_hole);
+}
+
+void MojoRendererWrapper::SetMediaGeometry(const gfx::RectF& rect) {
+ mojo_renderer_->SetMediaGeometry(rect);
+}
+#endif
+
base::TimeDelta MojoRendererWrapper::GetMediaTime() {
return mojo_renderer_->GetMediaTime();
}
void StartPlayingFrom(base::TimeDelta time) override;
void SetPlaybackRate(double playback_rate) override;
void SetVolume(float volume) override;
+
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHole(bool is_video_hole) override;
+ void SetMediaGeometry(const gfx::RectF& rect) override;
+#endif
+
base::TimeDelta GetMediaTime() override;
private:
enabled_features += [ "tizen_multimedia" ]
}
+ if (tizen_video_hole) {
+ enabled_features += [ "tizen_video_hole" ]
+ }
+
shared_typemaps = [
{
types = [
// Attaches the CDM associated with `cdm_id` to the renderer service,
// executing the callback with whether the CDM was successfully attached.
SetCdm(mojo_base.mojom.UnguessableToken? cdm_id) => (bool success);
+
+ [EnableIf=tizen_video_hole]
+ SetVideoHole(bool is_video_hole);
+
+ [EnableIf=tizen_video_hole]
+ SetMediaGeometry(gfx.mojom.RectF rect);
};
// A Mojo equivalent of media::RendererClient. See media/mojo/README.md
weak_this_, std::move(callback)));
}
+#if defined(TIZEN_VIDEO_HOLE)
+void MojoRendererService::SetVideoHole(bool is_video_hole) {
+ renderer_->SetVideoHole(is_video_hole);
+}
+
+void MojoRendererService::SetMediaGeometry(const gfx::RectF& rect) {
+ renderer_->SetMediaGeometry(rect);
+}
+#endif
+
void MojoRendererService::OnError(PipelineStatus error) {
DVLOG(1) << __func__ << "(" << error << ")";
state_ = STATE_ERROR;
void SetCdm(const absl::optional<base::UnguessableToken>& cdm_id,
SetCdmCallback callback) final;
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHole(bool is_video_hole) final;
+ void SetMediaGeometry(const gfx::RectF& rect) final;
+#endif
+
private:
enum State {
STATE_UNINITIALIZED,
#include "ui/gl/gl_enums.h"
#include "ui/gl/trace_util.h"
+#if defined(TIZEN_VIDEO_HOLE)
+#include "components/viz/common/quads/solid_color_draw_quad.h"
+#endif
+
namespace media {
namespace {
break;
}
+#if defined(TIZEN_VIDEO_HOLE)
+ case VideoFrameResourceType::HOLE: {
+ DCHECK_EQ(frame_resources_.size(), 0u);
+ auto* solid_color_draw_quad =
+ render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
+
+ // Create a solid color quad with transparent black and force no
+ // blending / no anti-aliasing.
+ solid_color_draw_quad->SetAll(shared_quad_state, quad_rect,
+ visible_quad_rect, false,
+ SkColors::kTransparent, true);
+ break;
+ }
+#endif
case VideoFrameResourceType::NONE:
NOTIMPLEMENTED();
break;
VideoFrameExternalResources
VideoResourceUpdater::CreateExternalResourcesFromVideoFrame(
scoped_refptr<VideoFrame> video_frame) {
+#if defined(TIZEN_VIDEO_HOLE)
+ if (video_frame->storage_type() == media::VideoFrame::STORAGE_HOLE) {
+ VideoFrameExternalResources external_resources;
+ external_resources.type = VideoFrameResourceType::HOLE;
+ return external_resources;
+ }
+#endif
+
if (video_frame->format() == PIXEL_FORMAT_UNKNOWN)
return VideoFrameExternalResources();
DCHECK(video_frame->HasTextures() || video_frame->IsMappable());
RGB,
RGBA_PREMULTIPLIED,
RGBA,
+#if defined(TIZEN_VIDEO_HOLE)
+ // TODO(danakj): Implement this with a solid color layer instead of a video
+ // frame and video layer.
+ HOLE,
+#endif
STREAM_TEXTURE,
// The VideoFrame is merely a hint to compositor that a hole must be made
// transparent so the video underlay will be visible.
out->cookie_enabled = data.cookie_enabled();
out->accelerated_video_decode_enabled =
data.accelerated_video_decode_enabled();
+#if defined(TIZEN_VIDEO_HOLE)
+ out->video_hole_enabled = data.video_hole_enabled();
+#endif
out->user_gesture_required_for_presentation =
data.user_gesture_required_for_presentation();
out->text_tracks_enabled = data.text_tracks_enabled();
// Defaults to false.
bool accelerated_video_decode_enabled;
+#if defined(TIZEN_VIDEO_HOLE)
+ bool video_hole_enabled = false;
+#endif
+
blink::mojom::ImageAnimationPolicy animation_policy =
blink::mojom::ImageAnimationPolicy::kImageAnimationPolicyAllowed;
return r.accelerated_video_decode_enabled;
}
+#if defined(TIZEN_VIDEO_HOLE)
+ static bool video_hole_enabled(const blink::web_pref::WebPreferences& r) {
+ return r.video_hole_enabled;
+ }
+#endif
+
static blink::mojom::ImageAnimationPolicy animation_policy(
const blink::web_pref::WebPreferences& r) {
return r.animation_policy;
if (use_efl) {
enabled_features += [ "is_efl" ]
}
+ if (tizen_video_hole) {
+ enabled_features += [ "tizen_video_hole" ]
+ }
shared_cpp_typemaps = [
{
// Defaults to false.
bool accelerated_video_decode_enabled;
+ [EnableIf=tizen_video_hole]
+ bool video_hole_enabled;
+
ImageAnimationPolicy animation_policy;
bool user_gesture_required_for_presentation;
[EnableIf=is_efl]
PrintToPdf(uint32 width, uint32 height, mojo_base.mojom.FilePath filename);
+ [EnableIf=tizen_video_hole]
+ SetVideoHoleForRender(bool enable);
+
// Informs the widget that it was hidden. This allows it to reduce its
// resource utilization, and will cancel any pending
// RecordContentToVisibleTimeRequest that was set with WasShown or
submitter_ = std::move(submitter);
}
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetDrawableContentRectChangedCallback(
+ cc::DrawableContentRectChangedCallback cb) override;
+ void OnDrawableContentRectChanged(const gfx::Rect&) override;
+#endif
+
private:
// TracingCategory name for |auto_open_close_|.
static constexpr const char kTracingCategory[] = "media,rail";
// Can only be called from the compositor thread.
base::TimeDelta GetLastIntervalWithoutLock();
+#if defined(TIZEN_VIDEO_HOLE)
+ cc::DrawableContentRectChangedCallback drawable_content_rect_changed_cb_;
+#endif
+
// This will run tasks on the compositor thread. If
// kEnableSurfaceLayerForVideo is enabled, it will instead run tasks on the
// media thread.
mojo::PendingRemote<media::mojom::MediaMetricsProvider> metrics_provider,
CreateSurfaceLayerBridgeCB create_bridge_callback,
scoped_refptr<viz::RasterContextProvider> raster_context_provider,
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole,
+#endif
bool use_surface_layer_for_video,
bool is_background_suspend_enabled,
bool is_background_video_playback_enabled,
virtual void SetAccessibilityEnabled(bool) = 0;
virtual bool GetAccessibilityEnabled() = 0;
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+ virtual void SetVideoHoleEnabled(bool) = 0;
+#endif
protected:
~WebSettings() = default;
// Returns whether this WebView represents a fenced frame root or not.
virtual bool IsFencedFrameRoot() const = 0;
+#if defined(TIZEN_VIDEO_HOLE)
+ // Video hole support ---------------------------------------------------
+ virtual void SetVideoHoleForRender(bool enable) = 0;
+ virtual bool IsVideoHoleForRender() const = 0;
+ virtual void SetVideoHoleDisabledForOES(bool enabled) = 0;
+#endif
+
// Misc -------------------------------------------------------------
// Returns the number of live WebView instances in this process.
}
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+void WebSettingsImpl::SetVideoHoleEnabled(bool enabled) {
+ settings_->SetVideoHoleEnabled(enabled);
+}
+#endif
} // namespace blink
void SetAccessibilityEnabled(bool) override;
bool GetAccessibilityEnabled() override;
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHoleEnabled(bool) override;
+#endif
bool RenderVSyncNotificationEnabled() const {
return render_v_sync_notification_enabled_;
settings->SetTouchDragEndContextMenu(prefs.touch_dragend_context_menu);
settings->SetWebXRImmersiveArAllowed(prefs.webxr_immersive_ar_allowed);
+#if defined(TIZEN_VIDEO_HOLE)
+ settings->SetVideoHoleEnabled(prefs.video_hole_enabled);
+#endif
+
#if BUILDFLAG(IS_MAC)
web_view_impl->SetMaximumLegibleScale(
prefs.default_maximum_page_scale_factor);
}
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+void WebViewImpl::SetVideoHoleForRender(bool enable) {
+ web_pref::WebPreferences pref = GetWebPreferences();
+ pref.video_hole_enabled = enable;
+ SetWebPreferences(pref);
+}
+
+bool WebViewImpl::IsVideoHoleForRender() const {
+ return GetPage()->GetSettings().GetVideoHoleEnabled() &&
+ !is_videoHole_disabled_for_oes_;
+}
+
+void WebViewImpl::SetVideoHoleDisabledForOES(bool disabled) {
+ is_videoHole_disabled_for_oes_ = disabled;
+}
+#endif
} // namespace blink
gfx::Vector2dF ElasticOverscroll() const { return elastic_overscroll_; }
- class ChromeClient& GetChromeClient() const {
- return *chrome_client_.Get();
- }
+ class ChromeClient& GetChromeClient() const { return *chrome_client_.Get(); }
// Allows main frame updates to occur if they were previously blocked. They
// are blocked during loading a navigation, to allow Blink to proceed without
// words, after the frame has painted something.
void DidFirstVisuallyNonEmptyPaint();
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHoleForRender(bool enable) override;
+ bool IsVideoHoleForRender() const override;
+ void SetVideoHoleDisabledForOES(bool disabled) override;
+#endif
+
private:
FRIEND_TEST_ALL_PREFIXES(WebFrameTest, DivScrollIntoEditableTest);
FRIEND_TEST_ALL_PREFIXES(WebFrameTest,
gfx::Vector2dF elastic_overscroll_;
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_videoHole_disabled_for_oes_;
+#endif
+
// If true, we send IPC messages when |preferred_size_| changes.
bool send_preferred_size_changes_ = false;
initial: true,
type: "bool",
},
+ {
+ name: "videoHoleEnabled",
+ initial: false,
+ type: "bool"
+ },
],
}
}
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+void WebFrameWidgetImpl::SetVideoHoleForRender(bool enable) {
+ WebView* view = View();
+ if (view)
+ view->SetVideoHoleForRender(enable);
+}
+#endif
+
void WebFrameWidgetImpl::OrientationChanged() {
local_root_->SendOrientationChangeEvent();
}
uint32_t height,
const base::FilePath& filename) override;
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHoleForRender(bool enable) override;
+#endif
+
void OrientationChanged() override;
void DidUpdateSurfaceAndScreen(
const display::ScreenInfos& previous_original_screen_infos) override;
virtual void PasswordFieldReset(HTMLInputElement& element) {}
+#if defined(TIZEN_VIDEO_HOLE)
+ virtual void SetVideoHoleDisabledForOES(bool disabled) const {}
+#endif
+
protected:
ChromeClient() = default;
class WebMediaPlayerMS;
struct WebMediaPlayerMSCompositorTraits;
+#if defined(TIZEN_VIDEO_HOLE)
+using DrawableContentRectChangedCallback =
+ base::RepeatingCallback<void(gfx::Rect, bool)>;
+using VideoVisibilityChangedCallback = base::RepeatingCallback<void(bool)>;
+#endif
+
// This class is designed to handle the work load on compositor thread for
// WebMediaPlayerMS. It will be instantiated on the main thread, but destroyed
// on the thread holding the last reference.
// Gets metadata which is available after kReadyStateHaveMetadata state.
Metadata GetMetadata();
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetDrawableContentRectChangedCallback(
+ DrawableContentRectChangedCallback cb) override {}
+
+ // Notifies the client of video plane geometry to be use.
+ void OnDrawableContentRectChanged(const gfx::Rect&) override {}
+#endif
+
private:
friend class WTF::ThreadSafeRefCounted<WebMediaPlayerMSCompositor,
WebMediaPlayerMSCompositorTraits>;
SetCurrentFrame_Locked(std::move(black_frame), tick_clock_->NowTicks());
}
+#if defined(TIZEN_VIDEO_HOLE)
+void VideoFrameCompositor::SetDrawableContentRectChangedCallback(
+ cc::DrawableContentRectChangedCallback cb) {
+ drawable_content_rect_changed_cb_ = std::move(cb);
+}
+
+void VideoFrameCompositor::OnDrawableContentRectChanged(const gfx::Rect& rect) {
+ if (!drawable_content_rect_changed_cb_.is_null())
+ drawable_content_rect_changed_cb_.Run(rect, true);
+}
+#endif
+
} // namespace blink
mojo::PendingRemote<media::mojom::MediaMetricsProvider> metrics_provider,
CreateSurfaceLayerBridgeCB create_bridge_callback,
scoped_refptr<viz::RasterContextProvider> raster_context_provider,
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole,
+#endif
bool use_surface_layer,
bool is_background_suspend_enabled,
bool is_background_video_playback_enabled,
std::move(request_routing_token_cb), std::move(media_observer),
enable_instant_source_buffer_gc, embedded_media_experience_enabled,
std::move(metrics_provider), std::move(create_bridge_callback),
- std::move(raster_context_provider), use_surface_layer,
+ std::move(raster_context_provider),
+#if defined(TIZEN_VIDEO_HOLE)
+ is_video_hole,
+#endif
+ use_surface_layer,
is_background_suspend_enabled, is_background_video_playback_enabled,
is_background_video_track_optimization_supported,
std::move(demuxer_override), std::move(remote_interfaces));
#include "media/base/android/media_codec_util.h"
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+// NSW : Is this necessary?
+namespace {
+const base::TimeDelta kLayerBoundUpdateInterval = base::Milliseconds(50);
+} // namespace
+#endif
+
namespace blink {
namespace {
mojo::PendingRemote<media::mojom::MediaMetricsProvider> metrics_provider,
CreateSurfaceLayerBridgeCB create_bridge_callback,
scoped_refptr<viz::RasterContextProvider> raster_context_provider,
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole,
+#endif
bool use_surface_layer,
bool is_background_suspend_enabled,
bool is_background_video_playback_enabled,
base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
base::Unretained(this))),
will_play_helper_(nullptr),
+#if defined(TIZEN_VIDEO_HOLE)
+ is_video_hole_(is_video_hole),
+#endif
demuxer_override_(std::move(demuxer_override)) {
DVLOG(1) << __func__;
DCHECK(adjust_allocated_memory_cb_);
media_task_runner_, main_task_runner_,
base::BindRepeating(&WebMediaPlayerImpl::CreateRenderer,
base::Unretained(this)),
+#if defined(TIZEN_VIDEO_HOLE)
+ is_video_hole_,
+#endif
media_log_.get());
pipeline_controller_ = std::make_unique<media::PipelineController>(
// it's not interested in recording these events.
playback_events_recorder_.reset_on_disconnect();
+#if defined(TIZEN_VIDEO_HOLE)
+ if (is_video_hole_) {
+ vfc_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &VideoFrameCompositor::SetDrawableContentRectChangedCallback,
+ base::Unretained(compositor_.get()),
+ media::BindToCurrentLoop(base::BindRepeating(
+ &WebMediaPlayerImpl::OnDrawableContentRectChanged,
+ weak_this_))));
+ }
+#endif
#if BUILDFLAG(IS_ANDROID)
renderer_factory_selector_->SetRemotePlayStateChangeCB(
media::BindToCurrentLoop(base::BindRepeating(
RecordVideoNaturalSize(rotated_size);
+#if defined(TIZEN_VIDEO_HOLE)
+ if (ShouldUseVideoHole()) {
+ CreateVideoHoleFrame();
+ StartLayerBoundUpdateTimer();
+ }
+#endif
+
gfx::Size old_size = pipeline_metadata_.natural_size;
if (rotated_size == old_size)
return;
DCHECK(main_task_runner_->BelongsToCurrentThread());
DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
+#if defined(TIZEN_VIDEO_HOLE)
+ if (ShouldUseVideoHole()) {
+ CreateVideoHoleFrame();
+ StartLayerBoundUpdateTimer();
+ }
+#endif
+
const bool codec_change =
pipeline_metadata_.video_decoder_config.codec() != config.codec();
const bool codec_profile_change =
media_metrics_provider_->SetRendererType(renderer_type_);
media_log_->SetProperty<MediaLogProperty::kRendererName>(renderer_type_);
+#if defined(TIZEN_VIDEO_HOLE)
+ if (ShouldUseVideoHole())
+ StartLayerBoundUpdateTimer();
+#endif
+
return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer(
media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
compositor_.get(), std::move(request_overlay_info_cb),
return true;
}
+#if defined(TIZEN_VIDEO_HOLE)
+bool WebMediaPlayerImpl::ShouldUseVideoHole() const {
+ if (HasVideo() && is_video_hole_)
+ return true;
+ return false;
+}
+
+void WebMediaPlayerImpl::CreateVideoHoleFrame() {
+ gfx::Size size(pipeline_metadata_.natural_size.width(),
+ pipeline_metadata_.natural_size.height());
+
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::CreateHoleFrame(size);
+ if (video_frame)
+ compositor_->PaintSingleFrame(video_frame);
+}
+
+void WebMediaPlayerImpl::OnDrawableContentRectChanged(gfx::Rect rect,
+ bool is_video) {
+ gfx::RectF rect_f = static_cast<gfx::RectF>(rect);
+ LOG(INFO) << __func__ << " : " << rect_f.ToString();
+ if (rect_f != last_computed_rect_)
+ pipeline_controller_->SetMediaGeometry(rect_f);
+
+ last_computed_rect_ = rect_f;
+}
+
+bool WebMediaPlayerImpl::UpdateBoundaryRectangle() {
+ if (!video_layer_)
+ return false;
+
+ // Compute the geometry of video frame layer.
+ cc::Layer* layer = video_layer_.get();
+ if (!layer->layer_tree_host())
+ return false;
+
+ gfx::Rect layer_screen_space_rect = cc::MathUtil::MapEnclosingClippedRect(
+ layer->ScreenSpaceTransform(), gfx::Rect(layer->bounds()));
+ gfx::RectF rect = gfx::RectF(layer_screen_space_rect);
+ // Return false when the geometry hasn't been changed from the last time.
+ // if (last_computed_rect_ == rect)
+ // return false;
+
+ // Store the changed geometry information when it is actually changed.
+ last_computed_rect_ = rect;
+ return true;
+}
+
+void WebMediaPlayerImpl::StartLayerBoundUpdateTimer() {
+ if (layer_bound_update_timer_.IsRunning())
+ return;
+
+ LOG(INFO) << __func__;
+ layer_bound_update_timer_.Start(
+ FROM_HERE, kLayerBoundUpdateInterval, this,
+ &WebMediaPlayerImpl::OnLayerBoundUpdateTimerFired);
+}
+
+void WebMediaPlayerImpl::StopLayerBoundUpdateTimer() {
+ if (layer_bound_update_timer_.IsRunning())
+ layer_bound_update_timer_.Stop();
+}
+
+void WebMediaPlayerImpl::OnLayerBoundUpdateTimerFired() {
+ LOG(INFO) << __func__;
+ if (UpdateBoundaryRectangle())
+ pipeline_controller_->SetMediaGeometry(last_computed_rect_);
+ StopLayerBoundUpdateTimer();
+}
+#endif
} // namespace blink
mojo::PendingRemote<media::mojom::MediaMetricsProvider> metrics_provider,
CreateSurfaceLayerBridgeCB create_bridge_callback,
scoped_refptr<viz::RasterContextProvider> raster_context_provider,
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole,
+#endif
bool use_surface_layer,
bool is_background_suspend_enabled,
bool is_background_video_play_enabled,
// Returns true if the video frame from this player are being captured.
bool IsVideoBeingCaptured() const;
+#if defined(TIZEN_VIDEO_HOLE)
+ bool ShouldUseVideoHole() const;
+ void CreateVideoHoleFrame();
+ void OnDrawableContentRectChanged(gfx::Rect rect, bool is_video);
+ bool UpdateBoundaryRectangle();
+ void StartLayerBoundUpdateTimer();
+ void StopLayerBoundUpdateTimer();
+ void OnLayerBoundUpdateTimerFired();
+#endif
+
// Report UMAs when this object instance is destroyed.
void ReportSessionUMAs() const;
LearningExperimentHelper will_play_helper_;
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole_;
+ gfx::RectF last_computed_rect_;
+ base::RepeatingTimer layer_bound_update_timer_;
+#endif
+
// Stores the optional override Demuxer until it is used in DoLoad().
std::unique_ptr<media::Demuxer> demuxer_override_;
}
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+void WidgetBase::SetVideoHoleForRender(bool enable) {
+ client_->SetVideoHoleForRender(enable);
+}
+#endif
+
void WidgetBase::WasHidden() {
// A provisional frame widget will never be hidden since that would require it
// to be shown first. A frame must be attached to the frame tree before
void PrintToPdf(uint32_t width,
uint32_t height,
const base::FilePath& filename) override;
+#endif
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHoleForRender(bool enable) override;
#endif
void WasHidden() override;
void WasShown(bool was_evicted,
uint32_t height,
const base::FilePath& filename) {}
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+ virtual void SetVideoHoleForRender(bool enable) {}
+#endif
// Convert screen coordinates to device emulated coordinates (scaled
// coordinates when devtools is used). This occurs for popups where their
if (tizen_web_speech_recognition) {
defines += [ "TIZEN_WEB_SPEECH_RECOGNITION" ]
}
+ if (tizen_video_hole) {
+ defines += [ "TIZEN_VIDEO_HOLE" ]
+ }
# TODO: There are X11 dependencies in following condition.
# The files need to be implemented based on Wayland.
tizen_multimedia_support = false
tizen_multimedia = false
tizen_tbm_support = false
+ tizen_video_hole = false
tizen_audio_io = false
tizen_web_speech_recognition = false
tizen_audio_io=true
tizen_web_speech_recognition=true
tizen_tbm_support=true
+ tizen_video_hole=true
"
}
#include "tizen_src/chromium_impl/media/filters/media_player_registry.h"
#include "tizen_src/chromium_impl/media/filters/media_player_tizen.h"
+#if defined(TIZEN_VIDEO_HOLE)
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
+#endif
+
#if defined(TIZEN_TBM_SUPPORT)
namespace media {
void DestroyMediaPacket(void* media_packet, int player_id) {
}
} // namespace media
#endif
+
namespace content {
class TizenRendererImpl::RendererClientInternal final
render_process_id_(process_id),
routing_id_(routing_id),
volume_(kDefaultVolume),
+#if defined(TIZEN_VIDEO_HOLE)
+ web_contents_(web_contents),
+#endif
renderer_extension_receiver_(this,
std::move(renderer_extension_receiver)) {
DCHECK_EQ(WebContents::FromRenderFrameHost(
GetPlayer()->Seek(time);
}
+#if defined(TIZEN_VIDEO_HOLE)
+void TizenRendererImpl::SetVideoHole(bool is_video_hole) {
+ if (is_video_hole_ == is_video_hole)
+ return;
+
+ is_video_hole_ = is_video_hole;
+ SetPlayerVideoHole();
+}
+
+void TizenRendererImpl::SetPlayerVideoHole() {
+ if (GetPlayer())
+ GetPlayer()->SetVideoHole(is_video_hole_);
+}
+
+void TizenRendererImpl::SetMediaGeometry(const gfx::RectF& rect) {
+ if (video_rect_ == rect)
+ return;
+
+ video_rect_ = rect;
+ SetPlayerMediaGeometry();
+}
+
+void TizenRendererImpl::SetPlayerMediaGeometry() {
+ if (GetPlayer())
+ GetPlayer()->SetMediaGeometry(GetViewportRect(), video_rect_);
+}
+
+gfx::Rect TizenRendererImpl::GetViewportRect() const {
+ if (!web_contents_)
+ return gfx::Rect();
+
+ if (RenderWidgetHostViewAura* rwhv = static_cast<RenderWidgetHostViewAura*>(
+ web_contents_->GetRenderWidgetHostView())) {
+ if (rwhv->offscreen_helper()) {
+ // offscreen rendering mode
+ return rwhv->offscreen_helper()->GetViewBoundsInPix();
+ } else {
+ // onscreen rendering mode
+ return rwhv->window()->bounds();
+ }
+ }
+ return gfx::Rect();
+}
+#endif
+
void TizenRendererImpl::StartPlayingFrom(base::TimeDelta time) {
LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
<< " time : " << time.InMicroseconds();
time.InMicroseconds());
if (!GetPlayer()->IsInitialized())
- GetPlayer()->Initialize(sink_);
+#if defined(TIZEN_VIDEO_HOLE)
+ if (is_video_hole_) {
+ SetPlayerVideoHole();
+ SetPlayerMediaGeometry();
+ }
+#endif
+ GetPlayer()->Initialize(sink_);
if (!GetPlayer()->IsPrepared()) {
SetStreamInfo();
void OnDurationChange(base::TimeDelta duration);
void OnBufferUpdate(base::TimeDelta time);
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHole(bool is_video_hole) final;
+ void SetMediaGeometry(const gfx::RectF& rect) final;
+
+ gfx::Rect GetViewportRect() const;
+#endif
+
void OnNewFrameAvailable(uint32_t playerId,
base::UnsafeSharedMemoryRegion frame,
uint32_t size,
void SetStreamInfo();
void SetPlayerVolume();
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetPlayerVideoHole();
+ void SetPlayerMediaGeometry();
+#endif
void OnRendererEnded();
void OnError(media::PipelineStatus error);
void OnStatisticsUpdate(const media::PipelineStatistics& stats);
// Indicates if a serious error has been encountered by the |media_player_|.
bool has_error_ = false;
+#if defined(TIZEN_VIDEO_HOLE)
+ WebContents* web_contents_;
+ bool is_video_hole_ = false;
+ gfx::RectF video_rect_;
+#endif
+
base::WeakPtrFactory<TizenRendererImpl> weak_factory_{this};
};
weak_factory_.GetWeakPtr()));
}
+#if defined(TIZEN_VIDEO_HOLE)
+void MediaPlayerRendererClient::SetVideoHole(bool is_video_hole) {
+ is_video_hole_ = is_video_hole;
+ MojoRendererWrapper::SetVideoHole(is_video_hole);
+}
+
+void MediaPlayerRendererClient::SetMediaGeometry(const gfx::RectF& rect) {
+ MojoRendererWrapper::SetMediaGeometry(rect);
+}
+#endif
+
void MediaPlayerRendererClient::OnRemoteRendererInitialized(
media::PipelineStatus status) {
DCHECK(media_task_runner_->BelongsToCurrentThread());
media::RendererClient* client,
media::PipelineStatusCallback init_cb) override;
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHole(bool is_video_hole) override;
+ void SetMediaGeometry(const gfx::RectF& rect) override;
+#endif
+
// media::mojom::MediaPlayerRendererClientExtension implementation
void OnDurationChange(base::TimeDelta duration) override;
void OnVideoSizeChange(const gfx::Size& size) override;
private:
void OnRemoteRendererInitialized(media::PipelineStatus status);
+#if defined(TIZEN_MULTIMEDIA)
+ bool is_video_hole_ = false;
+#endif
+
// The underlying type should always be a MediaUrlDemuxer, but we only use
// methods from the MediaResource interface.
media::MediaResource* media_resource_;
#include "base/time/time.h"
#include "media/base/efl/media_player_util_efl.h"
+#if defined(TIZEN_VIDEO_HOLE)
+#include "ui/gfx/geometry/rect_f.h"
+#endif
+
typedef struct media_packet_s* media_packet_h;
namespace content {
virtual void Resume() { suspended_ = false; }
virtual void Suspend() { suspended_ = true; }
+#if defined(TIZEN_VIDEO_HOLE)
+ virtual void SetVideoHole(bool is_video_hole) = 0;
+ virtual void SetMediaGeometry(const gfx::Rect& viewport_rect,
+ const gfx::RectF& rect) = 0;
+#endif
+
protected:
explicit MediaPlayerEfl(int player_id, MediaPlayerManager* manager);
#include "third_party/libyuv/include/libyuv/planar_functions.h"
#include "ui/gfx/geometry/size.h"
+#if defined(TIZEN_VIDEO_HOLE)
+#include "tizen_src/chromium_impl/media/base/tizen/video_plane_controller_capi.h"
+#include "tizen_src/chromium_impl/media/filters/esplusplayer_util.h"
+#endif
+
namespace {
// Update duration every 100ms.
PLAYER_ERROR_NONE)
LOG(ERROR) << "Unable to set streaming user agent.";
- ret = player_set_media_packet_video_frame_decoded_cb(
- player_, MediaPacketDecodedCb, this);
- if (ret != PLAYER_ERROR_NONE) {
- OnHandlePlayerError(ret, FROM_HERE);
- RunCompleteCB(false, FROM_HERE);
- return;
+#if defined(TIZEN_VIDEO_HOLE)
+ if (is_video_hole_) {
+ ret = player_set_display(player_, PLAYER_DISPLAY_TYPE_OVERLAY,
+ video_plane_controller_->GetVideoPlaneHandle());
+ if (ret != PLAYER_ERROR_NONE) {
+ OnHandlePlayerError(ret, FROM_HERE);
+ RunCompleteCB(false, FROM_HERE);
+ return;
+ }
+ } else
+#endif
+ {
+ ret = player_set_media_packet_video_frame_decoded_cb(
+ player_, MediaPacketDecodedCb, this);
+ if (ret != PLAYER_ERROR_NONE) {
+ OnHandlePlayerError(ret, FROM_HERE);
+ RunCompleteCB(false, FROM_HERE);
+ return;
+ }
}
player_set_completed_cb(player_, PlaybackCompleteCb, this);
}
void MediaPlayerBridgeCapi::Initialize() {
+#if defined(TIZEN_VIDEO_HOLE)
+ if (is_video_hole_) {
+ if (!video_plane_controller_)
+ return;
+
+ int ret = video_plane_controller_->Initialize();
+ if (ret != PLAYER_ERROR_NONE) {
+ OnHandlePlayerError(ret, FROM_HERE);
+ return;
+ }
+ }
+#endif
+
Prepare(base::BindOnce(&MediaPlayerBridgeCapi::OnInitComplete,
weak_factory_.GetWeakPtr()));
}
return;
}
+#if defined(TIZEN_VIDEO_HOLE)
+ if (!delayed_rect_.IsEmpty() && !delayed_viewport_rect_.IsEmpty()) {
+ SetMediaGeometry(delayed_viewport_rect_, delayed_rect_);
+ delayed_viewport_rect_ = gfx::Rect();
+ delayed_rect_ = gfx::RectF();
+ }
+#endif
+
WakeUpDisplayAndAcquireDisplayLock();
StartCurrentTimeUpdateTimer();
volume_ = volume;
}
+#if defined(TIZEN_VIDEO_HOLE)
+void MediaPlayerBridgeCapi::SetVideoHole(bool is_video_hole) {
+ LOG(INFO) << __func__ << " is_video_hole : " << is_video_hole;
+ is_video_hole_ = is_video_hole;
+ if (is_video_hole_ && player_ && !video_plane_controller_) {
+ video_plane_controller_.reset(new VideoPlaneControllerCapi(player_));
+ }
+}
+
+void MediaPlayerBridgeCapi::SetMediaGeometry(const gfx::Rect& viewport_rect,
+ const gfx::RectF& rect) {
+ if (!is_video_hole_)
+ return;
+
+ if (GetPlayerState() < PLAYER_STATE_PLAYING) {
+ delayed_viewport_rect_ = viewport_rect;
+ delayed_rect_ = rect;
+ return;
+ }
+
+ LOG(INFO) << __func__ << " viewport_rect: " << viewport_rect.ToString()
+ << " rect : " << rect.ToString();
+ video_plane_controller_->SetMediaGeometry(viewport_rect, rect);
+}
+#endif
+
void MediaPlayerBridgeCapi::UpdateMediaType() {
int sample_rate = 0;
int channel = 0;
return;
}
+#if defined(TIZEN_VIDEO_HOLE)
+ if (is_video_hole_)
+ video_plane_controller_->ApplyDeferredVideoRectIfNeeded();
+#endif
+
UpdateMediaType();
if (media_type_ == 0) {
RunCompleteCB(true, FROM_HERE);
#include "media/base/ranges.h"
#include "media/base/video_frame.h"
+#if defined(TIZEN_VIDEO_HOLE)
+#include "tizen_src/chromium_impl/media/base/tizen/video_plane_controller.h"
+#include "ui/gfx/geometry/rect_f.h"
+#endif
+
namespace media {
class MEDIA_EXPORT MediaPlayerBridgeCapi : public MediaPlayerEfl {
void SetVolume(double volume) override;
double GetCurrentTime() override;
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHole(bool is_video_hole) override;
+ void SetMediaGeometry(const gfx::Rect& viewport_rect,
+ const gfx::RectF& rect) override;
+#endif
+
void ExecuteDelayedPlayerState();
void OnPlaybackCompleteUpdate();
int media_type_;
+#if defined(TIZEN_VIDEO_HOLE)
+ bool is_video_hole_ = false;
+ gfx::Rect delayed_viewport_rect_;
+ gfx::RectF delayed_rect_;
+ std::unique_ptr<VideoPlaneController> video_plane_controller_;
+#endif
+
// NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<MediaPlayerBridgeCapi> weak_factory_;
};
--- /dev/null
+// Copyright 2016 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/base/tizen/video_plane_controller.h"
+
+#if defined(OS_TIZEN_TV_PRODUCT)
+#include "ui/display/device_display_info_efl.h"
+#endif
+
+namespace media {
+
+void* VideoPlaneController::main_window_handle_ = nullptr;
+VideoPlaneController::RenderingMode VideoPlaneController::rendering_mode_ =
+ VideoPlaneController::RenderingMode::OFFSCREEN;
+
+VideoPlaneController::VideoPlaneController() : should_crop_video_(false) {}
+
+VideoPlaneController::~VideoPlaneController() {}
+
+void* VideoPlaneController::GetVideoPlaneHandle() {
+ if (!main_window_handle_)
+ LOG(ERROR) << "failed: main window is null!";
+
+ return main_window_handle_;
+}
+
+gfx::RectF VideoPlaneController::SetCropRatio(
+ const gfx::Rect& viewport_rect,
+ const gfx::RectF& video_rect,
+ const absl::optional<gfx::RectF>& visible_cropratio) {
+ gfx::RectF view_rect =
+ gfx::RectF(viewport_rect.x(), viewport_rect.y(), viewport_rect.width(),
+ viewport_rect.height());
+
+ // Offset the position of the video to fit the screen.
+ // Because of the player(MM) use the based on the
+ // screen(EFL window) coordinates, the offset this.
+ gfx::RectF screen_video_rect = video_rect;
+ screen_video_rect.Offset(view_rect.x(), view_rect.y());
+
+ gfx::RectF visible_rect = screen_video_rect;
+ visible_rect.Intersect(view_rect);
+
+ int ret = PLAYER_ERROR_NONE;
+
+ if (visible_rect.size() == screen_video_rect.size() ||
+ visible_rect.IsEmpty()) {
+ if (should_crop_video_ || (visible_cropratio != gfx::RectF{0, 0, 1, 1})) {
+ ret = PlayerSetCropRatio(
+ visible_cropratio.value_or(gfx::RectF(0, 0, 1, 1)));
+ if (ret != PLAYER_ERROR_NONE)
+ return gfx::RectF();
+ }
+ should_crop_video_ = false;
+
+ if (visible_rect.IsEmpty())
+ return gfx::RectF(view_rect.x(), view_rect.y(), 1, 1);
+ return screen_video_rect;
+ }
+
+ gfx::RectF cropratio_rect = screen_video_rect;
+ cropratio_rect.set_x(screen_video_rect.x() < visible_rect.x()
+ ? abs(screen_video_rect.x() - visible_rect.x()) /
+ screen_video_rect.width()
+ : 0.0);
+
+ cropratio_rect.set_width(
+ screen_video_rect.width() > visible_rect.width()
+ ? 1.0 - abs(screen_video_rect.width() - visible_rect.width()) /
+ screen_video_rect.width()
+ : 1.0);
+
+ cropratio_rect.set_y(screen_video_rect.y() < visible_rect.y()
+ ? abs(screen_video_rect.y() - visible_rect.y()) /
+ screen_video_rect.height()
+ : 0.0);
+
+ cropratio_rect.set_height(
+ screen_video_rect.height() > visible_rect.height()
+ ? 1.0 - abs(screen_video_rect.height() - visible_rect.height()) /
+ screen_video_rect.height()
+ : 1.0);
+
+ if (visible_cropratio.has_value())
+ cropratio_rect.Intersect(visible_cropratio.value());
+ ret = PlayerSetCropRatio(cropratio_rect);
+ if (ret != PLAYER_ERROR_NONE)
+ return gfx::RectF();
+
+ should_crop_video_ = true;
+
+ return visible_rect;
+}
+
+void VideoPlaneController::SetDeferredVideoRect(
+ const gfx::Rect& viewport_rect,
+ const gfx::RectF& rect,
+ const absl::optional<gfx::RectF>& visible_crop_ratio) {
+ deferred_viewport_rect_ = viewport_rect;
+ deferred_video_rect_ = rect;
+ deferred_visible_crop_ratio_ = visible_crop_ratio;
+}
+
+void VideoPlaneController::ApplyDeferredVideoRectIfNeeded() {
+ if (!deferred_video_rect_.IsEmpty() ||
+ deferred_visible_crop_ratio_.has_value()) {
+ SetMediaGeometry(deferred_viewport_rect_, deferred_video_rect_,
+ deferred_visible_crop_ratio_, GetVideoRotation());
+ deferred_video_rect_ = gfx::RectF();
+ deferred_visible_crop_ratio_ = gfx::RectF();
+ }
+}
+
+int VideoPlaneController::SetMediaGeometry(
+ const gfx::Rect& viewport_rect,
+ const gfx::RectF& rect,
+ const absl::optional<gfx::RectF>& visible_ratio,
+ int rotation) {
+ LOG(INFO) << "VideoPlaneController::SetMediaGeometry, viewport_rect: "
+ << viewport_rect.ToString() << " rect: " << rect.ToString()
+ << " visible_ratio: "
+ << visible_ratio.value_or(gfx::RectF(0, 0, 1, 1)).ToString()
+ << " rotation: " << rotation;
+
+ video_rotation_ = rotation;
+ SetDisplayRotation();
+
+ if (rect.IsEmpty()) {
+ LOG(INFO) << "skip: rect is empty!";
+ return PLAYER_ERROR_NONE;
+ }
+
+ current_viewport_rect_ = viewport_rect;
+ current_rect_ = rect;
+ current_visible_ratio_ = visible_ratio;
+
+ if (!IsAvailableSetMediaGeometry()) {
+ LOG(INFO) << "store the video rect because of player was not ready.";
+ SetDeferredVideoRect(viewport_rect, rect, visible_ratio);
+ return PLAYER_ERROR_NONE;
+ }
+
+ LOG(INFO) << "Video_geometry (" << rect.ToString() << ")";
+
+ gfx::RectF display_rect = SetCropRatio(viewport_rect, rect, visible_ratio);
+
+ if (display_rect.IsEmpty()) {
+ LOG(INFO) << "skip: crop rect is empty!";
+ return PLAYER_ERROR_NONE;
+ }
+
+ LOG(INFO) << "Display_video_geometry(" << display_rect.ToString() << ")";
+
+ return SetVideoRect(display_rect);
+}
+
+void VideoPlaneController::ResetMediaGeometry() {
+ SetMediaGeometry(current_viewport_rect_, current_rect_,
+ current_visible_ratio_, video_rotation_);
+}
+
+} // namespace media
--- /dev/null
+// Copyright 2016 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_BASE_TIZEN_VIDEO_PLANE_CONTROLLER_H_
+#define MEDIA_BASE_TIZEN_VIDEO_PLANE_CONTROLLER_H_
+
+#include "base/logging.h"
+#include "media/base/media_export.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace media {
+
+class MediaPlayerESPlusPlayer;
+
+class MEDIA_EXPORT VideoPlaneController {
+ public:
+ enum class RenderingMode { OFFSCREEN, ONSCREEN };
+ enum PlayerError { PLAYER_ERROR_NONE, PLAYER_ERROR_INVALID_OPERATION };
+
+ static void SetSharedVideoWindowHandle(void* handle,
+ RenderingMode rendering_mode) {
+ main_window_handle_ = handle;
+ rendering_mode_ = rendering_mode;
+ }
+ static RenderingMode rendering_mode() { return rendering_mode_; }
+
+ VideoPlaneController();
+ virtual ~VideoPlaneController();
+
+ virtual int Initialize() = 0;
+ void* GetVideoPlaneHandle();
+ int SetMediaGeometry(
+ const gfx::Rect& viewport_rect,
+ const gfx::RectF& rect,
+ const absl::optional<gfx::RectF>& visible_cropratio = absl::nullopt,
+ int rotation = 0);
+
+ void ApplyDeferredVideoRectIfNeeded();
+
+ void ResetMediaGeometry();
+ virtual void SetDisplayRotation(int rotation_degree) = 0;
+ virtual void SetDisplayRotation() = 0;
+
+ protected:
+ int GetVideoRotation() const { return video_rotation_; }
+
+ private:
+ static void* main_window_handle_;
+ static RenderingMode rendering_mode_;
+
+ gfx::RectF SetCropRatio(const gfx::Rect&,
+ const gfx::RectF&,
+ const absl::optional<gfx::RectF>& visible_crop_ratio);
+
+ // If player_prepare_async is not complete, store the video rect.
+ void SetDeferredVideoRect(const gfx::Rect&,
+ const gfx::RectF&,
+ const absl::optional<gfx::RectF>&);
+
+ virtual int SetVideoRect(const gfx::RectF&) = 0;
+ virtual int PlayerSetCropRatio(const gfx::RectF& rect) = 0;
+ virtual bool IsAvailableSetMediaGeometry() = 0;
+
+ bool should_crop_video_;
+ gfx::Rect deferred_viewport_rect_{};
+ gfx::RectF deferred_video_rect_{};
+ absl::optional<gfx::RectF> deferred_visible_crop_ratio_{};
+ gfx::Rect current_viewport_rect_;
+ gfx::RectF current_rect_;
+ absl::optional<gfx::RectF> current_visible_ratio_;
+ int video_rotation_{0};
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_TIZEN_VIDEO_PLANE_CONTROLLER_H_
--- /dev/null
+// Copyright 2016 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/base/tizen/video_plane_controller_capi.h"
+
+#include <Evas.h>
+
+#include "base/logging.h"
+#include "media/base/efl/media_player_util_efl.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+
+#if defined(OS_TIZEN_TV_PRODUCT)
+#include <player_product.h>
+#endif
+
+namespace media {
+
+VideoPlaneControllerCapi::VideoPlaneControllerCapi(player_h player)
+ : player_handle_(player) {}
+
+VideoPlaneControllerCapi::~VideoPlaneControllerCapi() {}
+
+int VideoPlaneControllerCapi::Initialize() {
+ int ret = PLAYER_ERROR_NONE;
+#if defined(OS_TIZEN_TV_PRODUCT)
+ ret = player_set_display_mode(player_handle_, PLAYER_DISPLAY_MODE_DST_ROI);
+
+ if (ret != PLAYER_ERROR_NONE)
+ return ret;
+
+ // init video size
+ gfx::RectF init_rect(0.0f, 0.0f, 1.0f, 1.0f);
+ ret = SetVideoRect(init_rect);
+#endif
+
+ return ret;
+}
+
+int VideoPlaneControllerCapi::SetVideoRect(const gfx::RectF& rect) {
+ int ret = PLAYER_ERROR_NONE;
+#if defined(OS_TIZEN_TV_PRODUCT)
+ ret = player_set_display_roi_area(player_handle_, rect.x(), rect.y(),
+ rect.width(), rect.height());
+#endif
+ return ret;
+}
+
+int VideoPlaneControllerCapi::PlayerSetCropRatio(const gfx::RectF& rect) {
+ int ret = PLAYER_ERROR_NONE;
+#if defined(OS_TIZEN_TV_PRODUCT)
+ LOG(INFO) << "crop_ratio : (" << rect.x() << ", " << rect.y() << ", "
+ << rect.width() << ", " << rect.height() << ")";
+
+ ret = player_set_crop_ratio(player_handle_, rect.x(), rect.y(), rect.width(),
+ rect.height());
+#endif
+ return ret;
+}
+
+player_state_e VideoPlaneControllerCapi::GetPlayerState() {
+ player_state_e state = PLAYER_STATE_NONE;
+ player_get_state(player_handle_, &state);
+ return state;
+}
+
+bool VideoPlaneControllerCapi::IsAvailableSetMediaGeometry() {
+ return (GetPlayerState() >= PLAYER_STATE_READY);
+}
+
+void VideoPlaneControllerCapi::SetDisplayRotation(int rotation_degree) {
+ player_display_rotation_e screen_rotation =
+ ConvertToPlayerDisplayRotation(rotation_degree);
+ player_display_rotation_e rotation = PLAYER_DISPLAY_ROTATION_NONE;
+ int ret = player_get_display_rotation(player_handle_, &rotation);
+ if (ret == PLAYER_ERROR_NONE && screen_rotation != rotation) {
+ LOG(INFO) << "video should rotate angle : " << screen_rotation;
+ ret = player_set_display_rotation(player_handle_, screen_rotation);
+ if (ret != PLAYER_ERROR_NONE) {
+ LOG(ERROR) << "Cannot set display rotation : "
+ << GetErrorString(static_cast<player_error_e>(ret));
+ }
+ }
+}
+
+void VideoPlaneControllerCapi::SetDisplayRotation() {
+ int rotation =
+ display::Screen::GetScreen()->GetPrimaryDisplay().RotationAsDegree();
+ SetDisplayRotation(rotation);
+}
+
+player_display_rotation_e
+VideoPlaneControllerCapi::ConvertToPlayerDisplayRotation(int rotation) {
+ switch (rotation) {
+#if defined(OS_TIZEN_TV_PRODUCT)
+ case 90:
+ return PLAYER_DISPLAY_ROTATION_270;
+ case 180:
+ return PLAYER_DISPLAY_ROTATION_180;
+ case 270:
+ return PLAYER_DISPLAY_ROTATION_90;
+#else
+ case 90:
+ return PLAYER_DISPLAY_ROTATION_90;
+ case 180:
+ return PLAYER_DISPLAY_ROTATION_180;
+ case 270:
+ return PLAYER_DISPLAY_ROTATION_270;
+#endif
+ default:
+ return PLAYER_DISPLAY_ROTATION_NONE;
+ }
+}
+
+} // namespace media
--- /dev/null
+// Copyright 2016 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_BASE_TIZEN_VIDEO_PLANE_CONTROLLER_CAPI_H_
+#define MEDIA_BASE_TIZEN_VIDEO_PLANE_CONTROLLER_CAPI_H_
+
+#include <player.h>
+
+#include "media/base/tizen/video_plane_controller.h"
+
+namespace media {
+
+class MEDIA_EXPORT VideoPlaneControllerCapi : public VideoPlaneController {
+ public:
+ VideoPlaneControllerCapi(player_h player);
+
+ ~VideoPlaneControllerCapi() override;
+
+ int Initialize() override;
+ void SetDisplayRotation(int) override;
+ void SetDisplayRotation() override;
+
+ private:
+ player_state_e GetPlayerState();
+ int SetVideoRect(const gfx::RectF&) override;
+ int PlayerSetCropRatio(const gfx::RectF& rect) override;
+ bool IsAvailableSetMediaGeometry() override;
+
+ player_display_rotation_e ConvertToPlayerDisplayRotation(int rotation);
+
+ player_h player_handle_;
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_TIZEN_VIDEO_PLANE_CONTROLLER_CAPI_H_
--- /dev/null
+// Copyright 2019 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/base/tizen/video_plane_controller_esplusplayer.h"
+
+#include <Evas.h>
+#include <drm.h>
+#include <esplusplayer_capi.h>
+#include <esplusplayer_internal.h>
+
+#include "base/logging.h"
+#include "tizen_src/chromium_impl/media/filters/esplusplayer_util.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+
+namespace media {
+
+VideoPlaneControllerESPlusPlayer::VideoPlaneControllerESPlusPlayer(
+ void* esplayer_handle)
+ : player_handle_(esplayer_handle) {}
+
+VideoPlaneControllerESPlusPlayer::~VideoPlaneControllerESPlusPlayer() {}
+
+int VideoPlaneControllerESPlusPlayer::Initialize() {
+ int player_error = esplusplayer_set_display_mode(
+ player_handle_, ESPLUSPLAYER_DISPLAY_MODE_DST_ROI);
+ if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
+ LOG(ERROR) << "esplusplayer_set_display_mode failed! error code "
+ << player_error;
+
+ return player_error;
+ }
+
+ // init video size
+ gfx::RectF init_rect(0.0f, 0.0f, 1.0f, 1.0f);
+ return SetVideoRect(init_rect);
+}
+
+int VideoPlaneControllerESPlusPlayer::SetVideoRect(const gfx::RectF& rect) {
+ LOG(INFO) << __func__ << " rect:" << rect.ToString();
+ int player_error = esplusplayer_set_display_roi(
+ player_handle_, rect.x(), rect.y(), rect.width(), rect.height());
+ if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
+ LOG(ERROR) << "esplusplayer_set_display_roi failed! error code "
+ << player_error;
+ }
+ return player_error;
+}
+
+int VideoPlaneControllerESPlusPlayer::PlayerSetCropRatio(
+ const gfx::RectF& rect) {
+ LOG(INFO) << "crop_ratio : (" << rect.x() << ", " << rect.y() << ", "
+ << rect.width() << ", " << rect.height() << ")";
+
+ int player_error = esplusplayer_set_video_roi(
+ player_handle_, rect.x(), rect.y(), rect.width(), rect.height());
+ if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
+ LOG(ERROR) << "esplusplayer_set_display_roi failed! error code "
+ << player_error;
+ }
+ return player_error;
+}
+
+esplusplayer_state VideoPlaneControllerESPlusPlayer::GetPlayerState() {
+ return esplusplayer_get_state(player_handle_);
+}
+
+bool VideoPlaneControllerESPlusPlayer::IsAvailableSetMediaGeometry() {
+ return (GetPlayerState() >= ESPLUSPLAYER_STATE_READY);
+}
+
+void VideoPlaneControllerESPlusPlayer::SetDisplayRotation(int rotation_degree) {
+ esplusplayer_display_rotation_type screen_rotation =
+ ConvertToESPlusPlayerDisplayRotation(rotation_degree);
+
+ esplusplayer_display_rotation_type rotation;
+ int player_error =
+ esplusplayer_get_display_rotation(player_handle_, &rotation);
+ if (player_error == ESPLUSPLAYER_ERROR_TYPE_NONE &&
+ screen_rotation != rotation) {
+ LOG(INFO) << "video should rotate angle : " << screen_rotation;
+
+ player_error =
+ esplusplayer_set_display_rotation(player_handle_, screen_rotation);
+ if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
+ LOG(ERROR) << "Cannot set display rotation. error code " << player_error;
+ }
+ }
+}
+
+void VideoPlaneControllerESPlusPlayer::SetDisplayRotation() {
+ int display_rotation =
+ display::Screen::GetScreen()->GetPrimaryDisplay().RotationAsDegree();
+ SetDisplayRotation((display_rotation + GetVideoRotation()) % 360);
+}
+} // namespace media
--- /dev/null
+// Copyright 2019 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_BASE_TIZEN_VIDEO_PLANE_CONTROLLER_ESPLUSPLAYER_H_
+#define MEDIA_BASE_TIZEN_VIDEO_PLANE_CONTROLLER_ESPLUSPLAYER_H_
+
+#include <esplusplayer_capi/esplusplayer_capi.h>
+#include <esplusplayer_capi/esplusplayer_internal.h>
+
+#include "media/base/tizen/video_plane_controller.h"
+
+namespace media {
+
+class MEDIA_EXPORT VideoPlaneControllerESPlusPlayer
+ : public VideoPlaneController {
+ public:
+ VideoPlaneControllerESPlusPlayer(void* esplayer_handle);
+
+ ~VideoPlaneControllerESPlusPlayer() override;
+
+ int Initialize() override;
+ void SetDisplayRotation(int) override;
+ void SetDisplayRotation() override;
+
+ private:
+ esplusplayer_state GetPlayerState();
+ int SetVideoRect(const gfx::RectF&) override;
+ int PlayerSetCropRatio(const gfx::RectF& rect) override;
+ bool IsAvailableSetMediaGeometry() override;
+
+ esplusplayer_handle player_handle_;
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_TIZEN_VIDEO_PLANE_CONTROLLER_ESPLUSPLAYER_H_
return PIPELINE_ERROR_DECODE;
}
-gfx::Size GetMaxCodecResolution(esplusplayer_video_mime_type mime_type) {
+gfx::Size GetMaxCodecResolution(esplusplayer_video_mime_type mime_type,
+ bool is_video_hole) {
switch (mime_type) {
case ESPLUSPLAYER_VIDEO_MIME_TYPE_AV1:
return {k8KVideoMaxWidth, k8KVideoMaxHeight};
case ESPLUSPLAYER_VIDEO_MIME_TYPE_HEVC:
return {k8KVideoMaxWidth, k8KVideoMaxHeight};
case ESPLUSPLAYER_VIDEO_MIME_TYPE_H264:
- return {kFHDVideoMaxWidth, kFHDVideoMaxHeight};
+ if (is_video_hole)
+ return {k4KVideoMaxWidth, k4KVideoMaxHeight};
+ else
+ return {kFHDVideoMaxWidth, kFHDVideoMaxHeight};
default:
// for all kind of codecs.
return {kFHDVideoMaxWidth, kFHDVideoMaxHeight};
}
}
+esplusplayer_display_rotation_type ConvertToESPlusPlayerDisplayRotation(
+ int rotation) {
+ switch (rotation) {
+ case 90:
+ return ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_270;
+ case 180:
+ return ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_180;
+ case 270:
+ return ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_90;
+ default:
+ return ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_NONE;
+ }
+}
+
} // namespace media
#include "ui/gfx/geometry/size.h"
namespace media {
-
const int kElementryStreamCount = 2; // Audio, Video only.
const int kVideoFramerateDen = 100;
PipelineStatus GetPipelineError(const esplusplayer_error_type error);
-gfx::Size GetMaxCodecResolution(esplusplayer_video_mime_type mime_type);
+gfx::Size GetMaxCodecResolution(esplusplayer_video_mime_type mime_type,
+ bool is_video_hole);
+
+esplusplayer_display_rotation_type ConvertToESPlusPlayerDisplayRotation(
+ int rotation);
} // namespace media
#if defined(TIZEN_VIDEO_HOLE)
void MediaPlayerBridgeCapiAdapter::SetVideoHole(bool is_video_hole) {
- NOTIMPLEMENTED();
+ media_player_->SetVideoHole(is_video_hole);
}
void MediaPlayerBridgeCapiAdapter::SetMediaGeometry(
const gfx::Rect& viewport_rect,
const gfx::RectF& rect) {
- NOTIMPLEMENTED();
+ media_player_->SetMediaGeometry(viewport_rect, rect);
}
#endif
#include "third_party/libyuv/include/libyuv/convert.h"
#include "tizen_src/chromium_impl/media/filters/media_player_registry.h"
+#if defined(TIZEN_VIDEO_HOLE)
+#include <Ecore_Wl2.h>
+#include "tizen_src/chromium_impl/media/base/tizen/video_plane_controller_esplusplayer.h"
+#endif
+
namespace media {
using player_buffer_size_t = unsigned long long;
buffer_observer_.reset(BufferObserver::CreateBufferObserver());
+#if defined(TIZEN_VIDEO_HOLE)
+ LOG(INFO) << __func__ << " is_video_hole_: " << is_video_hole_;
+ if (is_video_hole_) {
+ video_plane_controller_.reset(
+ new VideoPlaneControllerESPlusPlayer(esplayer_));
+ }
+#endif
+
return true;
}
esplusplayer_decoded_video_frame_buffer_type video_frame_buffer_type =
ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_COPY;
+#if defined(TIZEN_VIDEO_HOLE)
+ if (is_video_hole_)
+ video_frame_buffer_type = ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_NONE;
+#endif
error = esplusplayer_set_video_frame_buffer_type(esplayer_,
video_frame_buffer_type);
return;
}
+#if defined(TIZEN_VIDEO_HOLE)
+ if (is_video_hole_ && video_plane_controller_) {
+ if (video_plane_controller_->Initialize() != TIZEN_ERROR_NONE) {
+ LOG(ERROR) << "video_plane_controller init error";
+ return;
+ }
+ LOG(INFO) << __func__ << " set ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY";
+ int player_error = ESPLUSPLAYER_ERROR_TYPE_NONE;
+ if (video_plane_controller_->rendering_mode() ==
+ VideoPlaneController::RenderingMode::OFFSCREEN) {
+ player_error = esplusplayer_set_display(
+ esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+ video_plane_controller_->GetVideoPlaneHandle());
+ } else {
+ int wl_w, wl_h, wl_x, wl_y;
+ ecore_wl2_window_geometry_get(
+ static_cast<Ecore_Wl2_Window*>(
+ video_plane_controller_->GetVideoPlaneHandle()),
+ &wl_x, &wl_y, &wl_w, &wl_h);
+
+ player_error = esplusplayer_set_ecore_display(
+ esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+ static_cast<Ecore_Wl2_Window*>(
+ video_plane_controller_->GetVideoPlaneHandle()),
+ wl_x, wl_y, wl_w, wl_h);
+ }
+ if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
+ LOG(ERROR) << "player_error #"
+ << esplusplayer_get_error_string(
+ static_cast<esplusplayer_error_type>(player_error));
+ return;
+ }
+ }
+#endif
+
int error = esplusplayer_prepare_async(esplayer_);
if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
LOG(ERROR) << "player prepare failed! error #"
} else {
video_stream_info.codec_data = NULL;
}
- auto max_resolution = GetMaxCodecResolution(video_stream_info.mime_type);
+ auto max_resolution =
+ GetMaxCodecResolution(video_stream_info.mime_type, is_video_hole_);
video_stream_info.max_width = max_resolution.width();
video_stream_info.max_height = max_resolution.height();
<< " pending_seek_ : " << pending_seek_
<< " pending_seek_position_ : " << pending_seek_position_;
+#if defined(TIZEN_VIDEO_HOLE)
+ if (is_video_hole_)
+ video_plane_controller_->ResetMediaGeometry();
+#endif
+
is_prepared_ = true;
if (pending_seek_) {
Seek(pending_seek_position_);
data_cb_ = datacb;
}
+#if defined(TIZEN_VIDEO_HOLE)
+void MediaPlayerESPlusPlayer::SetVideoHole(bool is_video_hole) {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
+ << " is_video_hole : " << is_video_hole;
+ is_video_hole_ = is_video_hole;
+ if (is_video_hole_ && esplayer_ && !video_plane_controller_) {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
+ << " pended set video_plane_controller";
+ video_plane_controller_.reset(
+ new VideoPlaneControllerESPlusPlayer(esplayer_));
+ }
+}
+
+void MediaPlayerESPlusPlayer::SetMediaGeometry(const gfx::Rect& viewport_rect,
+ const gfx::RectF& rect) {
+ if (!is_video_hole_)
+ return;
+
+ LOG(INFO) << __func__ << " viewport_rect: " << viewport_rect.ToString()
+ << " rect : " << rect.ToString();
+ video_plane_controller_->SetMediaGeometry(viewport_rect, rect);
+}
+
+#endif
+
} // namespace media
#include "tizen_src/chromium_impl/media/filters/esplusplayer_util.h"
#include "tizen_src/chromium_impl/media/filters/media_player_tizen.h"
+#if defined(TIZEN_VIDEO_HOLE)
+#include "tizen_src/chromium_impl/media/base/tizen/video_plane_controller.h"
+#include "ui/gfx/geometry/rect_f.h"
+#endif
+
namespace media {
class DemuxerStream;
class RendererClient;
+class VideoPlaneController;
using Queue = base::circular_deque<scoped_refptr<DecoderBuffer>>;
base::TimeDelta GetCurrentTime() override;
void SetFrameAvailableCallback(const DataRequestCB& datacb) override;
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHole(bool is_video_hole) override;
+ void SetMediaGeometry(const gfx::Rect& viewport_rect,
+ const gfx::RectF& rect) override;
+#endif
#if defined(TIZEN_TBM_SUPPORT)
void DestroyMediaPacket(void* media_packet) override;
bool should_set_playback_rate_ = false;
+ bool is_video_hole_ = false;
+#if defined(TIZEN_VIDEO_HOLE)
+ gfx::Rect viewport_rect_;
+ std::unique_ptr<VideoPlaneController> video_plane_controller_;
+#endif
+
base::OnceClosure flush_cb_;
int player_id_ = 0;
if (tizen_multimedia_support) {
external_media_efl_deps += [
"//tizen_src/build:capi-media-audio-io",
- "//tizen_src/build:libcapi-media-audio-io",
"//tizen_src/build:capi-media-camera",
- "//tizen_src/build:libcapi-media-camera",
"//tizen_src/build:capi-media-player",
- "//tizen_src/build:libcapi-media-player",
"//tizen_src/build:ecore",
+ "//tizen_src/build:libcapi-media-audio-io",
+ "//tizen_src/build:libcapi-media-camera",
+ "//tizen_src/build:libcapi-media-player",
"//tizen_src/build:libecore",
"//tizen_src/build:mm_player",
]
"//tizen_src/chromium_impl/media:media_efl_config",
]
+ if (use_wayland) {
+ external_media_video_decode_config += [
+ "//tizen_src/build:ecore-wayland",
+ "//tizen_src/build:libecore-wayland",
+ ]
+ }
+
external_media_video_decode_sources += [
"//tizen_src/chromium_impl/media/filters/esplusplayer_buffer_observer.h",
"//tizen_src/chromium_impl/media/filters/esplusplayer_buffer_observer_impl.cc",
"//tizen_src/chromium_impl/media/base/tizen/media_player_bridge_capi.cc",
"//tizen_src/chromium_impl/media/base/tizen/media_player_bridge_capi.h",
]
+
+ if (tizen_video_hole) {
+ external_media_video_decode_sources += [
+ "//tizen_src/chromium_impl/media/base/tizen/video_plane_controller.cc",
+ "//tizen_src/chromium_impl/media/base/tizen/video_plane_controller.h",
+ "//tizen_src/chromium_impl/media/base/tizen/video_plane_controller_capi.cc",
+ "//tizen_src/chromium_impl/media/base/tizen/video_plane_controller_capi.h",
+ "//tizen_src/chromium_impl/media/base/tizen/video_plane_controller_esplusplayer.cc",
+ "//tizen_src/chromium_impl/media/base/tizen/video_plane_controller_esplusplayer.h",
+ ]
+ }
}
if (tizen_audio_io) {
#include <cursor_module.h>
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+#include "tizen_src/chromium_impl/media/base/tizen/video_plane_controller.h"
+#endif
+
namespace ui {
#if BUILDFLAG(IS_TIZEN_TV)
#endif
if (ee_)
ecore_evas_free(ee_);
+
+#if defined(TIZEN_VIDEO_HOLE)
+ media::VideoPlaneController::SetSharedVideoWindowHandle(
+ nullptr, media::VideoPlaneController::RenderingMode::ONSCREEN);
+#endif
}
void EflWindow::Show(bool inactive) {
return;
}
+#if defined(TIZEN_VIDEO_HOLE)
+ // Hand a window handle to enable video hole in OnscreenRendering mode.
+ media::VideoPlaneController::SetSharedVideoWindowHandle(
+ ww, media::VideoPlaneController::RenderingMode::ONSCREEN);
+#endif
+
void* egl_window = ecore_wl2_egl_window_native_get(wl2_egl_window_);
if (!egl_window) {
LOG(ERROR) << "Failed to get native egl window";
bool, /* capable */
int /* calback id */)
+#if defined(TIZEN_VIDEO_HOLE)
+IPC_MESSAGE_ROUTED1(EwkViewMsg_SetVideoHole, bool /* Enable */)
+#endif
+
IPC_SYNC_MESSAGE_CONTROL1_1(EwkHostMsg_DecideNavigationPolicy,
NavigationPolicyParams,
bool /*handled*/)
base::BindRepeating(&EWebView::OnFocusOut, base::Unretained(this)));
}
+#if defined(TIZEN_VIDEO_HOLE)
+ if (rwhva() && pending_video_hole_setting_) {
+ rwhva()->host()->SetVideoHoleForRender(pending_video_hole_setting_);
+ pending_video_hole_setting_ = false;
+ }
+#endif
+
RenderViewHost* render_view_host = web_contents_->GetRenderViewHost();
SendDelayedMessages(render_view_host);
web_contents_->GetController().LoadURLWithParams(params);
}
+#if defined(TIZEN_VIDEO_HOLE)
+void EWebView::SetVideoHoleSupport(bool enable) {
+ if (!web_contents_->GetPrimaryMainFrame() ||
+ !web_contents_->GetPrimaryMainFrame()->IsRenderFrameLive() || !rwhva()) {
+ pending_video_hole_setting_ = enable;
+ return;
+ }
+
+ rwhva()->host()->SetVideoHoleForRender(enable);
+}
+#endif
+
bool EWebView::HandleShow() {
if (!native_view_)
return false;
if (!native_view_)
return false;
evas_object_move(native_view_, x, y);
+
+#if defined(TIZEN_VIDEO_HOLE) && !defined(EWK_BRINGUP)
+ if (rwhva())
+ rwhva()->offscreen_helper()->DidMoveWebView();
+#endif
+
return true;
}
int64_t current_quota);
void ExceededIndexedDatabaseQuotaReply(bool allow);
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetVideoHoleSupport(bool enable);
+#endif
+
/// ---- Event handling
bool HandleShow();
bool HandleHide();
std::unique_ptr<EWebAccessibility> eweb_accessibility_;
bool lazy_initialize_atk_ = false;
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+ bool pending_video_hole_setting_ = false;
+#endif
};
const unsigned int g_default_tilt_motion_sensitivity = 3;
#if defined(TIZEN_WEB_SPEECH_RECOGNITION)
#include "content/browser/speech/tts_platform_impl_tizen.h"
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+#include "tizen_src/chromium_impl/media/base/tizen/video_plane_controller.h"
+#endif
static Eina_Bool _ewk_view_default_user_media_permission(
Evas_Object*, Ewk_User_Media_Permission_Request*, void*);
Eina_Bool ewk_view_set_support_video_hole(Evas_Object* ewkView, Evas_Object* window, Eina_Bool enable, Eina_Bool isVideoWindow) {
LOG_EWK_API_MOCKUP();
- return false;
+#if defined(TIZEN_VIDEO_HOLE)
+ EWK_VIEW_IMPL_GET_OR_RETURN(ewkView, impl, EINA_FALSE);
+ impl->SetVideoHoleSupport(enable);
+ media::VideoPlaneController::SetSharedVideoWindowHandle(
+ window,
+ static_cast<media::VideoPlaneController::RenderingMode>(isVideoWindow));
+ return EINA_TRUE;
+#else
+ LOG_EWK_API_MOCKUP("Video Hole feature is not enabled");
+ return EINA_FALSE;
+#endif
}
void ewk_view_widget_pepper_extension_callback_set(Evas_Object* ewk_view, Generic_Sync_Call_Callback cb, void* user_data) {
* @}
*/
+#if defined(TIZEN_VIDEO_HOLE)
+/**
+ * @brief Sets the support of video hole and video window, Use H/W overlay for
+ * performance of video output
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] o the view object
+ * @param[in] o the top-level window object
+ * @param[in] enable EINA_TRUE to set on support the video hole,
+ * EINA_FALSE otherwise
+ * @param[in] enable EINA_TRUE to set on the video window of video hole,
+ * EINA_FALSE to set on the video windowless of video hole
+ *
+ * @return return @c EINA_TRUE on success or @c EINA_FALSE on failure
+ */
+EXPORT_API Eina_Bool ewk_view_set_support_video_hole(Evas_Object* ewkView,
+ Evas_Object* window,
+ Eina_Bool enable,
+ Eina_Bool isVideoWindow);
+#endif
+
#ifdef __cplusplus
}
#endif
tracing_enabled_(false),
user_agent_(ua),
tizen_version_(tizen_version),
+#if defined(TIZEN_VIDEO_HOLE)
+ video_hole_(false),
+#endif
#if BUILDFLAG(IS_TIZEN)
haptic_timer_id_(nullptr),
haptic_handle_(nullptr),
void OnWindowLoadStarted(Window::IdType id);
void OnWindowLoadFinished(Window::IdType id);
+#if defined(TIZEN_VIDEO_HOLE)
+ void SetEnableVideoHole(bool enable) { video_hole_ = enable; }
+ bool IsVideoHoleEnabled() const { return video_hole_; }
+#endif
+
void Exit() const;
void SetDefaultZoomFactor(double zoom);
double DefaultZoomFactor();
std::string user_agent_;
std::string tizen_version_;
+#if defined(TIZEN_VIDEO_HOLE)
+ bool video_hole_;
+#endif
#if BUILDFLAG(IS_TIZEN)
Ecore_Timer* haptic_timer_id_;
haptic_device_h haptic_handle_;
int desktop_mode = 1;
#endif
+#if defined(TIZEN_VIDEO_HOLE)
+int video_hw_overlay = 0;
+#endif
+
struct AppData {
AppData() : browser(nullptr), ewk_initialized(false) { }
printf(" -n, --no-color Don't use colors in application logs\n");
printf(" -d, --desktop Run application UI in desktop mode\n");
printf(" -m, --mobile Run application UI in mobile mode\n");
+#if defined(TIZEN_VIDEO_HOLE)
+ printf(" -o, --overlay Enable the H/W overlay of video\n");
+#endif
printf(" -u, --user-agent Set user agent string\n");
printf(" -l, --gui-level Run application different GUI elements\n");
printf(" 0 - no GUI\n");
{"zoom", required_argument, 0, 'z'},
{"help", no_argument, &show_help, 1},
{"tizen-version", required_argument, 0, 't'},
+#if defined(TIZEN_VIDEO_HOLE)
+ {"overlay", no_argument, &video_hw_overlay, 1},
+#endif
{0, 0, 0, 0}};
int option_index = 0;
+#if defined(TIZEN_VIDEO_HOLE)
+ c = getopt_long(argc, argv, "vndmhou:l:z:t:", long_options, &option_index);
+#else
c = getopt_long(argc, argv, "vndmhu:l:z:t:", long_options, &option_index);
+#endif
if (c == -1)
break;
case 't':
tizen_version = optarg;
break;
+#if defined(TIZEN_VIDEO_HOLE)
+ case 'o':
+ video_hw_overlay = 1;
+ break;
+#endif
default:
// Ignore EFL or chromium specific options,
// ewk_set_arguments should handle them
new Browser(desktop_mode, gui_level, user_agent, tizen_version);
if (zoom_factor > 0)
app_data->browser->SetDefaultZoomFactor(zoom_factor);
+
+#if defined(TIZEN_VIDEO_HOLE)
+ if (video_hw_overlay)
+ app_data->browser->SetEnableVideoHole(true);
+#endif
+
std::vector<std::string>::iterator it = app_data->urls.begin();
for (;it != app_data->urls.end(); ++it)
app_data->browser->CreateWindow().LoadURL(*it);
else
web_view_ = ewk_view_add(evas);
+#if defined(TIZEN_VIDEO_HOLE)
+ if (browser.IsVideoHoleEnabled())
+ ewk_view_set_support_video_hole(web_view_, window_, EINA_TRUE, EINA_FALSE);
+#endif
+
evas_object_resize(web_view_, width, height);
elm_object_part_content_set(web_view_elm_host_, "overlay", web_view_);