[Tizen][WebRTC] Pixmap implementation for video decode accelerator
authorsonal.g1@samsung.com <sonal.g1@samsung.com>
Mon, 19 Jan 2015 14:56:14 +0000 (20:26 +0530)
committerYoungsoo Choi <kenshin.choi@samsung.com>
Tue, 10 Jul 2018 06:57:09 +0000 (06:57 +0000)
Implementation of Rendering through pixmap surface.

Together with: I325093df8aac31fc0eab155da08cd87de2ab58f7
Reviewed by: Min-Soo Koo, SeungSeop Park, Venugopal S M

Change-Id: I80a06a4fa0fa65106061a32f0a57b4e2b8a3635b
Signed-off-by: sonal.g1@samsung.com <sonal.g1@samsung.com>
tizen_src/impl/content/common/gpu/media/tizen/tizen_video_decode_accelerator.cc
tizen_src/impl/content/common/gpu/media/tizen/tizen_video_decode_accelerator.h

index 26a5ad5..1cfce5c 100644 (file)
@@ -15,6 +15,9 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/time/time.h"
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+#include "ui/gl/efl_pixmap.h"
+#endif
 
 #if GST_VERSION_MAJOR == 1
 #include <gst/video/videooverlay.h>
@@ -41,6 +44,10 @@ const char* kDecoderGstElement = "omxh264dec";
 const char* kDecoderGstElement = "omx_h264dec";
 #endif
 
+// Generating Unique Key from given width and height.
+int32 ConvertWidthAndHeightToKey(int width, int height) {
+  return ((width << 16) | height);
+}
 } // namespace
 
 namespace content {
@@ -48,6 +55,9 @@ namespace content {
 enum {
   MAX_BITRATE = 2000000,                 // bps.
   INPUT_BUFFER_SIZE = MAX_BITRATE / 8,   // bytes. 1 sec for H.264 HD video.
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+  ID_LAST = 0x3FFFFFFF,                  // wrap round ID after this
+#endif
 };
 
 media::VideoDecodeAccelerator* CreateTizenVideoDecodeAccelerator() {
@@ -103,7 +113,21 @@ struct TizenVideoDecodeAccelerator::Impl {
         sink_(NULL),
         appsrc_(NULL),
         io_message_loop_proxy_(base::MessageLoopProxy::current()),
-        gst_thread_("TizenDecoderThreadGst") {}
+        gst_thread_("TizenDecoderThreadGst")
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+        ,bitstream_buffer_id_(0),
+        pixmap_id_(0),
+        gst_width_(0),
+        gst_height_(0),
+        damage_(0),
+        damage_handler_(NULL),
+        is_x_window_handle_set_(false)
+#endif
+{
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+  xpixmap_buffer_map_.clear();
+#endif
+}
 
   static GstBusSyncReply OnBusMessage(
       GstBus* bus, GstMessage* msg, gpointer data) {
@@ -123,7 +147,30 @@ struct TizenVideoDecodeAccelerator::Impl {
         g_free(debug);
         break;
       }
-      default: NOTREACHED();
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+      case GST_MESSAGE_ELEMENT: {
+        TizenVideoDecodeAccelerator::Impl* obj_impl =
+            static_cast<TizenVideoDecodeAccelerator::Impl*>(data);
+        if (obj_impl) {
+          if (obj_impl->IsXWindowHandleSet()) {
+#if GST_VERSION_MAJOR == 1
+            if (gst_is_video_overlay_prepare_window_handle_message(msg)) {
+#else
+            if (gst_structure_has_name(msg->structure, "prepare-xid")) {
+#endif
+              obj_impl->OnXWindowIdPrepared(msg);
+              gst_message_unref(msg);
+              return GST_BUS_PASS;
+            }
+          }
+        } else {
+          LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL";
+        }
+        break;
+      }
+#endif
+      default:
+        break;
     }
     return GST_BUS_PASS;
   }
@@ -142,6 +189,17 @@ struct TizenVideoDecodeAccelerator::Impl {
     impl->can_feed_ = false;
   }
 
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+  bool IsXWindowHandleSet() const {return is_x_window_handle_set_;}
+  void OnXWindowIdPrepared(GstMessage* message);
+  void SetXWindowHandle(bool handle_set);
+  void SetPixmap(const int32& gst_width, const int32& gst_height);
+  void DeregisterDamageHandler();
+  static Eina_Bool OnSurfaceChanged(void* ptr_acc, int type, void* event);
+  static void OnSinkCapChanged(
+      GstPad* sink_pad, GParamSpec* gparamspec, void* user_data);
+#endif
+
   volatile bool can_feed_;
   volatile bool is_destroying_;
   GstElement* pipeline_;
@@ -150,6 +208,18 @@ struct TizenVideoDecodeAccelerator::Impl {
   scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
   scoped_ptr<base::WeakPtrFactory<Client> > io_client_weak_factory_;
   base::Thread gst_thread_;
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+  int bitstream_buffer_id_;
+  scoped_refptr<gfx::EflPixmap> pixmap_surface_;
+  int pixmap_id_;
+  gint gst_width_;
+  gint gst_height_;
+  Ecore_X_Damage damage_;
+  Ecore_Event_Handler* damage_handler_;
+  bool is_x_window_handle_set_;
+  typedef std::map<int16, scoped_refptr<gfx::EflPixmap> > PixmapSurfaceTizenMap;
+  PixmapSurfaceTizenMap xpixmap_buffer_map_;
+#endif
 };
 
 TizenVideoDecodeAccelerator::TizenVideoDecodeAccelerator()
@@ -166,6 +236,7 @@ bool TizenVideoDecodeAccelerator::Initialize(
   GstCaps* video_caps = NULL;
   GstElement* gst_decoder = NULL;
   GstBus* gst_bus = NULL;
+  GstPad* video_sink_pad = NULL;
   scoped_ptr<GstElement, GstElementDeleter> gst_pipeline;
   static GstAppSrcCallbacks appsrc_callbacks =
       {&Impl::StartFeed, &Impl::StopFeed, NULL};
@@ -259,6 +330,15 @@ bool TizenVideoDecodeAccelerator::Initialize(
     return false;
   }
   g_object_set(impl_->sink_, "rotate", 0, NULL);
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+  if (!(video_sink_pad = gst_element_get_static_pad(impl_->sink_, "sink"))) {
+    return false;
+  }
+  g_signal_connect(
+      video_sink_pad, "notify::caps", G_CALLBACK(impl_->OnSinkCapChanged), impl_);
+  impl_->SetXWindowHandle(false);
+  gst_object_unref(video_sink_pad);
+#endif
 
   // linking the elements.
   if (!gst_element_link(impl_->appsrc_, gst_decoder)) {
@@ -385,6 +465,11 @@ void TizenVideoDecodeAccelerator::Reset() {
 
 void TizenVideoDecodeAccelerator::Destroy() {
   if (impl_ != NULL) {
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+    impl_->SetXWindowHandle(false);
+    impl_->DeregisterDamageHandler();
+    impl_->xpixmap_buffer_map_.clear();
+#endif
     if (impl_->gst_thread_.IsRunning()) {
       impl_->gst_thread_.Stop();
     }
@@ -408,6 +493,131 @@ void TizenVideoDecodeAccelerator::StartDecoder() {
   gst_element_set_state(impl_->pipeline_, GST_STATE_PLAYING);
 };
 
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+void TizenVideoDecodeAccelerator::Impl::OnXWindowIdPrepared(
+    GstMessage* message) {
+#if GST_VERSION_MAJOR == 1
+  const GstStructure* structure = gst_message_get_structure(message);
+  gst_structure_get_int(structure, "video-width", &gst_width_);
+  gst_structure_get_int(structure, "video-height", &gst_height_);
+#else
+  gst_structure_get_int(message->structure, "video-width", &gst_width_);
+  gst_structure_get_int(message->structure, "video-height", &gst_height_);
+#endif
+  SetPixmap(gst_width_, gst_height_);
+  SetXWindowHandle(true);
+}
+
+void TizenVideoDecodeAccelerator::Impl::SetXWindowHandle(
+    bool handle_set) {
+  is_x_window_handle_set_ = handle_set;
+}
+
+void TizenVideoDecodeAccelerator::Impl::SetPixmap(
+    const int32& gst_width, const int32& gst_height) {
+  int32 key_wh = ConvertWidthAndHeightToKey(gst_width, gst_height);
+  PixmapSurfaceTizenMap::iterator it = xpixmap_buffer_map_.find(key_wh);
+  if (it != xpixmap_buffer_map_.end()) {
+    pixmap_surface_ = it->second;
+    pixmap_id_ = pixmap_surface_->GetId();
+  } else {
+    pixmap_surface_ =
+        gfx::EflPixmap::Create(gfx::EflPixmapBase::UsageType::SURFACE,
+                               gfx::Size(gst_width, gst_height));
+    if (pixmap_surface_.get() == NULL) {
+      LOG(ERROR) << __FUNCTION__ << "Failed to create pixmap Surface";
+      return;
+    }
+    pixmap_id_ = pixmap_surface_->GetId();
+    xpixmap_buffer_map_[key_wh] = pixmap_surface_;
+  }
+  gst_width_ = gst_width;
+  gst_height_ = gst_height;
+  DeregisterDamageHandler();
+
+  // Register to get notification from ecore for damage updates.
+  damage_ = ecore_x_damage_new(pixmap_id_,
+                               ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES);
+  damage_handler_ = ecore_event_handler_add(ECORE_X_EVENT_DAMAGE_NOTIFY,
+                                            OnSurfaceChanged,
+                                            this);
+#if GST_VERSION_MAJOR == 1
+  gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(sink_), pixmap_id_);
+#else
+  gst_x_overlay_set_window_handle(GST_X_OVERLAY(sink_), pixmap_id_);
+#endif
+}
+
+void TizenVideoDecodeAccelerator::Impl::DeregisterDamageHandler() {
+  if (damage_) {
+    ecore_x_damage_free(damage_);
+    damage_ = 0;
+  }
+  if (damage_handler_) {
+    ecore_event_handler_del(damage_handler_);
+    damage_handler_ = NULL;
+  }
+}
+
+// Callback received when pixmap surface is changed/damaged
+Eina_Bool TizenVideoDecodeAccelerator::Impl::OnSurfaceChanged(void* ptr_acc,
+                                                              int type,
+                                                              void* event) {
+  TizenVideoDecodeAccelerator::Impl* self =
+      static_cast<TizenVideoDecodeAccelerator::Impl*>(ptr_acc);
+
+  if (self) {
+    media::Picture picture(self->pixmap_id_,
+                           self->bitstream_buffer_id_,
+                           gfx::Rect(self->gst_width_, self->gst_height_));
+
+    self->io_message_loop_proxy_->PostTask(
+        FROM_HERE,
+        base::Bind(&media::VideoDecodeAccelerator::Client::PictureReady,
+                   self->io_client_weak_factory_->GetWeakPtr(),
+                   picture) );
+    self->bitstream_buffer_id_ = (self->bitstream_buffer_id_ + 1) & ID_LAST;
+  } else {
+    LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL";
+    return ECORE_CALLBACK_CANCEL;
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+void TizenVideoDecodeAccelerator::Impl::OnSinkCapChanged(
+    GstPad* sink_pad, GParamSpec* gparamspec,void* user_data) {
+  TizenVideoDecodeAccelerator::Impl* self =
+      static_cast<TizenVideoDecodeAccelerator::Impl*>(user_data);
+  if (!self) {
+    LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL";
+    return;
+  }
+
+  int width = 0, height = 0;
+#if GST_VERSION_MAJOR == 1
+  GstCaps* caps = gst_pad_get_current_caps(GST_PAD(sink_pad));
+  if (caps) {
+    GstVideoInfo info;
+    gst_video_info_init(&info);
+
+    if (gst_video_info_from_caps(&info, caps)) {
+      width = info.width;
+      height = info.height;
+      if ((self->gst_width_ != width) || (self->gst_height_ != height)) {
+        self->SetPixmap(width, height);
+      }
+    }
+  }
+#else
+  if (gst_video_get_size(sink_pad, &width, &height)) {
+    if ((self->gst_width_ != width) || (self->gst_height_ != height)) {
+      self->SetPixmap(width, height);
+    }
+  }
+#endif
+}
+#endif
+
 void TizenVideoDecodeAccelerator::OnDecode(
     scoped_ptr<BitstreamBufferRef> buffer_ref) {
   if (!buffer_ref) {
index 10a42f5..c312e5e 100644 (file)
@@ -5,6 +5,13 @@
 #ifndef CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_DECODE_ACCELERATOR_H_
 #define CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_DECODE_ACCELERATOR_H_
 
+#include <Ecore.h>
+#include <Ecore_X.h>
+#include <gst/gst.h>
+#include <gst/app/gstappsink.h>
+#include <gst/app/gstappsrc.h>
+#include <map>
+
 #include "base/synchronization/lock.h"
 #include "base/threading/thread.h"
 #include "content/common/content_export.h"