return (mailbox.name[0] << 24) + (mailbox.name[1] << 16) +
(mailbox.name[2] << 8) + mailbox.name[3];
}
-
-ui::RenderingWorkarounds ConvertToRenderingWorkarounds(
- const gpu::GpuDriverBugWorkarounds& gpu_driver_workarounds) {
- ui::RenderingWorkarounds result;
- result.rotation_180_degrees_workaround =
- gpu_driver_workarounds.rotation_180_degrees_workaround;
- result.replace_rotate_180_with_hv_flip =
- gpu_driver_workarounds.replace_rotate_180_with_hv_flip;
- result.limit_rotation_to_single_plane =
- gpu_driver_workarounds.limit_rotation_to_single_plane;
- return result;
-}
} // namespace
OverlayProcessorTizen::OverlayProcessorTizen(
: gpu_task_scheduler_(display_controller->gpu_task_scheduler()),
shared_image_interface_(shared_image_interface),
overlay_candidates_(std::move(overlay_candidates)),
- rendering_workarounds_(
- ConvertToRenderingWorkarounds(display_controller->skia_dependency()
- ->GetGpuDriverBugWorkarounds())) {
+ rendering_workarounds_(ui::ConvertToRenderingWorkarounds(
+ display_controller->skia_dependency()
+ ->GetGpuDriverBugWorkarounds())) {
weak_this_ = weak_factory_.GetWeakPtr();
plane_collection_manager_ =
"features": [
"ttvd_disable_buffer_parallel_copy"
]
+ },
+ {
+ "id": 413,
+ "description": "Prefer manual rendering within TTVD when used for low latency playback",
+ "os": {
+ "type": "linux"
+ },
+ "machine_model_name": ["NIKEL"],
+ "features": [
+ "ttvd_prefer_manual_rendering_for_low_latency",
+ "ttvd_disable_faster_decoder_selection"
+ ]
}
]
}
ttvd_force_frames_rendering
ttvd_disable_buffer_parallel_copy
ttvd_disable_faster_decoder_selection
+ttvd_prefer_manual_rendering_for_low_latency
scalarize_vec_and_mat_constructor_args
set_zero_level_before_generating_mipmap
simulate_out_of_memory_on_large_textures
case MediaVideoPixelFormat::kPixelFormatNV12:
hw_buffers_[VideoFrame::kUVPlane]->CopyFrom(
frame.nv12_data.uv_phys_data, frame.nv12_data.uv_stride,
- frame.image_size.width(), frame.image_size.height() / 2);
+ frame.image_size.width(), frame.image_size.width(),
+ frame.image_size.height() / 2);
break;
case MediaVideoPixelFormat::kPixelFormatNV16:
hw_buffers_[VideoFrame::kUVPlane]->Scale(
hw_buffers_[VideoFrame::kYPlane]->CopyFrom(
frame.nv12_data.y_phys_data, frame.nv12_data.y_stride,
- frame.image_size.width(), frame.image_size.height());
+ frame.image_size.width(), frame.image_size.width(),
+ frame.image_size.height());
std::array<base::ScopedClosureRunner, kNumNV12Planes> hw_buffers_unmappers;
namespace media {
-std::unique_ptr<DecoderFacadeVideo> CreateDecoderFacadeVideo() {
- return std::make_unique<OmxFacadeVideo>(std::make_unique<OmxWrapper>());
+std::unique_ptr<DecoderFacadeVideo> CreateDecoderFacadeVideo(
+ const gpu::GpuDriverBugWorkarounds* workarounds) {
+ return std::make_unique<OmxFacadeVideo>(std::make_unique<OmxWrapper>(),
+ workarounds);
}
} // namespace media
#ifndef MEDIA_FILTERS_TIZEN_DECODER_FACADE_FACTORY_H_
#define MEDIA_FILTERS_TIZEN_DECODER_FACADE_FACTORY_H_
+#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "media/filters/tizen/decoder_facade_video.h"
namespace media {
-std::unique_ptr<DecoderFacadeVideo> CreateDecoderFacadeVideo();
+std::unique_ptr<DecoderFacadeVideo> CreateDecoderFacadeVideo(
+ const gpu::GpuDriverBugWorkarounds* workarounds = nullptr);
} // namespace media
#endif // TIZEN_VERSION_AT_LEAST(6, 5, 0)
} // namespace
-OmxFacadeVideo::OmxFacadeVideo(std::unique_ptr<OmxWrapper> wrapper)
- : OmxFacade(std::move(wrapper)) {
+OmxFacadeVideo::OmxFacadeVideo(std::unique_ptr<OmxWrapper> wrapper,
+ const gpu::GpuDriverBugWorkarounds* workarounds)
+ : OmxFacade(std::move(wrapper)),
+ workarounds_(workarounds ? *workarounds
+ : gpu::GpuDriverBugWorkarounds()) {
weak_this_ = weak_factory_.GetWeakPtr();
}
param.bPresetMode = OMX_FALSE;
param.nCodecExtraDataSize = 0;
param.bErrorConcealment = OMX_FALSE;
+
+ const bool is_mfc = component_name.find("mfc") != std::string::npos;
+ if (is_mfc && low_delay_ &&
+ workarounds_.ttvd_prefer_manual_rendering_for_low_latency) {
+ param.bNoVideoOut = OMX_TRUE;
+ }
+
switch (codec_) {
case MediaVideoCodec::kCodecH264:
case MediaVideoCodec::kCodecHEVC:
#define MEDIA_FILTERS_TIZEN_OMX_OMX_FACADE_VIDEO_H_
#include "base/memory/weak_ptr.h"
+#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "media/base/video_color_space.h"
#include "media/filters/tizen/decoder_facade_video.h"
#include "media/filters/tizen/omx/omx_facade.h"
class OmxFacadeVideo : public DecoderFacadeVideo, public OmxFacade {
public:
- explicit OmxFacadeVideo(std::unique_ptr<OmxWrapper> wrapper);
+ explicit OmxFacadeVideo(std::unique_ptr<OmxWrapper> wrapper,
+ const gpu::GpuDriverBugWorkarounds* workarounds);
~OmxFacadeVideo() override = default;
// DecoderFacadeVideo impl.
HdrMetadataCB hdr_metadata_cb_;
ColorSpaceCB color_space_cb_;
+ const gpu::GpuDriverBugWorkarounds workarounds_;
+
base::WeakPtr<OmxFacadeVideo> weak_this_;
base::WeakPtrFactory<OmxFacadeVideo> weak_factory_{this};
};
OmxFacadeVideoTest() {
auto wrapper = std::make_unique<testing::NiceMock<MockOmxWrapper>>();
mock_omx_wrapper_ = wrapper.get();
- facade_ = std::make_unique<OmxFacadeVideo>(std::move(wrapper));
+ facade_ = std::make_unique<OmxFacadeVideo>(std::move(wrapper), nullptr);
memset(&decoded_spec_, 0, sizeof(decoded_spec_));
}
TTvdVideoDecoder::TTvdVideoDecoder(
base::RepeatingCallback<gpu::CommandBufferStub*()> get_command_buffer_cb,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
- base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
- get_video_facade_cb,
+ base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+ const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb,
const gpu::GpuDriverBugWorkarounds& workarounds)
: workarounds_(workarounds),
decoder_thread_("ttvd_decoder_thread"),
TTvdVideoDecoder(
base::RepeatingCallback<gpu::CommandBufferStub*()> get_command_buffer_cb,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
- base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
- get_video_facade_cb,
+ base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+ const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb,
const gpu::GpuDriverBugWorkarounds& workarounds);
~TTvdVideoDecoder() override;
base::Thread decoder_thread_;
base::SequenceBound<TTvdVideoDecoderImpl> decoder_impl_;
- base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
+ base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+ const gpu::GpuDriverBugWorkarounds*)>
get_video_facade_cb_;
base::RepeatingCallback<gpu::CommandBufferStub*()> get_command_buffer_cb_;
namespace media {
TTvdVideoDecoderBase::TTvdVideoDecoderBase(
- base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
- get_video_facade_cb)
+ base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+ const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb)
: get_video_facade_cb_(std::move(get_video_facade_cb)),
weak_self_(weak_factory_.GetWeakPtr()) {}
TTvdVideoDecoderBase::~TTvdVideoDecoderBase() {
allocated_decoder_ = std::move(decoder);
init_cb_ = std::move(init_cb);
- decoder_facade_ = get_video_facade_cb_.Run();
+ decoder_facade_ = get_video_facade_cb_.Run(nullptr);
decoder_facade_->Initialize(
codec, coded_size, low_delay, false /* secure_mode */,
allocated_decoder_->decoding_mode, allocated_decoder_->component_name,
class MEDIA_EXPORT TTvdVideoDecoderBase {
public:
explicit TTvdVideoDecoderBase(
- base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
- get_video_facade_cb);
+ base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+ const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb);
~TTvdVideoDecoderBase();
void Initialize(MediaVideoCodec codec,
};
std::list<Decoding> decoding_requests_;
- base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
+ base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+ const gpu::GpuDriverBugWorkarounds*)>
get_video_facade_cb_;
base::WeakPtrFactory<TTvdVideoDecoderBase> weak_factory_{this};
GetCommandbufferCB get_command_buffer_cb,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> decoder_task_runner,
- base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
- get_video_facade_cb,
+ base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+ const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb,
const gpu::GpuDriverBugWorkarounds& workarounds)
: workarounds_(workarounds),
last_processing_frame_(
render_data.timestamp = ttvd_decoded_frame->Timestamp();
render_data.low_latency = config_.is_rtc();
render_data.collection_token = collection_token_;
+
+ // As we're about to render buffer that already sits in decoded queue
+ // (comparing to the rendering just decoded frame), we cannot be sure that
+ // data provided by facade is still valid (refers to this specific frame),
+ // so just skip rendering. It should not affect negatively on rendering,
+ // just potentially increase delay (1 frame) for normal latency playbback.
render_cb_.Run(render_data);
}
<< "Not supported video codec: " << config_.codec();
}
- decoder_facade_ = get_video_facade_cb_.Run();
+ decoder_facade_ = get_video_facade_cb_.Run(&workarounds_);
const bool is_secure_mode = cdm_bridge_ != nullptr;
decoder_facade_->Initialize(
codec, config_.coded_size(), low_delay_, is_secure_mode,
render_data.timestamp = output_data.timestamp;
render_data.low_latency = config_.is_rtc();
render_data.collection_token = collection_token_;
+
+ if (supports_software_rendering_) {
+ render_data.nv12_data = &output_data.nv12_data;
+ }
render_cb_.Run(render_data);
pending_render_ = false;
}
render_data.timestamp = output_data.timestamp;
render_data.low_latency = config_.is_rtc();
render_data.collection_token = collection_token_;
+ if (supports_software_rendering_) {
+ render_data.nv12_data = &output_data.nv12_data;
+ }
if (surface_prepare_cb_) {
TIZEN_MEDIA_LOG(INFO) << "Prepare surface with first frame";
allocated_decoder_->decoding_mode != DecodingMode::kDecodingNormal) &&
!cdm_bridge_;
+ supports_software_rendering_ = supports_texturing;
supports_overlay_ =
(allocated_decoder_->decoding_mode == DecodingMode::kDecodingNormal);
GetCommandbufferCB get_command_buffer_cb,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> decoder_task_runner,
- base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
- get_video_facade_cb,
+ base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+ const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb,
const gpu::GpuDriverBugWorkarounds& workarounds);
~TTvdVideoDecoderImpl();
std::deque<scoped_refptr<TTvdDecodedFrame>> ttvd_decoded_frame_pool_;
bool supports_texturing_ = false;
+ bool supports_software_rendering_ = false;
bool supports_overlay_ = false;
gfx::VideoOutputMode output_mode_ = gfx::VideoOutputMode::kUnknown;
// decoder buffer. See |unique_id| in |DecodingRequest| structure.
DecoderFacade::DecodingUniqueId next_decode_unique_id_ = 0;
- base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
+ base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+ const gpu::GpuDriverBugWorkarounds*)>
get_video_facade_cb_;
GetCommandbufferCB get_command_buffer_cb_;
}
}
+tizen_pkg_config("video-mm-control") {
+ packages = []
+ if (tizen_tv_upstream_multimedia) {
+ packages = [ "video-mm-control" ]
+ }
+}
+
config("notification") {
if (is_tizen) {
ldflags = [ "-lnotification" ]
#include <capi-graphics-control.h>
#include <tbm_type_common.h>
+
#include <cstring>
#include "base/files/scoped_file.h"
#include "tizen_src/chromium_impl/ui/gfx/tbm_utils.h"
+#include "ui/gfx/tizen_gpu_buffer.h"
namespace gfx {
return std::make_unique<TizenGpuBuffer>(std::move(bufmgr), std::move(bo));
}
+std::unique_ptr<TizenGpuBuffer> TizenGpuBuffer::AllocateForDisplay(
+ size_t size,
+ size_t plane_type,
+ size_t plane,
+ size_t index) {
+ auto bufmgr = TbmBufMgrType(tbm_bufmgr_init(-1));
+ if (!bufmgr) {
+ return nullptr;
+ }
+
+ constexpr const int kDisplayMemoryType = 1 << 16;
+ const int plane_type_bits = (plane_type == 0 ? 2 : 3) << 20;
+
+ const int plane_index = plane << 3;
+ const int plane_bits = (plane_index | index) << 24;
+
+ const int mode = kDisplayMemoryType | plane_type_bits | plane_bits;
+ auto bo = TbmBOType(tbm_bo_alloc(bufmgr.get(), size, mode));
+ if (!bo) {
+ return nullptr;
+ }
+ return std::make_unique<TizenGpuBuffer>(std::move(bufmgr), std::move(bo));
+}
+
std::unique_ptr<TizenGpuBuffer> TizenGpuBuffer::ImportFromFd(
const base::ScopedFD& fd) {
auto bufmgr = TbmBufMgrType(tbm_bufmgr_init(-1));
bool TizenGpuBuffer::CopyFrom(uint32_t phys_addr,
int stride,
+ int dst_stride,
int width,
int height) {
tbm_bo_handle handle = tbm_bo_get_handle(bo_.get(), TBM_DEVICE_2D);
// dst info
ga_info.dst_handle = handle.u32;
- ga_info.dst_hbytesize = width;
+ ga_info.dst_hbytesize = dst_stride;
ga_info.dst_rect.x = 0;
ga_info.dst_rect.y = 0;
static std::unique_ptr<TizenGpuBuffer> Allocate(size_t size,
bool use_for_scanout);
+ static std::unique_ptr<TizenGpuBuffer> AllocateForDisplay(size_t size,
+ size_t plane_type,
+ size_t plane,
+ size_t index);
static std::unique_ptr<TizenGpuBuffer> ImportFromFd(const base::ScopedFD& fd);
bool Map(AccessMode);
bool Unmap();
base::ScopedFD ExportFd();
- bool CopyFrom(uint32_t phys_addr, int stride, int width, int height);
+ bool CopyFrom(uint32_t phys_addr,
+ int stride,
+ int dst_stride,
+ int width,
+ int height);
bool Scale(uint32_t phys_addr,
int stride,
int width,
size_t UniqueId() const { return std::hash<TbmBOType>{}(bo_); }
+ TbmBOType Release() { return std::move(bo_); }
+
private:
// GCC compiler requires namespace specification for `Tbm*` wrappers,
// otherwise compile error is being reported.
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "gpu/command_buffer/common/mailbox.h"
+#include "media/filters/tizen/nv12_data.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/video_output_mode.h"
base::TimeDelta timestamp;
base::UnguessableToken collection_token;
+ // Available only with specific decoders, |nullptr| value means it
+ // does not support software rendering.
+ media::NV12Data* nv12_data = nullptr;
+
bool low_latency = false;
};
configs += [
"//tizen_src/build:tizen-extension-client",
"//tizen_src/build:tizen-hwc-client",
+ "//tizen_src/build:video-mm-control",
"//tizen_src/build:video-render-ctrl-c-glue",
]
sources += [
"tizen_native_pixmap.h",
"video_surface.cc",
"video_surface.h",
+ "video_rendering.h",
+ "video_rendering_direct.cc",
+ "video_rendering_direct.h",
+ "video_rendering_software.cc",
+ "video_rendering_software.h",
"wayland_object.cc",
"wayland_object.h",
]
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/efl/video_rendering_direct.h"
+#include "ui/ozone/platform/efl/video_rendering_software.h"
// This may happen on older tizens (e.g. 6.0) due to using the same
// include header guard `_DRM_MODE_H` by different headers.
gfx::ScaleRect(crop_rect, image_size.width(), image_size.height())));
return {screen_rect, picture_rect};
}
+
+bool IsSoftwareRenderingCapable(const gfx::OverlayRenderData& render_data) {
+ return render_data.nv12_data != nullptr &&
+ render_data.nv12_data->y_phys_data != 0 &&
+ render_data.nv12_data->y_stride != 0 &&
+ render_data.nv12_data->uv_phys_data != 0 &&
+ render_data.nv12_data->uv_stride != 0;
+}
} // namespace
OutputSurfaceImpl::OutputSurfaceImpl(
int device_id,
const RenderingWorkarounds& rendering_workarounds)
: video_surface_(device_id, rendering_workarounds),
- rendering_workarounds_(rendering_workarounds){};
+ rendering_workarounds_(rendering_workarounds) {}
OutputSurfaceImpl::~OutputSurfaceImpl() {
TIZEN_MEDIA_LOG(INFO) << "Destroy output surface impl";
}
if (pending_source_change_ || !last_picture_plane_) {
- video_surface_.UsePlane(render_data.plane_id);
+ if (IsSoftwareRenderingCapable(render_data) && render_data.low_latency &&
+ rendering_workarounds_.prefer_manual_rendering_for_low_latency) {
+ TIZEN_MEDIA_LOG(INFO) << "Use software video rendering method";
+ current_rendering_method_ = rendering_software_.get();
+ } else {
+ TIZEN_MEDIA_LOG(INFO) << "Use direct video rendering method";
+ current_rendering_method_ = rendering_direct_.get();
+ }
+
+ video_surface_.PreparePlane(render_data, current_rendering_method_);
}
// Ensure that new values are set before returning due to the wrong
TIZEN_MEDIA_LOG(VERBOSE) << "Display: " << geometry_.picture.ToString()
<< " on: " << geometry_.screen.ToString();
-
- if (!video_surface_.Render(render_data.plane_id)) {
- TIZEN_MEDIA_LOG(ERROR) << "Error displaying picture";
- return;
- }
- return;
+ video_surface_.RenderPlane(render_data, current_rendering_method_);
}
void OutputSurfaceImpl::SetBelow(OutputSurfaceImpl& above) {
res_data.color_ycbcr = 0;
res_data.colorimetry = AVOC_COLORIMETRY_NODATA;
res_data.rgb_range = ConvertColorRange(color_space_.GetRangeID());
- res_data.netflix_max_v_size = 1920;
- res_data.netflix_max_h_size = 1080;
+ res_data.netflix_max_h_size = 1920;
+ res_data.netflix_max_v_size = 1080;
res_data.video_pack = 0;
res_data.res_screen_mirroring = 0;
+#if TIZEN_VERSION_AT_LEAST(7, 0, 0)
+ if (use_game_mode) {
+ res_data.sub_source_mode = AVOC_SUB_SOURCE_UNIPLAYER_CLOUD_GAME;
+ } else {
+ res_data.sub_source_mode = AVOC_SUB_SOURCE_UNIPLAYER_OTT;
+ }
+#else
res_data.sub_source_mode = AVOC_SUB_SOURCE_UNIPLAYER_OTT;
+#endif // TIZEN_VERSION_AT_LEAST(7, 0, 0)
res_data.graphic_mode = 0;
res_data.freesync_max_vfreq = 0;
res_data.hdmi_dsc = 0;
return false;
}
+ rendering_software_ = std::make_unique<VideoRenderingSoftware>(plane_);
+ rendering_direct_ = std::make_unique<VideoRenderingDirect>(plane_);
+
return true;
}
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/hdr_metadata.h"
+#include "ui/gfx/tizen_gpu_buffer.h"
#include "ui/gfx/tizen_overlay_plane.h"
#include "ui/ozone/platform/efl/output_surface.h"
#include "ui/ozone/platform/efl/rendering_workarounds.h"
+#include "ui/ozone/platform/efl/video_rendering.h"
#include "ui/ozone/platform/efl/video_surface.h"
namespace ui {
void SetBelow(OutputSurfaceImpl& above);
private:
-
void EnableSeqMode(bool enabled);
void SetHdrMetadata(gfx::HDRMetadata hdr_metadata);
absl::optional<bool> low_latency_source_;
bool has_decoded_frame_ = false;
+ std::unique_ptr<VideoRendering> rendering_software_;
+ std::unique_ptr<VideoRendering> rendering_direct_;
+ VideoRendering* current_rendering_method_ = nullptr;
+
VideoSurface video_surface_;
Plane plane_;
gpu_driver_workarounds.replace_rotate_180_with_hv_flip;
result.limit_rotation_to_single_plane =
gpu_driver_workarounds.limit_rotation_to_single_plane;
+ result.prefer_manual_rendering_for_low_latency =
+ gpu_driver_workarounds.ttvd_prefer_manual_rendering_for_low_latency;
return result;
}
bool rotation_180_degrees_workaround = false;
bool replace_rotate_180_with_hv_flip = false;
bool limit_rotation_to_single_plane = false;
+ bool prefer_manual_rendering_for_low_latency = false;
};
RenderingWorkarounds ConvertToRenderingWorkarounds(
--- /dev/null
+// Copyright 2024 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 UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_H_
+#define UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_H_
+
+#include <avoc/avoc_defs.h>
+#include <tbm_bo.h>
+#include <tbm_type.h>
+#include <tbm_type_common.h>
+#include <video-sink-defs.h>
+#include <wayland-extension/tizen-hwc-client-protocol.h>
+
+#include "base/containers/flat_map.h"
+#include "base/functional/callback_helpers.h"
+#include "tizen_src/chromium_impl/build/tizen_version.h"
+#include "tizen_src/chromium_impl/ui/gfx/tbm_utils.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/hdr_metadata.h"
+#include "ui/ozone/platform/efl/output_surface.h"
+#include "ui/ozone/platform/efl/rendering_workarounds.h"
+#include "ui/ozone/platform/efl/wayland_object.h"
+
+#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
+#include <video-common-defs.h>
+#else
+#include <ivideo-renderer.hpp>
+#include <ivideo-swdec.hpp>
+#endif
+
+namespace ui {
+
+#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
+using FrameInfo = VideoSink_SetPlaneInfo;
+#else
+using FrameInfo = IVideoRenderer::SetPlaneInfo;
+#endif // TIZEN_VERSION_AT_LEAST(8, 0, 0)
+
+class VideoRendering {
+ public:
+ VideoRendering(OutputSurface::Plane plane) : plane_(plane) {}
+ virtual ~VideoRendering() = default;
+
+ virtual VideoSink_SrcBufferTypes GetType() const = 0;
+ // Called by client every time we're preparing for rendering video
+ // decoded by new decoder.
+ virtual gfx::TbmBOType PreparePlane(const gfx::OverlayRenderData& render_data,
+ void* video_sink,
+ void* bufmgr) = 0;
+ // Implementation should fill |frame_info| with values specific for
+ // rendering method.
+ virtual void PrepareForRenderingFrame(
+ FrameInfo* frame_info,
+ const gfx::OverlayRenderData& render_data) = 0;
+
+ protected:
+ OutputSurface::Plane plane_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_H_
--- /dev/null
+// Copyright 2024 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 "ui/ozone/platform/efl/video_rendering_direct.h"
+
+namespace ui {
+
+gfx::TbmBOType VideoRenderingDirect::PreparePlane(
+ const gfx::OverlayRenderData& render_data,
+ void* video_sink,
+ void* bufmgr) {
+ return gfx::TbmBOType{tbm_bo_import_fd(reinterpret_cast<tbm_bufmgr>(bufmgr),
+ render_data.plane_id)};
+}
+
+void VideoRenderingDirect::PrepareForRenderingFrame(
+ FrameInfo* frame_info,
+ const gfx::OverlayRenderData& render_data) {
+ // We need to use |v4l2_drm| as there's no other structure that
+ // matches with the layout. Platform library interally casts
+ // to this structure so no other solution is possible.
+ v4l2_info_.plane = render_data.plane_id;
+ v4l2_info_.reserved = 0x1234ABCD;
+
+#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
+ frame_info->v4l2_ptr = &v4l2_info_;
+#else
+ // |VideoBufMetaData| does not match |v4l2_drm|, that's why we need to do
+ // it this way.
+ frame_info->metadata =
+ reinterpret_cast<IVideoRenderer::VideoBufMetaData*>(&v4l2_info_);
+#endif
+
+ // Do not set seamless resolution for now.
+ frame_info->max_hres = -1;
+ frame_info->max_vres = -1;
+}
+
+} // namespace ui
--- /dev/null
+// Copyright 2024 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 UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_DIRECT_H_
+#define UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_DIRECT_H_
+
+#include <avoc/avoc_defs.h>
+#include <libdrm/drm_mode.h>
+#include <linux/videodev2_tztv.h>
+#include <tbm_bo.h>
+#include <tbm_type.h>
+#include <tbm_type_common.h>
+#include <tztv-kernel-headers/drm/drm_mode.h>
+#include <video-sink-defs.h>
+#include <wayland-extension/tizen-hwc-client-protocol.h>
+
+#include "tizen_src/chromium_impl/ui/gfx/tbm_utils.h"
+#include "ui/ozone/platform/efl/output_surface.h"
+#include "ui/ozone/platform/efl/video_rendering.h"
+
+namespace ui {
+
+class VideoRenderingDirect : public VideoRendering {
+ public:
+ explicit VideoRenderingDirect(OutputSurface::Plane plane)
+ : VideoRendering(plane) {}
+ ~VideoRenderingDirect() override = default;
+
+ VideoSink_SrcBufferTypes GetType() const override {
+ return VIDEOSINK_SRC_BUFFER_HW;
+ };
+ gfx::TbmBOType PreparePlane(const gfx::OverlayRenderData& render_data,
+ void* video_sink,
+ void* bufmgr) override;
+ void PrepareForRenderingFrame(
+ FrameInfo* frame_info,
+ const gfx::OverlayRenderData& render_data) override;
+
+ private:
+ v4l2_drm v4l2_info_{};
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_DIRECT_H_
--- /dev/null
+// Copyright 2024 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 "ui/ozone/platform/efl/video_rendering_software.h"
+
+#include <tbm_surface_internal.h>
+#include <video-render-ctrl-c-glue.h>
+#include <ivideo-dp-control.hpp>
+
+#include "media/base/tizen/logger/media_logger.h"
+#include "ui/gfx/tbm_utils.h"
+#include "ui/gfx/tizen_gpu_buffer.h"
+
+namespace ui {
+
+namespace {
+constexpr const size_t kDefaultFramerate = 60 * 100;
+constexpr const uint32_t kProgressiveScanType = 1;
+
+IVideoDpControl::ScalerIndex PlaneToScalerIndex(OutputSurface::Plane plane) {
+ switch (plane) {
+ case OutputSurface::Plane::kMain:
+ return IVideoDpControl::VIDEO_MAIN_SCALER;
+ case OutputSurface::Plane::kSub:
+ return IVideoDpControl::VIDEO_SUB_SCALER;
+ case OutputSurface::Plane::kSub2:
+ return IVideoDpControl::VIDEO_SUB2_SCALER;
+ case OutputSurface::Plane::kSub3:
+ return IVideoDpControl::VIDEO_BG_SCALER;
+ }
+ return IVideoDpControl::VIDEO_MAX_SCALER;
+}
+
+size_t PlaneToIndex(OutputSurface::Plane plane) {
+ switch (plane) {
+ case OutputSurface::Plane::kMain:
+ return 0;
+ case OutputSurface::Plane::kSub:
+ return 1;
+ case OutputSurface::Plane::kSub2:
+ return 2;
+ case OutputSurface::Plane::kSub3:
+ return 3;
+ }
+ // We should not reach here, keep it to suppress warnings.
+ return 0;
+}
+} // namespace
+
+VideoRenderingSoftware::VideoRenderingSoftware(OutputSurface::Plane plane)
+ : VideoRendering(plane) {
+ IVideoDpControl::getInstance()->getFrameBufferProp(
+ IVideoDpControl::VIDEO_Y_FB_BYTEPERLINE, PlaneToScalerIndex(plane_),
+ IVideoDpControl::COLOR_FMT_YC420, &fb_bytes_per_line_);
+}
+
+gfx::TbmBOType VideoRenderingSoftware::PreparePlane(
+ const gfx::OverlayRenderData& render_data,
+ void* video_sink,
+ void* bufmgr) {
+ constexpr const size_t kMaxDisplayBuffers = 8;
+
+ for (size_t i = display_buffers_.size(); i < kMaxDisplayBuffers; ++i) {
+ constexpr size_t kPlaneY = 0;
+ constexpr size_t kPlaneUV = 1;
+ // Actual allocation size does not matter, any value might be provided.
+ auto y_buffer = gfx::TizenGpuBuffer::AllocateForDisplay(
+ fb_bytes_per_line_, kPlaneY, PlaneToIndex(plane_), i);
+ if (!y_buffer) {
+ break;
+ }
+
+ auto uv_buffer = gfx::TizenGpuBuffer::AllocateForDisplay(
+ fb_bytes_per_line_ / 2, kPlaneUV, PlaneToIndex(plane_), i);
+ if (!uv_buffer) {
+ break;
+ }
+
+ display_buffers_.emplace_back(
+ DisplayBuffers{.y = std::move(y_buffer), .uv = std::move(uv_buffer)});
+ }
+
+ TIZEN_MEDIA_LOG(INFO) << "Allocated buffers for software rendering: "
+ << display_buffers_.size();
+
+ constexpr const size_t kMetaBufferSize = 4096;
+ auto tbm_bo = gfx::TizenGpuBuffer::Allocate(kMetaBufferSize, false);
+ if (!tbm_bo) {
+ TIZEN_MEDIA_LOG(ERROR) << "Cannot allocate meta buffer";
+ return nullptr;
+ }
+
+ if (!tbm_bo->Map(gfx::TizenGpuBuffer::AccessMode::kReadWrite)) {
+ TIZEN_MEDIA_LOG(ERROR) << "Cannot map meta buffer";
+ return nullptr;
+ }
+
+ constexpr const uint32_t kInvalidDisplayIndex = 0xffffffff;
+#if TIZEN_VERSION_AT_LEAST(7, 0, 0)
+ VideoSink_DecInfo dec_info{};
+ dec_info.width = render_data.picture_size.width();
+ dec_info.height = render_data.picture_size.height();
+ dec_info.framerate = kDefaultFramerate;
+ dec_info.colorformat = VIDEOSINK_DRM_COLORFORMAT_YUV420;
+ dec_info.scantype = kProgressiveScanType;
+ dec_info.display_index = kInvalidDisplayIndex;
+
+ if (videoRenderCtrl_getBufferMetaData(video_sink, &dec_info,
+ tbm_bo->Memory()) != 0) {
+ TIZEN_MEDIA_LOG(ERROR) << "Error when setting SW renderer metadata";
+ return nullptr;
+ }
+#else
+ IVideoSWDec::DecInfo dec_info{};
+ dec_info.width = render_data.picture_size.width();
+ dec_info.height = render_data.picture_size.height();
+ dec_info.framerate = kDefaultFramerate;
+ dec_info.colorformat = IVideoSWDec::COLORFORMAT_YUV420;
+ dec_info.scantype = kProgressiveScanType;
+ dec_info.display_index = kInvalidDisplayIndex;
+
+ if (IVideoSWDec::getInstance()->getBufferMetaData(
+ &dec_info, reinterpret_cast<IVideoRenderer::VideoBufMetaData*>(
+ tbm_bo->Memory())) != 0) {
+ TIZEN_MEDIA_LOG(ERROR) << "Error when setting SW renderer metadata";
+ return nullptr;
+ }
+#endif // TIZEN_VERSION_AT_LEAST(7, 0, 0)
+
+ if (!tbm_bo->Unmap()) {
+ TIZEN_MEDIA_LOG(ERROR) << "Cannot unmap meta buffer";
+ return nullptr;
+ }
+
+ return tbm_bo->Release();
+}
+
+void VideoRenderingSoftware::PrepareForRenderingFrame(
+ FrameInfo* frame_info,
+ const gfx::OverlayRenderData& render_data) {
+ if (!render_data.nv12_data) {
+ TIZEN_MEDIA_LOG(WARNING) << "No rendering data source";
+ return;
+ }
+
+ current_index_ += 1;
+ if (current_index_ >= display_buffers_.size()) {
+ current_index_ = 0;
+ }
+
+ display_buffers_[current_index_].y->CopyFrom(
+ render_data.nv12_data->y_phys_data, render_data.nv12_data->y_stride,
+ fb_bytes_per_line_, render_data.picture_size.width(),
+ render_data.picture_size.height());
+ display_buffers_[current_index_].uv->CopyFrom(
+ render_data.nv12_data->uv_phys_data, render_data.nv12_data->uv_stride,
+ fb_bytes_per_line_, render_data.picture_size.width(),
+ render_data.picture_size.height() / 2);
+
+ dec_info_.width = render_data.picture_size.width();
+ dec_info_.height = render_data.picture_size.height();
+ dec_info_.framerate = kDefaultFramerate;
+ dec_info_.scantype = kProgressiveScanType;
+ dec_info_.display_index = current_index_;
+
+#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
+ dec_info_.colorformat = VIDEORCTRL_COLORFORMAT_YUV420;
+ dec_info_.stereoscopic_info = VIDEOCTRL_STEREOSCOPIC_2D;
+
+ frame_info->v4l2_ptr = &dec_info_;
+#else
+ dec_info_.colorformat = IVideoSWDec::COLORFORMAT_YUV420;
+ dec_info_.stereoscopic_info = IVideoSWDec::STEREOSCOPIC_2D;
+
+ // See above why it's needed. |VideoBufMetaData| does not match |v4l2_drm|.
+ frame_info->metadata =
+ reinterpret_cast<IVideoRenderer::VideoBufMetaData*>(&dec_info_);
+#endif
+
+ frame_info->sw_hres = render_data.picture_size.width();
+ frame_info->sw_vres = render_data.picture_size.height();
+}
+
+} // namespace ui
--- /dev/null
+// Copyright 2024 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 UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_SOFTWARE_H_
+#define UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_SOFTWARE_H_
+
+#include <avoc/avoc_defs.h>
+#include <tbm_bo.h>
+#include <tbm_surface.h>
+#include <tbm_type.h>
+#include <tbm_type_common.h>
+#include <video-sink-defs.h>
+#include <wayland-extension/tizen-hwc-client-protocol.h>
+
+#include "ui/gfx/tizen_gpu_buffer.h"
+#include "ui/ozone/platform/efl/output_surface.h"
+#include "ui/ozone/platform/efl/video_rendering.h"
+
+namespace ui {
+
+class VideoRenderingSoftware : public VideoRendering {
+ public:
+ explicit VideoRenderingSoftware(OutputSurface::Plane plane);
+ ~VideoRenderingSoftware() override = default;
+
+ VideoSink_SrcBufferTypes GetType() const override {
+ return VIDEOSINK_SRC_BUFFER_SW;
+ };
+ gfx::TbmBOType PreparePlane(const gfx::OverlayRenderData& render_data,
+ void* video_sink,
+ void* bufmgr) override;
+ void PrepareForRenderingFrame(
+ FrameInfo* frame_info,
+ const gfx::OverlayRenderData& render_data) override;
+
+ private:
+ int fb_bytes_per_line_ = 0;
+
+ size_t current_index_ = 0;
+ struct DisplayBuffers {
+ std::unique_ptr<gfx::TizenGpuBuffer> y;
+ std::unique_ptr<gfx::TizenGpuBuffer> uv;
+ };
+ std::vector<DisplayBuffers> display_buffers_;
+
+#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
+ VideoCtrlDecInfo_s dec_info_;
+#else
+ IVideoSWDec::DecInfo dec_info_;
+#endif // TIZEN_VERSION_AT_LEAST(8, 0, 0)
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_SOFTWARE_H_
#include "tizen_src/chromium_impl/ui/gfx/tbm_utils.h"
#include "ui/ozone/platform/efl/efl_window.h"
-#if !TIZEN_VERSION_AT_LEAST(8, 0, 0)
-#include <ivideo-renderer.hpp>
-#endif
-
namespace {
// TODO(vdwasm) Currently graphics resolution is capped to 1920x1080.
return false;
}
- res = videoRenderCtrl_setSrcBufferType(video_sink_.get(),
- VIDEOSINK_SRC_BUFFER_HW);
- if (res != 0) {
- TIZEN_MEDIA_LOG(ERROR) << "Cannot set video sink buffer type, error: "
- << res;
- return false;
- }
-
return true;
}
pending_commit_feedbacks_.erase(it);
}
-void VideoSurface::UsePlane(int plane_id) {
- TIZEN_MEDIA_LOG(VERBOSE) << "Use plane: " << plane_id;
+void VideoSurface::PreparePlane(const gfx::OverlayRenderData& render_data,
+ VideoRendering* renderer) {
+ TIZEN_MEDIA_LOG(VERBOSE) << "Use plane: " << render_data.plane_id;
auto temp_surface = std::move(tbm_surface_);
auto temp_bo = std::move(tbm_bo_);
return;
}
- tbm_bo_ = gfx::TbmBOType{
- tbm_bo_import_fd(reinterpret_cast<tbm_bufmgr>(bufmgr), plane_id)};
- if (!tbm_bo_) {
+ // Set new buffer type that could change from the last one used.
+ int res =
+ videoRenderCtrl_setSrcBufferType(video_sink_.get(), renderer->GetType());
+ if (res != 0) {
+ TIZEN_MEDIA_LOG(ERROR) << "Cannot set video sink buffer type, error: "
+ << res;
+ }
+
+ auto tbm_bo = renderer->PreparePlane(render_data, video_sink_.get(), bufmgr);
+ if (!tbm_bo) {
TIZEN_MEDIA_LOG(ERROR) << "Cannot import video tbm_bo";
return;
}
+
+ // Dummy frame buffer size. It's not really used for rendering, just to
+ // notify renderer with metadata from the buffer object underneath what
+ // should be rendered.
+ constexpr const size_t kFrameBufferSize = 4096;
tbm_surface_info_s ts_info;
- ts_info.width = 4096;
- ts_info.height = 4096;
+ ts_info.width = kFrameBufferSize;
+ ts_info.height = kFrameBufferSize;
ts_info.format = TBM_FORMAT_XRGB8888;
- ts_info.bpp = 4096;
+ ts_info.bpp = tbm_surface_internal_get_bpp(ts_info.format);
ts_info.num_planes = 1;
- ts_info.planes[0].stride = 4096 * 4;
+ ts_info.planes[0].stride = kFrameBufferSize * 4;
ts_info.planes[0].offset = 0;
- auto tbm_bo_raw = tbm_bo_.get();
- tbm_surface_ = gfx::TbmSurfaceType{
+ auto tbm_bo_raw = tbm_bo.get();
+ auto tbm_surface = gfx::TbmSurfaceType{
tbm_surface_internal_create_with_bos(&ts_info, &tbm_bo_raw, 1)};
- if (!tbm_surface_) {
+ if (!tbm_surface) {
TIZEN_MEDIA_LOG(ERROR) << "Cannot create tbm surface for video";
return;
}
+
+ tbm_bo_ = std::move(tbm_bo);
+ tbm_surface_ = std::move(tbm_surface);
+
buffer_.reset(
wayland_tbm_client_create_buffer(tbm_client, tbm_surface_.get()));
if (!buffer_) {
// In case of same |plane_id| used, we need to ensure that framebuffer is
// recreated correctly. To do that, use nullptr as data for |renderFrame|.
- if (last_plane_id_ == plane_id) {
+ if (last_plane_id_ == render_data.plane_id) {
TIZEN_MEDIA_LOG(INFO) << "Reset video surface for same plane";
if (videoRenderCtrl_renderFrame(video_sink_.get(), nullptr) != 0) {
TIZEN_MEDIA_LOG(ERROR)
<< "Error when reseting video surface for same plane";
}
}
- last_plane_id_ = plane_id;
+ last_plane_id_ = render_data.plane_id;
}
void VideoSurface::Hide() {
WaitForCallbacksToFinish();
}
-bool VideoSurface::Render(uint32_t plane_id) {
+bool VideoSurface::RenderPlane(const gfx::OverlayRenderData& render_data,
+ VideoRendering* renderer) {
// If geometry of plane to be used has changed, we need to go through
// platform compositor path, so changes for subsurface are applied.
if (full_commit_pending_) {
WaitForCallbacksToFinish();
}
- // We need to use |v4l2_drm| as there's no other structure that
- // matches with the layout. Platform library interally casts
- // to this structure so no other solution is possible.
- v4l2_drm v4l2_info{};
- v4l2_info.plane = plane_id;
- v4l2_info.reserved = 0x1234ABCD;
-
-#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
- VideoSink_SetPlaneInfo frame_info{};
- frame_info.v4l2_ptr = &v4l2_info;
-#else
- IVideoRenderer::SetPlaneInfo frame_info{};
- // See above why it's needed. |VideoBufMetaData| does not match |v4l2_drm|.
- frame_info.metadata =
- reinterpret_cast<IVideoRenderer::VideoBufMetaData*>(&v4l2_info);
-#endif
-
- // Do not set seamless resolution for now.
- frame_info.max_hres = -1;
- frame_info.max_vres = -1;
+ FrameInfo frame_info{};
+ renderer->PrepareForRenderingFrame(&frame_info, render_data);
return videoRenderCtrl_renderFrame(video_sink_.get(), &frame_info) == 0;
}
#include "ui/gfx/hdr_metadata.h"
#include "ui/ozone/platform/efl/output_surface.h"
#include "ui/ozone/platform/efl/rendering_workarounds.h"
+#include "ui/ozone/platform/efl/video_rendering.h"
#include "ui/ozone/platform/efl/wayland_object.h"
class IVideoSink;
absl::optional<gfx::Rect> destination,
absl::optional<gfx::OverlayTransform> transform);
- void UsePlane(int plane_id);
+ void PreparePlane(const gfx::OverlayRenderData& render_data,
+ VideoRendering* renderer);
void Hide();
- bool Render(uint32_t plane_id);
+ bool RenderPlane(const gfx::OverlayRenderData& render_data,
+ VideoRendering* renderer);
bool SetResolution(const avoc_tpt_resolution_s& data);
bool SetPreResolution(const avoc_tpt_resolution_s& data);