waylandsink : sending flush buffer for gapless playback 57/71057/2 accepted/tizen/common/20160531.141848 accepted/tizen/ivi/20160602.022049 accepted/tizen/mobile/20160602.022126 accepted/tizen/tv/20160602.021908 accepted/tizen/wearable/20160602.022021 submit/tizen/20160530.013417
authorHyunil <hyunil46.park@samsung.com>
Tue, 24 May 2016 02:06:55 +0000 (11:06 +0900)
committerHyunil <hyunil46.park@samsung.com>
Tue, 24 May 2016 04:22:13 +0000 (13:22 +0900)
Change-Id: Ia3d7d5f4a771fc397a64921b44e3dd392adc5350
Signed-off-by: Hyunil <hyunil46.park@samsung.com>
ext/wayland/gstwaylandsink.c
ext/wayland/gstwaylandsink.h
ext/wayland/wlbuffer.c
ext/wayland/wlbuffer.h

index 9f9415c..888621b 100755 (executable)
@@ -141,6 +141,7 @@ enum
   PROP_0,
   PROP_DISPLAY,
 #ifdef GST_WLSINK_ENHANCEMENT
+  PROP_USE_GAPLESS,
   PROP_USE_TBM,
   PROP_ROTATE_ANGLE,
   PROP_DISPLAY_GEOMETRY_METHOD,
@@ -205,6 +206,7 @@ static void gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface *
 static void gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video);
 static void gst_wayland_sink_end_geometry_change (GstWaylandVideo * video);
 #ifdef GST_WLSINK_ENHANCEMENT
+static gboolean gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event);
 static void gst_wayland_sink_update_window_geometry (GstWaylandSink * sink);
 static void render_last_buffer (GstWaylandSink * sink);
 #endif
@@ -251,16 +253,25 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
   gstbasesink_class->propose_allocation =
       GST_DEBUG_FUNCPTR (gst_wayland_sink_propose_allocation);
   gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_wayland_sink_render);
+#ifdef GST_WLSINK_ENHANCEMENT
+  gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_wayland_sink_event);
+#endif
 
   g_object_class_install_property (gobject_class, PROP_DISPLAY,
       g_param_spec_string ("display", "Wayland Display name", "Wayland "
           "display name to connect to, if not supplied via the GstContext",
           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 #ifdef GST_WLSINK_ENHANCEMENT
+  g_object_class_install_property (gobject_class, PROP_USE_GAPLESS,
+      g_param_spec_boolean ("use-gapless", "use gapless",
+          "Use gapless playback on GST_STATE_PLAYING state, "
+          "Last tbm buffer is copied and returned to codec immediately when enabled",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_property (gobject_class, PROP_USE_TBM,
-      g_param_spec_boolean ("use-tbm",
-          "Use Tizen Buffer Memory insted of Shared memory",
-          "When enabled, Memory is alloced by TBM insted of SHM ", TRUE,
+      g_param_spec_boolean ("use-tbm", "use tbm buffer",
+          "Use Tizen Buffer Memory insted of Shared memory, "
+          "Memory is alloced by TBM insted of SHM when enabled", TRUE,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_property (gobject_class, PROP_ROTATE_ANGLE,
@@ -317,12 +328,16 @@ gst_wayland_sink_init (GstWaylandSink * sink)
 {
   FUNCTION;
 #ifdef GST_WLSINK_ENHANCEMENT
+  sink->use_gapless = FALSE;
+  sink->got_eos_event = FALSE;
   sink->USE_TBM = TRUE;
   sink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
   sink->flip = DEF_DISPLAY_FLIP;
   sink->rotate_angle = DEGREE_0;
   sink->orientation = DEGREE_0;
   sink->visible = TRUE;
+  g_mutex_init (&sink->gapless_lock);
+  g_cond_init (&sink->gapless_cond);
 #endif
   g_mutex_init (&sink->display_lock);
   g_mutex_init (&sink->render_lock);
@@ -337,6 +352,20 @@ gst_wayland_sink_stop_video (GstWaylandSink * sink)
   gst_wl_window_render (sink->window, NULL, NULL);
 }
 
+static int
+gst_wayland_sink_need_to_make_flush_buffer (GstWaylandSink * sink)
+{
+  g_return_if_fail (sink != NULL);
+  g_return_if_fail (sink->display != NULL);
+
+  if ((sink->use_gapless && sink->got_eos_event)
+      || sink->display->flush_request) {
+    sink->display->flush_request = TRUE;
+    return TRUE;
+  }
+  return FALSE;
+}
+
 static void
 gst_wayland_sink_update_last_buffer_geometry (GstWaylandSink * sink)
 {
@@ -354,8 +383,8 @@ gst_wayland_sink_update_last_buffer_geometry (GstWaylandSink * sink)
   /* ref count is incresed in gst_wl_buffer_attach() of render_last_buffer(),
      to call gst_wl_buffer_finalize(), we need to decrease buffer ref count.
      wayland can not release buffer if we attach same buffer,
-     if we use visible but we need to attach null buffer and wayland can release buffer,
-     so we don't need to below code. */
+     if we use no visible, we need to attach null buffer and wayland can release buffer,
+     so we don't need to below if() code. */
   if (!sink->visible)
     gst_buffer_unref (wlbuffer->gstbuffer);
 }
@@ -477,17 +506,20 @@ gst_wayland_sink_add_mm_video_buf_info (GstWlDisplay * display,
 }
 
 static int
-gst_wayland_sink_get_mm_video_buf_info (GstWlDisplay * display,
+gst_wayland_sink_get_mm_video_buf_info (GstWaylandSink * sink,
     GstBuffer * buffer)
 {
+  GstWlDisplay *display;
   GstMemory *mem;
   GstMapInfo mem_info = GST_MAP_INFO_INIT;
   MMVideoBuffer *mm_video_buf = NULL;
 
-  g_return_val_if_fail (display != NULL, FALSE);
+  g_return_val_if_fail (sink != NULL, FALSE);
   g_return_val_if_fail (buffer != NULL, FALSE);
 
   FUNCTION;
+  display = sink->display;
+  g_return_val_if_fail (sink->display != NULL, FALSE);
 
   mem = gst_buffer_peek_memory (buffer, 1);
   gst_memory_map (mem, &mem_info, GST_MAP_READ);
@@ -506,7 +538,7 @@ gst_wayland_sink_get_mm_video_buf_info (GstWlDisplay * display,
     display->flush_request = mm_video_buf->flush_request;
     GST_DEBUG ("flush_request value is %d", display->flush_request);
 #ifdef USE_WL_FLUSH_BUFFER
-    if (display->flush_request) {
+    if (gst_wayland_sink_need_to_make_flush_buffer (sink)) {
       if (!gst_wayland_sink_copy_mm_video_buf_info_to_flush (display,
               mm_video_buf)) {
         GST_ERROR ("cat not copy mm_video_buf info to flush");
@@ -523,7 +555,28 @@ gst_wayland_sink_get_mm_video_buf_info (GstWlDisplay * display,
   return TRUE;
 }
 
+static void
+gst_wayland_sink_gapless_render_flush_buffer (GstBaseSink * bsink)
+{
+  GstWaylandSink *sink;
+  GstBuffer *buffer;
+  sink = GST_WAYLAND_SINK (bsink);
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+  g_return_if_fail (sink->last_buffer != NULL);
+
+  buffer = gst_buffer_copy (sink->last_buffer);
+
+  g_mutex_lock (&sink->gapless_lock);
+  g_cond_wait (&sink->gapless_cond, &sink->gapless_lock);
+
+  gst_wayland_sink_render (bsink, buffer);
+  if (buffer)
+    gst_buffer_unref (buffer);
+  g_mutex_unlock (&sink->gapless_lock);
+}
 #endif
+
 static void
 gst_wayland_sink_get_property (GObject * object,
     guint prop_id, GValue * value, GParamSpec * pspec)
@@ -538,6 +591,9 @@ gst_wayland_sink_get_property (GObject * object,
       GST_OBJECT_UNLOCK (sink);
       break;
 #ifdef GST_WLSINK_ENHANCEMENT
+    case PROP_USE_GAPLESS:
+      g_value_set_boolean (value, sink->use_gapless);
+      break;
     case PROP_USE_TBM:
       g_value_set_boolean (value, sink->USE_TBM);
       break;
@@ -578,6 +634,10 @@ gst_wayland_sink_set_property (GObject * object,
       GST_OBJECT_UNLOCK (sink);
       break;
 #ifdef GST_WLSINK_ENHANCEMENT
+    case PROP_USE_GAPLESS:
+      sink->use_gapless = g_value_get_boolean (value);
+      GST_LOG ("use gapless is (%d)", sink->use_gapless);
+      break;
     case PROP_USE_TBM:
       sink->USE_TBM = g_value_get_boolean (value);
       GST_LOG ("1:USE TBM 0: USE SHM set(%d)", sink->USE_TBM);
@@ -678,10 +738,37 @@ gst_wayland_sink_finalize (GObject * object)
 
   g_mutex_clear (&sink->display_lock);
   g_mutex_clear (&sink->render_lock);
+#ifdef GST_WLSINK_ENHANCEMENT
+  g_mutex_clear (&sink->gapless_lock);
+  g_cond_clear (&sink->gapless_cond);
+#endif
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+#ifdef GST_WLSINK_ENHANCEMENT
+static gboolean
+gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event)
+{
+  GstWaylandSink *sink;
+  sink = GST_WAYLAND_SINK (bsink);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      GST_LOG ("get EOS event..state is %d", GST_STATE (sink));
+      if (sink->USE_TBM && sink->display->is_native_format && sink->use_gapless) {
+        sink->got_eos_event = TRUE;
+        gst_wayland_sink_gapless_render_flush_buffer (bsink);
+        sink->got_eos_event = FALSE;
+      }
+      break;
+    default:
+      break;
+  }
+  return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event);
+}
+#endif
+
 /* must be called with the display_lock */
 static void
 gst_wayland_sink_set_display_from_context (GstWaylandSink * sink,
@@ -1169,6 +1256,14 @@ frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
 
   g_atomic_int_set (&sink->redraw_pending, FALSE);
   wl_callback_destroy (callback);
+#ifdef GST_WLSINK_ENHANCEMENT
+  if (sink->got_eos_event && sink->use_gapless && sink->USE_TBM
+      && sink->display->is_native_format) {
+    g_mutex_lock (&sink->gapless_lock);
+    g_cond_signal (&sink->gapless_cond);
+    g_mutex_unlock (&sink->gapless_lock);
+  }
+#endif
 }
 
 static const struct wl_callback_listener frame_callback_listener = {
@@ -1265,7 +1360,8 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
 #ifdef GST_WLSINK_ENHANCEMENT
 
   wlbuffer = gst_buffer_get_wl_buffer (buffer);
-  if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
+  if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)
+      && !(sink->use_gapless && sink->got_eos_event)) {
     GST_LOG_OBJECT (sink, "buffer %p has a wl_buffer from our display, " "writing directly", buffer);   //buffer is from our  pool and have wl_buffer
     GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
     to_render = buffer;
@@ -1315,11 +1411,12 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
 
       if (sink->USE_TBM && sink->display->is_native_format) {
         /* in case of SN12 or ST12 */
-        if (!gst_wayland_sink_get_mm_video_buf_info (sink->display, buffer))
+        if (!gst_wayland_sink_get_mm_video_buf_info (sink, buffer))
           return GST_FLOW_ERROR;
 
         wlbuffer = gst_buffer_get_wl_buffer (buffer);
-        if (G_UNLIKELY (!wlbuffer)) {
+        if (G_UNLIKELY (!wlbuffer) || (sink->use_gapless
+                && sink->got_eos_event)) {
           wbuf =
               gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
               &sink->video_info);
@@ -1391,7 +1488,8 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
   }
 
   if (sink->USE_TBM && sink->display->is_native_format) {
-    if (G_UNLIKELY (buffer == sink->last_buffer)) {
+    if (G_UNLIKELY (buffer == sink->last_buffer) && !(sink->use_gapless
+            && sink->got_eos_event)) {
       GST_LOG_OBJECT (sink, "Buffer already being rendered");
       goto done;
     }
index 2366138..4c500e9 100644 (file)
@@ -97,6 +97,8 @@ struct _GstWaylandSink
   GMutex render_lock;
   GstBuffer *last_buffer;
 #ifdef GST_WLSINK_ENHANCEMENT
+  gboolean use_gapless;
+  gboolean got_eos_event;
   gboolean USE_TBM;
   GstCaps *caps;
   guint rotate_angle;
@@ -104,6 +106,9 @@ struct _GstWaylandSink
   guint orientation;
   guint flip;
   gboolean visible;
+
+  GMutex gapless_lock;
+  GCond gapless_cond;
 #endif
 };
 
index f1a2013..6907430 100644 (file)
@@ -91,7 +91,7 @@ gst_wl_buffer_dispose (GObject * gobject)
 {
   GstWlBuffer *self = GST_WL_BUFFER (gobject);
   FUNCTION;
-
+  GST_INFO ("%p", self);
   GST_TRACE_OBJECT (self, "dispose");
 
   /* if the display is shutting down and we are trying to dipose
@@ -117,12 +117,13 @@ gst_wl_buffer_finalize (GObject * gobject)
   if (self->tsurface)
     tbm_surface_destroy (self->tsurface);
 #endif
+  GST_INFO ("%p", self->wlbuffer);
   if (self->wlbuffer)
     wl_buffer_destroy (self->wlbuffer);
 
 #ifdef USE_WL_FLUSH_BUFFER
   if (self->display) {
-    if (self->display->flush_request) {
+    if (self->is_flush_request) {
       if (self->display->flush_tbm_bufmgr)
         self->display->flush_tbm_bufmgr = NULL;
       for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
@@ -166,8 +167,8 @@ buffer_release (void *data, struct wl_buffer *wl_buffer)
 
 #ifdef USE_WL_FLUSH_BUFFER
   /* unref should be last, because it may end up destroying the GstWlBuffer */
-  if (!self->display->flush_request) {
-    /*in case of flush_request, gstbuffer ref-count has already decreased. */
+  if (!self->is_flush_request) {
+    /*in case of is_flush_request, gstbuffer ref-count has already decreased. */
     gst_buffer_unref (self->gstbuffer);
   } else {
     /*we blocked below code at gstbuffer_disposed() */
@@ -188,6 +189,7 @@ gstbuffer_disposed (GstWlBuffer * self)
 {
   FUNCTION;
   g_assert (!self->used_by_compositor);
+  GST_INFO ("%p", self->gstbuffer);
   self->gstbuffer = NULL;
 
   GST_TRACE_OBJECT (self, "owning GstBuffer was finalized");
@@ -196,9 +198,9 @@ gstbuffer_disposed (GstWlBuffer * self)
    * finalizing and it has taken an additional reference to it */
 #ifdef USE_WL_FLUSH_BUFFER
   /* in case of normal routine, gstbuffer_disposed() is called by buffer_release()
-     but in case of flush_request, this func() is called when basesink unref gstbuffer.
+     but in case of is_flush_request, this func() is called when basesink unref gstbuffer.
      buffer_release() is not called  if we do 'g_object_unref (self)' */
-  if (self->display && !self->display->flush_request)
+  if (!self->is_flush_request)
 #endif
     g_object_unref (self);
 }
@@ -221,6 +223,11 @@ gst_buffer_add_wl_buffer (GstBuffer * gstbuffer, struct wl_buffer *wlbuffer,
     self->tsurface = NULL;
   GST_INFO ("self->tsurface(%p)", self->tsurface);
 #endif
+#ifdef USE_WL_FLUSH_BUFFER
+  self->is_flush_request = FALSE;
+  if (display->flush_request)
+    self->is_flush_request = TRUE;
+#endif
 
   gst_wl_display_register_buffer (self->display, self); //register GstWlBuffer
 
@@ -289,9 +296,9 @@ gst_wl_buffer_attach (GstWlBuffer * self, struct wl_surface *surface)
    * the compositor is using the buffer and it should not return
    * back to the pool and be re-used until the compositor releases it. */
 #ifdef USE_WL_FLUSH_BUFFER
-  /* in case of flush_request, we need to copy info and unref gstbuffer
+  /* in case of is_flush_request, we need to copy info and unref gstbuffer
      so, we need not to increase ref count. */
-  if (!self->display->flush_request)
+  if (!self->is_flush_request)
 #endif
     gst_buffer_ref (self->gstbuffer);
 
index 9f5102e..b285cba 100644 (file)
@@ -45,6 +45,7 @@ struct _GstWlBuffer
   gboolean used_by_compositor;
 
 #ifdef GST_WLSINK_ENHANCEMENT
+  gboolean is_flush_request;
   tbm_surface_h tsurface;
 #endif
 };