- Remove unnecessary comments.
[Version] 0.1.2
[Issue Type] Add feature
Change-Id: I4ba3a0d150fe4ba49a4890e52997439f483a7270
Name: libtrackrenderer
Summary: new multimedia streaming player trackrenderer
-Version: 0.1.1
+Version: 0.1.2
Release: 0
Group: Multimedia/Libraries
License: Apache-2.0
BuildRequires: pkgconfig(libtbm)
BuildRequires: pkgconfig(libpulse)
BuildRequires: pkgconfig(capi-media-sound-manager)
+BuildRequires: pkgconfig(mm-display-interface)
+BuildRequires: pkgconfig(capi-media-tool)
BuildRequires: gtest-devel
BuildRequires: gtest
"jsoncpp"
"capi-system-info"
"resource-manager resource-center-api"
- "capi-media-sound-manager libpulse")
+ "capi-media-sound-manager libpulse"
+ "mm-display-interface capi-media-tool")
INCLUDE(FindPkgConfig)
${PROJECT_SOURCE_DIR}/gstobject_guard.cpp
${PROJECT_SOURCE_DIR}/gstsignal_holder.cpp
${PROJECT_SOURCE_DIR}/track_util.cpp
+ ${PROJECT_SOURCE_DIR}/mediapacket.cpp
)
ADD_LIBRARY(${fw_name} SHARED ${CC_SRCS})
#include "trackrenderer/core/gstobject_guard.h"
#include "trackrenderer/core/utils/log.h"
+#include "mm_error.h"
+
namespace plusplayer {
namespace trackrenderer {
}
TRACKRENDERER_DEBUG(
- "window geometroy : x(%d) y(%d) width(%d) height(%d) rotation(%d)", *x,
+ "window geometry : x(%d) y(%d) width(%d) height(%d) rotation(%d)", *x,
*y, *width, *height, rotation);
return true;
}
}
+mm_display_type_e ConvertDisplayType(const DisplayType& type) {
+ switch (type) {
+ case DisplayType::kOverlay:
+ return MM_DISPLAY_TYPE_OVERLAY;
+ case DisplayType::kEvas:
+ return MM_DISPLAY_TYPE_EVAS;
+ default:
+ return MM_DISPLAY_TYPE_NONE;
+ }
+}
+
} // namespace internal
-Display::~Display() {}
+
+Display::Display() {
+ if (mm_display_interface_init(&interface_) != MM_ERROR_NONE)
+ TRACKRENDERER_ERROR("mm_display_interface_init() failed");
+}
+
+Display::~Display() {
+ if (!interface_)
+ return;
+
+ if (mm_display_interface_deinit(interface_) != MM_ERROR_NONE)
+ TRACKRENDERER_ERROR("mm_display_interface_deinit() failed");
+
+ interface_ = nullptr;
+}
bool Display::SetDisplay(const DisplayType& type, Evas_Object* obj) {
assert(obj && "obj should not be null");
return false;
}
return SetDisplay_(type, wl_window, x, y, w, h);
+ } else if (type == DisplayType::kEvas && obj_type == "image") {
+ type_ = type;
+ if (mm_display_interface_set_display(interface_, internal::ConvertDisplayType(type_), obj, nullptr) != MM_ERROR_NONE) {
+ TRACKRENDERER_ERROR("mm_display_interface_set_display() failed");
+ return false;
+ }
+
+ mm_display_interface_evas_set_mode(interface_, static_cast<int>(internal::ConvertDisplayModeValue(mode_)));
+ mm_display_interface_evas_set_rotation(interface_, static_cast<int>(rotate_));
+ mm_display_interface_evas_set_visible(interface_, visible_);
} else {
- // TODO(js4716.chun) :
- // else if (type == PLAYER_DISPLAY_TYPE_EVAS &&
- // !strcmp(object_type, "image"))
assert(obj && "not support yet!");
}
TRACKRENDERER_LEAVE;
return false;
}
- // TODO what is mean??
- // wl_window is based on app window(param display).
- // App window already move, so do not need to move wl_window
- // x = 0;
- // y = 0;
-
TRACKRENDERER_LEAVE;
return SetDisplay(type, surfaceid, x, y, w, h);
}
bool Display::SetDisplay(const DisplayType& type, const uint32_t surface_id,
const int x, const int y, const int w, const int h) {
TRACKRENDERER_ENTER;
- // TODO State should not be idle.
- // unsigned int pre_surface_id = surface_id_; // for backup previouse info.
std::lock_guard<std::mutex> lock(settings_mutex_);
TRACKRENDERER_INFO("type: %d, surface_id: %d, x(%d) y(%d) w(%d) h(%d)",
static_cast<int>(type), surface_id, x, y, w, h);
- if (type == DisplayType::kNone) { /* Null serface */
+ if (type == DisplayType::kNone) { /* Null surface */
surface_id_ = 0;
} else if (type == DisplayType::kOverlay) {
surface_id_ = surface_id;
window_.y = y;
window_.w = w;
window_.h = h;
- } else {
- // TODO
- // changing surface case
- // ret = mm_player_change_videosink(handle->mm_handle, mmType, set_handle);
- // if( ret != true) {
- // type = DisplayType::kNone;
- // surface_id_ = pre_surface_id;
- // return false;
- // }
}
- // TODO if We need to change window, how can we update it??
- // display_->Update(pipeline_->video_sink);
-
TRACKRENDERER_LEAVE;
return true;
}
roi_.y, "display-roi-width", roi_.w, "display-roi-height", roi_.h, nullptr);
}
}
+ } else if (type_ == DisplayType::kEvas) {
+ int ret = MM_ERROR_NONE;
+ ret = mm_display_interface_evas_set_mode(interface_, static_cast<int>(internal::ConvertDisplayModeValue(mode_)));
+ if (ret != MM_ERROR_NONE)
+ TRACKRENDERER_ERROR("mm_display_interface_evas_set_mode() failed [%x]", ret);
+
+ ret = mm_display_interface_evas_set_rotation(interface_, static_cast<int>(rotate_));
+ if (ret != MM_ERROR_NONE)
+ TRACKRENDERER_ERROR("mm_display_interface_evas_set_rotation() failed [%x]", ret);
+
+ ret = mm_display_interface_evas_set_visible(interface_, visible_);
+ if (ret != MM_ERROR_NONE)
+ TRACKRENDERER_ERROR("mm_display_interface_evas_set_visible() failed [%x]", ret);
+
+ if (mode_ == DisplayMode::kDstRoi) {
+ if (roi_.w != 0 && roi_.h != 0) {
+ TRACKRENDERER_ERROR("Roi > x[%d] y[%d] w[%d] h[%d]", roi_.x, roi_.y,
+ roi_.w, roi_.h);
+ ret = mm_display_interface_evas_set_roi_area(interface_, roi_.x, roi_.y, roi_.w, roi_.h);
+ if (ret != MM_ERROR_NONE)
+ TRACKRENDERER_ERROR("mm_display_interface_evas_set_roi_area() failed [%x]", ret);
+ }
+ }
}
TRACKRENDERER_LEAVE;
return true;
std::lock_guard<std::mutex> lock(settings_mutex_);
+ TRACKRENDERER_DEBUG("visible: %d", visible_);
if (type_ == DisplayType::kOverlay && surface_id_ != 0) { // waylandsink
- TRACKRENDERER_DEBUG("visible: %d", visible_);
g_object_set(G_OBJECT(videosink), "visible", visible_, nullptr);
+ } else if (type_ == DisplayType::kEvas) {
+ if (mm_display_interface_evas_set_visible(interface_, visible_) != MM_ERROR_NONE)
+ TRACKRENDERER_ERROR("mm_display_interface_evas_set_visible() failed");
}
TRACKRENDERER_LEAVE;
return true;
rotate_ = rotate;
}
+void Display::RenderToEvas(media_packet_h packet)
+{
+ if (mm_display_interface_evas_render(interface_, packet) != MM_ERROR_NONE)
+ TRACKRENDERER_ERROR("mm_display_interface_evas_render() failed");
+}
+
+void Display::FlushDisplay()
+{
+ if (type_ != DisplayType::kEvas)
+ return;
+
+ if (mm_display_interface_evas_set_visible(interface_, false) != MM_ERROR_NONE)
+ TRACKRENDERER_ERROR("mm_display_interface_evas_set_visible() failed");
+
+ if (mm_display_interface_evas_flush(interface_, false) != MM_ERROR_NONE)
+ TRACKRENDERER_ERROR("mm_display_interface_evas_flush() failed");
+}
+
} // namespace trackrenderer
} // namespace plusplayer
#include "Ecore_Wl2.h"
#include "Evas.h"
#include "gst/video/videooverlay.h"
+#include "mm_display_interface.h"
#include "trackrenderer/core/display.h"
#include "trackrenderer/core/gstobject_guard.h"
class Display : private boost::noncopyable {
public:
+ Display();
~Display();
uint32_t GetSurfaceId() const { return surface_id_; }
void SetDisplayMode(const DisplayMode& mode);
void GetDisplayMode(DisplayMode* mode) { *mode = mode_; }
void GetDisplayRotate(DisplayRotation* rotate) { *rotate = rotate_; }
+ void RenderToEvas(media_packet_h packet);
+ void FlushDisplay();
+
private:
bool SetDisplay_(const DisplayType& type, Ecore_Wl2_Window* ecore_wl2_window,
const int x, const int y, const int w, const int h);
DisplayRotation rotate_ = DisplayRotation::kNone;
bool visible_ = true;
std::mutex settings_mutex_;
+ mm_display_interface_h interface_;
};
} // namespace trackrenderer
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_MEDIAPACKET_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_MEDIAPACKET_H__
+
+#include <media_packet.h>
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+
+#include "trackrenderer/core/buffer.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class MediaPacket {
+public:
+ MediaPacket();
+ ~MediaPacket();
+
+ media_packet_h CreatePacket(tbm_surface_h tbm_surf);
+
+private:
+ void MediaPacketDispose(media_packet_h media_packet);
+ bool IsMediaFormatChangeRequired(const tbm_surface_info_s *info);
+ void CreateMediaFormat(const tbm_surface_info_s *info);
+ media_format_mimetype_e ConvertTbmFormatToMediaFormat(tbm_format format);
+
+ media_format_h media_format_;
+}; // class MediaPacket
+
+} // namespace trackrenderer
+
+} // namespace plusplayer
+
+#endif // __PLUSPLAYER_SRC_TRACKRENDERER_MEDIAPACKET_H__
\ No newline at end of file
#include "trackrenderer/core/track.h"
#include "trackrenderer/resource.h"
#include "trackrenderer/resource_conflict_listener.h"
+#include "trackrenderer/mediapacket.h"
#include "trackrenderer/trackrenderer_attr.h"
#include "trackrenderer/trackrenderer_debug.h"
gpointer userdata);
static void GstNeedDataCb_(GstElement* element, guint size,
- gpointer userdata);
+ gpointer userdata);
static void GstEnoughDataCb_(GstElement* element, gpointer userdata);
static gboolean GstSeekDataCb_(GstElement* element, guint64 offset,
- gpointer user_data);
+ gpointer user_data);
static gboolean GstVideoDrmInitDataCb_(int* drmhandle, unsigned int len,
unsigned char* psshdata,
void* userdata);
unsigned char* psshdata,
void* userdata);
static void GstPrerollDecodedVideoBufferCb_(GstElement* element,
- GstBuffer* buffer, GstPad* pad,
- void* userdata);
+ GstBuffer* buffer, GstPad* pad,
+ void* userdata);
static void GstDecodedVideoBufferCb_(GstElement* element,
- GstBuffer* buffer, GstPad* pad,
- void* userdata);
+ GstBuffer* buffer, GstPad* pad,
+ void* userdata);
+ static void GstPrerollEvasRenderVideoBufferCb_(GstElement* element,
+ GstBuffer* buffer, GstPad* pad,
+ void* userdata);
+ static void GstEvasRenderVideoBufferCb_(GstElement* element,
+ GstBuffer* buffer, GstPad* pad,
+ void* userdata);
static void GstCapsNotifyCb_(GstPad* pad,
- GParamSpec* unused, gpointer data);
+ GParamSpec* unused, gpointer data);
static AttributesByElement InitAttributeByElementType_();
static GstPadProbeReturn GstSrcPadProbeBlockCb_(GstPad* pad,
gpointer userdata);
static GstPadProbeReturn GstPadProbeAppsrcEventCb_(GstPad* pad,
- GstPadProbeInfo* info,
- gpointer userdata);
+ GstPadProbeInfo* info,
+ gpointer userdata);
TrackType GetTrackType_(GstElement* element);
bool SetWindowStandAloneMode_(const boost::any& value);
void GstElementLowLatency_(const TrackType& type);
void CreateTbmBufferManager_(const Track* track);
+ void CreateMediaPacketManager_();
void GetResolutionInfo_(EventMsg* event_msg);
bool SetUnlimitedMaxBufferMode_(const boost::any& value);
bool SetVideoPreDisplayMode_(const boost::any& value);
bool is_audioactivated_ = true;
bool need_audio_deactivated_ = false;
std::unique_ptr<TbmBufferManager> tbm_buffer_manager_;
+ std::unique_ptr<MediaPacket> media_packet_manager_;
double playback_rate_ = kDefaultPlaybackRate;
bool is_video_hole_enabled_ = true;
std::string stream_info_;
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media_format.h>
+#include <gst/gst.h>
+#include "trackrenderer/mediapacket.h"
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+MediaPacket::MediaPacket() {
+ media_format_ = nullptr;
+}
+
+MediaPacket::~MediaPacket() {
+ if (media_format_)
+ media_format_unref(media_format_);
+}
+
+bool MediaPacket::IsMediaFormatChangeRequired(const tbm_surface_info_s *info) {
+ media_format_mimetype_e fmtMimetype = MEDIA_FORMAT_NV12;
+ int fmt_width = 0;
+ int fmt_height = 0;
+
+ if (!info) {
+ TRACKRENDERER_ERROR("surface info is null");
+ return true;
+ }
+
+ if (!media_format_)
+ return true;
+
+ if (media_format_get_video_info(media_format_, &fmtMimetype, &fmt_width, &fmt_height, NULL, NULL) != MEDIA_FORMAT_ERROR_NONE)
+ return true;
+
+ if (fmtMimetype == ConvertTbmFormatToMediaFormat(info->format) &&
+ (int)info->width == fmt_width && (int)info->height == fmt_height)
+ return false;
+
+ TRACKRENDERER_DEBUG("format need to change");
+
+ return true;
+}
+
+void MediaPacket::CreateMediaFormat(const tbm_surface_info_s *info) {
+ int ret = 0;
+
+ if (!info) {
+ TRACKRENDERER_ERROR("surface info is null");
+ return;
+ }
+
+ if (media_format_)
+ media_format_unref(media_format_);
+
+ ret = media_format_create(&media_format_);
+ if (ret != MEDIA_FORMAT_ERROR_NONE) {
+ TRACKRENDERER_ERROR("media_format_create failed");
+ return;
+ }
+
+ ret = media_format_set_video_mime(media_format_, ConvertTbmFormatToMediaFormat(info->format));
+ if (ret != MEDIA_FORMAT_ERROR_NONE) {
+ TRACKRENDERER_ERROR("media_format_set_video_mime failed");
+ goto ERROR;
+ }
+
+ ret |= media_format_set_video_width(media_format_, info->width);
+ if (ret != MEDIA_FORMAT_ERROR_NONE) {
+ TRACKRENDERER_ERROR("media_format_set_video_width failed");
+ goto ERROR;
+ }
+ ret |= media_format_set_video_height(media_format_, info->height);
+ if (ret != MEDIA_FORMAT_ERROR_NONE) {
+ TRACKRENDERER_ERROR("media_format_set_video_height failed");
+ goto ERROR;
+ }
+
+ TRACKRENDERER_DEBUG("media_format_set_video_mime, width, height ret : 0x%x", ret);
+
+ return;
+
+ERROR:
+ media_format_unref(media_format_);
+ media_format_ = nullptr;
+}
+
+media_format_mimetype_e MediaPacket::ConvertTbmFormatToMediaFormat(tbm_format format) {
+ switch (format) {
+ case TBM_FORMAT_YUV420:
+ return MEDIA_FORMAT_I420;
+ case TBM_FORMAT_NV12:
+ return MEDIA_FORMAT_NV12;
+ case TBM_FORMAT_YUYV:
+ return MEDIA_FORMAT_YUYV;
+ default:
+ TRACKRENDERER_ERROR("Unsupported format");
+ return MEDIA_FORMAT_MAX;
+ }
+}
+
+void MediaPacket::MediaPacketDispose(media_packet_h media_packet) {
+ tbm_surface_h tsurf = nullptr;
+ GstBuffer* buffer = nullptr;
+
+ if (!media_packet) {
+ TRACKRENDERER_ERROR("media_packet is null");
+ return;
+ }
+
+ media_packet_get_tbm_surface(media_packet, &tsurf);
+ if (tsurf)
+ tbm_surface_destroy(tsurf);
+
+ media_packet_get_extra(media_packet, (void **)&buffer);
+ if (buffer)
+ gst_buffer_unref(buffer);
+}
+
+media_packet_h MediaPacket::CreatePacket(tbm_surface_h tbm_surf) {
+ media_packet_h mediaPacket = nullptr;
+ tbm_surface_info_s info;
+
+ if (!tbm_surf) {
+ TRACKRENDERER_ERROR("tbm_surf is null");
+ return nullptr;
+ }
+
+ if (tbm_surface_get_info(tbm_surf, &info) != TBM_SURFACE_ERROR_NONE) {
+ TRACKRENDERER_ERROR("Failed to get surface info");
+ return nullptr;
+ }
+
+ if (IsMediaFormatChangeRequired(&info))
+ CreateMediaFormat(&info);
+
+ if (media_packet_new_from_tbm_surface(media_format_, tbm_surf,
+ [](media_packet_h packet, void* user_data) -> void {
+ auto packetManager = static_cast<MediaPacket*>(user_data);
+ packetManager->MediaPacketDispose(packet);
+ }, this, &mediaPacket) != MEDIA_PACKET_ERROR_NONE) {
+ TRACKRENDERER_ERROR("Failed to create media packet from tbm surface");
+ return nullptr;
+ }
+
+ return mediaPacket;
+}
+
+} // namespace trackrenderer
+
+} // namespace plusplayer
\ No newline at end of file
}
inline bool IsDisplayNeeded(DisplayType& type) {
- return (type != DisplayType::kNone);
+ return (type == DisplayType::kOverlay);
}
uint32_t ConvertToTbmFormat(const gchar *data) {
TRACKRENDERER_INFO("Set pipeline state to GST_STATE_NULL.");
pipeline_->SetState(Elements::kPipeline, GST_STATE_NULL);
ReleaseResource_();
+ display_->FlushDisplay();
TRACKRENDERER_LEAVE;
return true;
}
return false;
}
+ auto prerollCallback = G_CALLBACK(GstPrerollDecodedVideoBufferCb_);
+ auto handoffCallback = G_CALLBACK(GstDecodedVideoBufferCb_);
+ if (display_type == DisplayType::kEvas) {
+ prerollCallback = G_CALLBACK(GstPrerollEvasRenderVideoBufferCb_);
+ handoffCallback = G_CALLBACK(GstEvasRenderVideoBufferCb_);
+ }
+
pipeline_->SignalConnect(Elements::kSinkVideo, "preroll-handoff",
- G_CALLBACK(GstPrerollDecodedVideoBufferCb_), this);
+ prerollCallback, this);
pipeline_->SignalConnect(Elements::kSinkVideo, "handoff",
- G_CALLBACK(GstDecodedVideoBufferCb_), this);
+ handoffCallback, this);
pipeline_->SignalConnect(Elements::kSinkVideo, "sink", "notify::caps",
G_CALLBACK(GstCapsNotifyCb_), this);
- if (internal::IsVideoDecodedBufferNeeded(decoded_buffer_type_)) {
+ if (internal::IsVideoDecodedBufferNeeded(decoded_buffer_type_) ||
+ display_type == DisplayType::kEvas) {
CreateTbmBufferManager_(track);
+ CreateMediaPacketManager_();
if (strstr(videosink_name, kFakeSinkName))
pipeline_->SetProperty(Elements::kSinkVideo, "signal-handoffs", true);
return;
}
+void TrackRenderer::GstPrerollEvasRenderVideoBufferCb_(GstElement* element,
+ GstBuffer* buffer,
+ GstPad* pad,
+ void* userdata) {
+ TRACKRENDERER_DEBUG("Preroll decoded buffer");
+ GstEvasRenderVideoBufferCb_(element, buffer, pad, userdata);
+}
+
+void TrackRenderer::GstEvasRenderVideoBufferCb_(GstElement* element,
+ GstBuffer* buffer,
+ GstPad* pad,
+ void* userdata) {
+#ifdef __DEBUG__
+ TRACKRENDERER_ENTER;
+#endif
+ auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+
+ GstMemory* mem = gst_buffer_peek_memory(buffer, 0);
+ tbm_surface_h tbm_surf = nullptr;
+
+ if (gst_is_tizen_memory(mem)) {
+ tbm_surf = (tbm_surface_h)gst_tizen_memory_get_surface(mem);
+ tbm_surface_internal_ref(tbm_surf);
+ } else {
+ auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad));
+ tbm_surf = internal::CreateTbmSurfaceWithBuffer(mem, caps.get());
+ }
+
+ if (!tbm_surf) {
+ TRACKRENDERER_ERROR("failed to get tbm surface");
+ return;
+ }
+
+#ifdef __DEBUG__
+ internal::DumpVideoFrame(tbm_surf);
+#endif
+ media_packet_h mediaPacket = trackrenderer->media_packet_manager_->CreatePacket(tbm_surf);
+ if (!mediaPacket) {
+ tbm_surface_destroy(tbm_surf);
+ return;
+ }
+ media_packet_set_extra(mediaPacket, gst_buffer_ref(buffer));
+ trackrenderer->display_->RenderToEvas(mediaPacket);
+
+#ifdef __DEBUG__
+ TRACKRENDERER_LEAVE;
+#endif
+}
+
void TrackRenderer::FlushAppsrc(TrackType type) {
TRACKRENDERER_ENTER;
if (!pipeline_) return;
tbm_buffer_manager_.reset(new TbmBufferManager);
}
+void TrackRenderer::CreateMediaPacketManager_() {
+ TRACKRENDERER_ENTER;
+ media_packet_manager_.reset(new MediaPacket);
+}
+
bool TrackRenderer::GetVolume(int* volume) {
gdouble vol;
if (!volume) return false;