Support evas display 94/318194/9
authorGilbok Lee <gilbok.lee@samsung.com>
Wed, 25 Sep 2024 10:30:17 +0000 (19:30 +0900)
committerGilbok Lee <gilbok.lee@samsung.com>
Thu, 26 Sep 2024 23:31:16 +0000 (08:31 +0900)
- Remove unnecessary comments.

[Version] 0.1.2
[Issue Type] Add feature

Change-Id: I4ba3a0d150fe4ba49a4890e52997439f483a7270

packaging/libtrackrenderer.spec
src/CMakeLists.txt
src/display.cpp
src/include_internal/trackrenderer/display.h
src/include_internal/trackrenderer/mediapacket.h [new file with mode: 0644]
src/include_internal/trackrenderer/trackrenderer.h
src/mediapacket.cpp [new file with mode: 0644]
src/trackrenderer.cpp

index d3d7227f6e1eb8a9960076df8edf8b94a1e4f4f7..690553010ef810ac5586144a4f1af55c384648d8 100644 (file)
@@ -1,6 +1,6 @@
 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
@@ -28,6 +28,8 @@ BuildRequires:  pkgconfig(gio-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
 
index 20cb6f661de431e17e90f7447bc4b95d0fdffc6b..2e5e1ac96ab49ac9733e0e53da95dea5c61aa9dd 100644 (file)
@@ -18,7 +18,8 @@ SET(dependents "gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-video-1.0 gst
                "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)
 
@@ -59,6 +60,7 @@ SET(CC_SRCS
   ${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})
index d482cd0e86ae5f7f5cb572110faf4b1964432ea0..29dcfad23c7bd72ad39d18d4077b06589ed1f7ec 100644 (file)
@@ -30,6 +30,8 @@
 #include "trackrenderer/core/gstobject_guard.h"
 #include "trackrenderer/core/utils/log.h"
 
+#include "mm_error.h"
+
 namespace plusplayer {
 
 namespace trackrenderer {
@@ -99,7 +101,7 @@ bool GetWindowGeometry(Evas_Object* obj, int* x, int* y, int* width,
   }
 
   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;
@@ -226,9 +228,34 @@ int ConvertDisplayModeValue(const DisplayMode& mode) {
   }
 }
 
+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");
@@ -268,10 +295,17 @@ bool Display::SetDisplay(const DisplayType& type, Evas_Object* obj) {
       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;
@@ -324,12 +358,6 @@ bool Display::SetDisplay_(const DisplayType& type,
     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);
 }
@@ -337,13 +365,11 @@ bool Display::SetDisplay_(const DisplayType& type,
 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;
@@ -359,20 +385,8 @@ bool Display::SetDisplay(const DisplayType& type, const uint32_t 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;
 }
@@ -429,6 +443,29 @@ bool Display::Update(GstElement* videosink) {
                      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;
@@ -443,9 +480,12 @@ bool Display::UpdateVisible(GstElement* videosink) {
 
   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;
@@ -457,6 +497,24 @@ void Display::SetDisplayRotate(const DisplayRotation& rotate) {
   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
index 41e5be70cd2946f890f8c35e2241600b94502712..e568c6334eb0e342de21d7c7170ad4ee66902265 100644 (file)
@@ -23,6 +23,7 @@
 #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"
@@ -33,6 +34,7 @@ namespace trackrenderer {
 
 class Display : private boost::noncopyable {
  public:
+  Display();
   ~Display();
   uint32_t GetSurfaceId() const { return surface_id_; }
   void SetDisplayMode(const DisplayMode& mode);
@@ -55,6 +57,9 @@ class Display : private boost::noncopyable {
   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);
@@ -69,6 +74,7 @@ class Display : private boost::noncopyable {
   DisplayRotation rotate_ = DisplayRotation::kNone;
   bool visible_ = true;
   std::mutex settings_mutex_;
+  mm_display_interface_h interface_;
 };
 
 }  // namespace trackrenderer
diff --git a/src/include_internal/trackrenderer/mediapacket.h b/src/include_internal/trackrenderer/mediapacket.h
new file mode 100644 (file)
index 0000000..b110213
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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
index e769d4eded45a83746f2ae19ca7ef9da1e2be581..60bbeed386c8d5d5fb111a2346096cd538cb2256 100644 (file)
@@ -42,6 +42,7 @@
 #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"
 
@@ -288,10 +289,10 @@ class TrackRenderer : public ResourceConflictListener,
                                           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);
@@ -299,13 +300,19 @@ class TrackRenderer : public ResourceConflictListener,
                                          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,
@@ -319,8 +326,8 @@ class TrackRenderer : public ResourceConflictListener,
                                                  gpointer userdata);
 
   static GstPadProbeReturn GstPadProbeAppsrcEventCb_(GstPad* pad,
-                                                       GstPadProbeInfo* info,
-                                                       gpointer userdata);
+                                                     GstPadProbeInfo* info,
+                                                     gpointer userdata);
 
   TrackType GetTrackType_(GstElement* element);
 
@@ -359,6 +366,7 @@ class TrackRenderer : public ResourceConflictListener,
   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);
@@ -411,6 +419,7 @@ class TrackRenderer : public ResourceConflictListener,
   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_;
diff --git a/src/mediapacket.cpp b/src/mediapacket.cpp
new file mode 100644 (file)
index 0000000..0abb1c4
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * 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
index 384c4f6b067ae72dd2f02996be4dc3f369299fc1..7f301d46698f8463bf478461d9763208e6530781 100644 (file)
@@ -129,7 +129,7 @@ inline bool IsVideoDecodedBufferNeeded(DecodedVideoFrameBufferType& type) {
 }
 
 inline bool IsDisplayNeeded(DisplayType& type) {
-  return (type != DisplayType::kNone);
+  return (type == DisplayType::kOverlay);
 }
 
 uint32_t ConvertToTbmFormat(const gchar *data) {
@@ -450,6 +450,7 @@ bool TrackRenderer::Stop() {
   TRACKRENDERER_INFO("Set pipeline state to GST_STATE_NULL.");
   pipeline_->SetState(Elements::kPipeline, GST_STATE_NULL);
   ReleaseResource_();
+  display_->FlushDisplay();
   TRACKRENDERER_LEAVE;
   return true;
 }
@@ -953,15 +954,24 @@ bool TrackRenderer::CreateVideoSink_(const Track* track) {
     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);
 
@@ -1733,6 +1743,55 @@ void TrackRenderer::GstDecodedVideoBufferCb_(GstElement* element,
   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;
@@ -2519,6 +2578,11 @@ void TrackRenderer::CreateTbmBufferManager_(const Track* track) {
     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;