[tizencamerasrc] Update code to handle buffers 09/197009/3
authorJeongmo Yang <jm80.yang@samsung.com>
Wed, 9 Jan 2019 01:18:07 +0000 (10:18 +0900)
committerJeongmo Yang <jm80.yang@samsung.com>
Thu, 10 Jan 2019 06:51:33 +0000 (15:51 +0900)
- Remove buffer copy in case of normal buffer
- Support tizen allocator if tbm is used in Camera HAL

[Version] 1.0.0
[Profile] Common
[Issue Type] Update
[Dependency module] N/A

Change-Id: Ia27d26f0d996c4620773299bff78555c2e76babd
Signed-off-by: Jeongmo Yang <jm80.yang@samsung.com>
packaging/gst-plugins-tizen.spec
tizencamerasrc/src/Makefile.am
tizencamerasrc/src/gsttizencamerasrc.c
tizencamerasrc/src/include/gsttizencamerasrc.h

index ae879dd..fb23e6a 100644 (file)
@@ -9,7 +9,7 @@
 Name:       gst-plugins-tizen
 Version:    1.0.0
 Summary:    GStreamer tizen plugins (common)
-Release:    64
+Release:    65
 Group:      Multimedia/Framework
 Url:        http://gstreamer.freedesktop.org/
 License:    LGPL-2.1+
index b9642f8..693e73c 100644 (file)
@@ -12,6 +12,7 @@ libgsttizencamerasrc_la_CFLAGS = -I$(srcdir)/include \
                                  $(GST_CFLAGS) \
                                  $(GST_BASE_CFLAGS) \
                                  $(GST_VIDEO_FLAGS) \
+                                 $(GST_ALLOCATORS_CFLAGS) \
                                  $(MMCOMMON_CFLAGS) \
                                  $(MMUTIL_JPEG_CFLAGS) \
                                  $(TBM_CFLAGS)
@@ -21,6 +22,7 @@ libgsttizencamerasrc_la_LIBADD = -ldl -lpthread -lrt -lm \
                                  $(GST_LIBS) \
                                  $(GST_BASE_LIBS) \
                                  $(GST_VIDEO_LIBS) \
+                                 $(GST_ALLOCATORS_LIBS) \
                                  $(MMCOMMON_LIBS) \
                                  $(MMUTIL_JPEG_LIBS) \
                                  $(TBM_LIBS)
index 3a3a18a..684f7ff 100644 (file)
@@ -178,6 +178,8 @@ static gboolean gst_tizencamerasrc_get_timeinfo(GstTizenCameraSrc *camerasrc, Gs
 static gboolean gst_tizencamerasrc_capture_start(GstTizenCameraSrc *camerasrc);
 static gboolean gst_tizencamerasrc_capture_stop(GstTizenCameraSrc *camerasrc);
 static void gst_tizencamerasrc_error_handler(GstTizenCameraSrc *camerasrc, int ret);
+static GstBuffer *gst_tizencamerasrc_buffer_new(GstTizenCameraSrc *camerasrc, camera_buffer_t *buffer, GstTizenCameraBufferType type);
+static void gst_tizencamerasrc_buffer_finalize(GstTizenCameraBuffer *buffer);
 
 /* Util functions */
 #if 0
@@ -185,6 +187,7 @@ static unsigned long _get_current_time(void);
 #endif
 static gboolean _gst_tizencamerasrc_get_frame_size(int fourcc, int width, int height, unsigned int *outsize);
 static gboolean _gst_tizencamerasrc_get_raw_pixel_info(int fourcc, int *pix_format);
+static gboolean _gst_tizencamerasrc_get_tbm_format(int pix_format, guint32 *tbm_format);
 static void _gst_tizencamerasrc_post_message_int(GstTizenCameraSrc *camerasrc, const char *msg_name, const char *field_name, int value);
 
 #if _ENABLE_CAMERASRC_DEBUG
@@ -198,6 +201,134 @@ GST_IMPLEMENT_TIZENCAMERASRC_CONTROL_METHODS(GstTizenCameraSrc, gst_tizencamera_
 /******************************************************************************
  * Implementations
  *******************************************************************************/
+static GstBuffer *gst_tizencamerasrc_buffer_new(GstTizenCameraSrc *camerasrc, camera_buffer_t *buffer, GstTizenCameraBufferType type)
+{
+  GstTizenCameraBuffer *new_buffer = NULL;
+  GstMemory *memory = NULL;
+  gboolean is_tbm_used = FALSE;
+
+  if (!camerasrc || !buffer) {
+    GST_ERROR("NULL pointer %p %p", camerasrc, buffer);
+    return NULL;
+  }
+
+  if (buffer->num_bos > 0)
+    is_tbm_used = TRUE;
+
+  GST_DEBUG_OBJECT(camerasrc, "is_tbm_used : %d", is_tbm_used);
+
+  /* allocate new buffer */
+  new_buffer = g_new0(GstTizenCameraBuffer, 1);
+
+  new_buffer->type = type;
+  new_buffer->index = buffer->index;
+  new_buffer->camerasrc = gst_object_ref(GST_OBJECT(camerasrc));
+  new_buffer->buffer = gst_buffer_new();
+  if (!new_buffer->buffer) {
+    GST_ERROR_OBJECT(camerasrc, "new GstBuffer failed");
+    goto _BUFFER_NEW_FAILED;
+  }
+
+  /* set timestamp info */
+  gst_tizencamerasrc_get_timeinfo(camerasrc, new_buffer->buffer);
+
+  if (is_tbm_used) {
+    GST_DEBUG_OBJECT(camerasrc, "TBM is used -> Tizen allocator");
+
+    /* create tbm surface from buffer */
+    new_buffer->t_surface = tbm_surface_internal_create_with_bos(&camerasrc->ts_info,
+      (tbm_bo *)buffer->bos, buffer->num_planes);
+    if (!new_buffer->t_surface) {
+      GST_ERROR_OBJECT(camerasrc, "tbm surface create failed");
+      goto _BUFFER_NEW_FAILED;
+    }
+
+    /* create tizen memory for gst buffer with tbm surface */
+    memory = gst_tizen_allocator_alloc_surface(camerasrc->allocator,
+      &camerasrc->video_info,
+      new_buffer->t_surface,
+      (gpointer)new_buffer,
+      (GDestroyNotify)gst_tizencamerasrc_buffer_finalize);
+  } else {
+    GST_DEBUG_OBJECT(camerasrc, "TBM is NOT used - size %u", buffer->total_size);
+
+    /* If tbm is not used, the data will be placed only in planes[0].data. */
+    memory = gst_memory_new_wrapped(0,
+      buffer->planes[0].data,
+      buffer->total_size,
+      0,
+      buffer->total_size,
+      (gpointer)new_buffer,
+      (GDestroyNotify)gst_tizencamerasrc_buffer_finalize);
+  }
+
+  if (!memory) {
+    GST_ERROR_OBJECT(camerasrc, "GstMemory failed");
+    goto _BUFFER_NEW_FAILED;
+  }
+
+  gst_buffer_append_memory(new_buffer->buffer, memory);
+  gst_buffer_set_size(new_buffer->buffer, buffer->total_size);
+
+  GST_DEBUG_OBJECT(camerasrc, "new buffer %p : gst buffer %p", new_buffer, new_buffer->buffer);
+
+  return new_buffer->buffer;
+
+_BUFFER_NEW_FAILED:
+  if (new_buffer) {
+    if (new_buffer->t_surface)
+      tbm_surface_destroy(new_buffer->t_surface);
+    if (new_buffer->buffer)
+      gst_buffer_unref(new_buffer->buffer);
+    if (new_buffer->camerasrc)
+      gst_object_unref(GST_OBJECT(camerasrc));
+    g_free(new_buffer);
+  }
+
+  return NULL;
+}
+
+
+static void gst_tizencamerasrc_buffer_finalize(GstTizenCameraBuffer *buffer)
+{
+  GstTizenCameraSrc *camerasrc = NULL;
+
+  if (!buffer) {
+    GST_ERROR("NULL buffer");
+    return;
+  }
+
+  GST_DEBUG_OBJECT(camerasrc, "type %d : index %d", buffer->type, buffer->index);
+
+  camerasrc = buffer->camerasrc;
+
+  if (buffer->type == BUFFER_TYPE_PREVIEW) {
+    camera_hal_interface_release_preview_buffer(camerasrc->hal_intf_handle, buffer->index);
+  } else if (buffer->type == BUFFER_TYPE_VIDEO) {
+    camera_hal_interface_release_video_buffer(camerasrc->hal_intf_handle, buffer->index);
+  } else {
+    GST_ERROR_OBJECT(camerasrc, "unknown type %d", buffer->type);
+  }
+
+  g_mutex_lock(&camerasrc->buffer_lock);
+  camerasrc->num_live_buffers--;
+  g_cond_broadcast(&camerasrc->buffer_cond);
+  g_mutex_unlock(&camerasrc->buffer_lock);
+
+  if (buffer->t_surface) {
+    tbm_surface_destroy(buffer->t_surface);
+    buffer->t_surface = NULL;
+  }
+
+  gst_object_unref(camerasrc);
+  g_free(buffer);
+
+  GST_DEBUG_OBJECT(camerasrc, "done");
+
+  return;
+}
+
+
 static void gst_tizencamerasrc_error_handler(GstTizenCameraSrc *camerasrc, int ret)
 {
   if (!camerasrc) {
@@ -336,11 +467,8 @@ static int _camera_hal_message_callback(camera_message_t *message, void *user_da
 
 static int _camera_preview_frame_cb(camera_buffer_t *buffer, camera_metadata_t *meta, void *user_data)
 {
-  int i = 0;
-  int copied_size = 0;
   GstTizenCameraSrc *camerasrc = NULL;
   GstBuffer *gst_buffer = NULL;
-  GstMapInfo map_info;
 
   if (!buffer || !user_data) {
     GST_ERROR("preview callback error %p %p", buffer, user_data);
@@ -352,44 +480,36 @@ static int _camera_preview_frame_cb(camera_buffer_t *buffer, camera_metadata_t *
   g_mutex_lock(&camerasrc->buffer_lock);
   if (!camerasrc->buffer_running) {
     GST_WARNING_OBJECT(camerasrc, "buffer is NOT running");
+
+    camera_hal_interface_release_preview_buffer(camerasrc->hal_intf_handle, buffer->index);
+
     goto _FRAME_CB_DONE;
   }
 
   /* create new buffer */
-  gst_buffer = gst_buffer_new_and_alloc(buffer->total_size);
+  gst_buffer = gst_tizencamerasrc_buffer_new(camerasrc, buffer, BUFFER_TYPE_PREVIEW);
   if (!gst_buffer) {
     GST_ERROR_OBJECT(camerasrc, "new buffer allocation failed. size %u", buffer->total_size);
-    goto _FRAME_CB_DONE;
-  }
 
-  if (!gst_buffer_map(gst_buffer, &map_info, GST_MAP_WRITE)) {
-    GST_ERROR_OBJECT(camerasrc, "failed to map gst buffer %p", gst_buffer);
-    gst_buffer_unref(gst_buffer);
-    goto _FRAME_CB_DONE;
-  }
+    camera_hal_interface_release_preview_buffer(camerasrc->hal_intf_handle, buffer->index);
 
-  /* copy buffer data */
-  for (i = 0 ; i < buffer->num_planes ; i++) {
-    memcpy(map_info.data + copied_size, buffer->planes[i].data, buffer->planes[i].size);
-    copied_size += buffer->planes[i].size;
+    goto _FRAME_CB_DONE;
   }
 
-  gst_buffer_unmap(gst_buffer, &map_info);
-  gst_buffer_set_size(gst_buffer, buffer->total_size);
+  camerasrc->num_live_buffers++;
 
   /* add new buffer to preview buffer list */
   g_queue_push_tail(camerasrc->preview_buffer_list, gst_buffer);
 
-  GST_DEBUG_OBJECT(camerasrc, "index %d, %p [size total %d, copied %d]",
-    buffer->index, gst_buffer, buffer->total_size, copied_size);
+  GST_DEBUG_OBJECT(camerasrc, "index %d, %p [size total %u][num_live_buffers %d]",
+    buffer->index, gst_buffer, buffer->total_size, camerasrc->num_live_buffers);
 
-  g_cond_signal(&camerasrc->buffer_cond);
+  g_cond_broadcast(&camerasrc->buffer_cond);
 
 _FRAME_CB_DONE:
   g_mutex_unlock(&camerasrc->buffer_lock);
 
-  /* release preview buffer from camera HAL */
-  camera_hal_interface_release_preview_buffer(camerasrc->hal_intf_handle, buffer->index);
+  GST_DEBUG_OBJECT(camerasrc, "done");
 
   return TRUE;
 }
@@ -786,6 +906,8 @@ static gboolean gst_tizencamerasrc_start(GstTizenCameraSrc *camerasrc)
 
   GST_INFO("VFLIP : %d, HFLIP : %d", camerasrc->vflip, camerasrc->hflip);
 
+  camerasrc->num_live_buffers = 0;
+
   /* start preview stream */
   ret = camera_hal_interface_start_preview(camerasrc->hal_intf_handle, _camera_preview_frame_cb, camerasrc);
   if (ret != CAMERA_ERROR_NONE) {
@@ -814,14 +936,14 @@ _ERROR:
 static gboolean gst_tizencamerasrc_stop(GstTizenCameraSrc *camerasrc)
 {
   int ret = CAMERA_ERROR_NONE;
+  gint64 end_time;
+  GstBuffer *buffer = NULL;
 
   GST_INFO_OBJECT (camerasrc, "ENTERED");
 
   if (camerasrc->hal_intf_handle) {
-    GstBuffer *buffer = NULL;
-
-    /* Stop preview stream */
     g_mutex_lock(&camerasrc->buffer_lock);
+
     if (camerasrc->buffer_running) {
       camerasrc->buffer_running = FALSE;
     } else {
@@ -829,10 +951,34 @@ static gboolean gst_tizencamerasrc_stop(GstTizenCameraSrc *camerasrc)
       g_mutex_unlock(&camerasrc->buffer_lock);
       return FALSE;
     }
+
+    g_mutex_unlock(&camerasrc->buffer_lock);
+
+    /* remove all cached buffers */
+    while (!g_queue_is_empty(camerasrc->preview_buffer_list)) {
+      buffer = g_queue_pop_head(camerasrc->preview_buffer_list);
+      GST_INFO_OBJECT(camerasrc, "unref queued buffer %p", buffer);
+      gst_buffer_unref(buffer);
+    }
+
+    g_mutex_lock(&camerasrc->buffer_lock);
+
+    /* wait until all buffers are returned */
+    while (camerasrc->num_live_buffers > 0) {
+      end_time = g_get_monotonic_time() + 1 * G_TIME_SPAN_SECOND;
+      if (!g_cond_wait_until(&camerasrc->buffer_cond, &camerasrc->buffer_lock, end_time)) {
+        GST_ERROR_OBJECT(camerasrc, "buffer wait failed");
+        break;
+      } else {
+        GST_INFO_OBJECT(camerasrc, "signal received. check again [num %d]", camerasrc->num_live_buffers);
+      }
+    }
+
     g_mutex_unlock(&camerasrc->buffer_lock);
 
     GST_INFO_OBJECT(camerasrc, "stop preview stream");
 
+    /* stop preview stream */
     ret = camera_hal_interface_stop_preview(camerasrc->hal_intf_handle);
     if (ret != CAMERA_ERROR_NONE) {
       GST_ERROR_OBJECT(camerasrc, "camera_hal_interface_stop_preview failed 0x%x", ret);
@@ -841,15 +987,6 @@ static gboolean gst_tizencamerasrc_stop(GstTizenCameraSrc *camerasrc)
     }
 
     camerasrc->mode = VIDEO_IN_MODE_NONE;
-
-    while (!g_queue_is_empty(camerasrc->preview_buffer_list)) {
-      buffer = g_queue_pop_head(camerasrc->preview_buffer_list);
-      if (buffer) {
-        GST_INFO_OBJECT(camerasrc, "unref buffer %p", buffer);
-        gst_buffer_unref(buffer);
-        buffer = NULL;
-      }
-    }
   }
 
   GST_INFO_OBJECT(camerasrc, "LEAVED");
@@ -993,9 +1130,6 @@ static GstFlowReturn gst_tizencamerasrc_read_preview(GstTizenCameraSrc *camerasr
     return GST_FLOW_FLUSHING;
   }
 
-  /* set timestamp and duration */
-  gst_tizencamerasrc_get_timeinfo(camerasrc, *buffer);
-
   if (camerasrc->firsttime) {
     camerasrc->firsttime = FALSE;
   }
@@ -1332,6 +1466,11 @@ static void gst_tizencamerasrc_finalize(GObject *object)
   g_mutex_clear(&camerasrc->buffer_lock);
   SAFE_FREE_GQUEUE(camerasrc->preview_buffer_list);
 
+  if (camerasrc->allocator) {
+    gst_object_unref(camerasrc->allocator);
+    camerasrc->allocator = NULL;
+  }
+
   if (G_OBJECT_CLASS (gst_tizencamerasrc_parent_class)->finalize)
     G_OBJECT_CLASS(gst_tizencamerasrc_parent_class)->finalize(object);
 
@@ -1553,6 +1692,38 @@ static gboolean _gst_tizencamerasrc_get_raw_pixel_info(int fourcc, int *pix_form
 }
 
 
+static gboolean _gst_tizencamerasrc_get_tbm_format(int pix_format, guint32 *tbm_format)
+{
+  if (tbm_format == NULL) {
+    GST_ERROR("NULL pointer");
+    return FALSE;
+  }
+
+  switch (pix_format) {
+  case CAMERA_PIXEL_FORMAT_I420:
+    *tbm_format = TBM_FORMAT_YUV420;
+    break;
+  case CAMERA_PIXEL_FORMAT_YV12:
+    *tbm_format = TBM_FORMAT_YVU420;
+    break;
+  case CAMERA_PIXEL_FORMAT_YUYV:
+    *tbm_format = TBM_FORMAT_YUYV;
+    break;
+  case CAMERA_PIXEL_FORMAT_UYVY:
+    *tbm_format = TBM_FORMAT_UYVY;
+    break;
+  case CAMERA_PIXEL_FORMAT_NV12:
+    *tbm_format = TBM_FORMAT_NV12;
+    break;
+  default:
+    GST_ERROR("unknown pixel format %d", pix_format);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
 static gboolean _gst_tizencamerasrc_get_frame_size(int fourcc, int width, int height, unsigned int *outsize)
 {
   switch (fourcc) {
@@ -1636,7 +1807,7 @@ static gboolean gst_tizencamerasrc_get_caps_info(GstTizenCameraSrc *camerasrc, G
     camerasrc->use_rotate_caps = TRUE;
   }
 
-  if (!gst_video_info_from_caps(&camerasrc->vinfo, caps)) {
+  if (!gst_video_info_from_caps(&camerasrc->video_info, caps)) {
     GST_ERROR_OBJECT(camerasrc, "failed to get video info from caps");
     goto _caps_info_failed;
   }
@@ -1754,6 +1925,9 @@ static gboolean gst_tizencamerasrc_set_caps(GstBaseSrc *src, GstCaps *caps)
   GstTizenCameraSrc *camerasrc = NULL;
   gboolean res = FALSE;
 
+  int tbm_ret = 0;
+  tbm_surface_h t_surface = NULL;
+
   camerasrc = GST_TIZENCAMERA_SRC(src);
 
   GST_INFO_OBJECT(camerasrc, "ENTERED");
@@ -1779,6 +1953,30 @@ static gboolean gst_tizencamerasrc_set_caps(GstBaseSrc *src, GstCaps *caps)
     return FALSE;
   }
 
+  /* get tbm surface info */
+  if (!_gst_tizencamerasrc_get_tbm_format(camerasrc->pix_format, &camerasrc->tbm_format)) {
+    GST_ERROR_OBJECT(camerasrc, "failed to get tbm format");
+    return FALSE;
+  }
+
+  t_surface = tbm_surface_create(camerasrc->width, camerasrc->height, camerasrc->tbm_format);
+  if (!t_surface) {
+    GST_ERROR_OBJECT(camerasrc, "tbm surface create failed");
+    return FALSE;
+  }
+
+  memset(&camerasrc->ts_info, 0x0, sizeof(tbm_surface_info_s));
+
+  tbm_ret = tbm_surface_get_info(t_surface, &camerasrc->ts_info);
+
+  tbm_surface_destroy(t_surface);
+  t_surface = NULL;
+
+  if (tbm_ret != TBM_SURFACE_ERROR_NONE) {
+    GST_ERROR_OBJECT(camerasrc, "tbm surface info get failed");
+    return FALSE;
+  }
+
   GST_INFO("            gst_tizencamerasrc_start");
   if (!gst_tizencamerasrc_start(camerasrc)) {
     GST_INFO_OBJECT (camerasrc,  "Cam sensor start failed.");
@@ -1997,6 +2195,9 @@ static void gst_tizencamerasrc_init(GstTizenCameraSrc *camerasrc)
   g_mutex_init(&camerasrc->buffer_lock);
   g_cond_init(&camerasrc->buffer_cond);
 
+  /* tizen allocator */
+  camerasrc->allocator = gst_tizen_allocator_new();
+
   /* we operate in time */
   gst_base_src_set_format(GST_BASE_SRC(camerasrc), GST_FORMAT_TIME);
   gst_base_src_set_live(GST_BASE_SRC(camerasrc), TRUE);
index f87f91e..5796aa2 100644 (file)
 #include <gst/video/colorbalance.h>
 #include <gst/video/cameracontrol.h>
 #include <gst/video/video-format.h>
+#include <gst/allocators/gsttizenmemory.h>
 
 #include "camera_hal_interface.h"
 
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+
 
 G_BEGIN_DECLS
 #define GST_TYPE_TIZENCAMERA_SRC             (gst_tizencamerasrc_get_type())
@@ -53,13 +57,30 @@ G_BEGIN_DECLS
 
 typedef struct _GstTizenCameraSrc GstTizenCameraSrc;
 typedef struct _GstTizenCameraSrcClass GstTizenCameraSrcClass;
+typedef struct _GstTizenCameraBuffer GstTizenCameraBuffer;
+typedef enum {
+  BUFFER_TYPE_PREVIEW = 0,
+  BUFFER_TYPE_VIDEO,
+  BUFFER_TYPE_NUM
+} GstTizenCameraBufferType;
+
+struct _GstTizenCameraBuffer {
+  GstBuffer *buffer;
+  GstTizenCameraSrc *camerasrc;
+  GstTizenCameraBufferType type;
+  int index;
+  tbm_surface_h t_surface;
+};
 
 struct _GstTizenCameraSrc
 {
   GstPushSrc element;
+  GstAllocator *allocator;
 
   /* Video info */
-  GstVideoInfo vinfo;
+  GstVideoInfo video_info;
+  tbm_surface_info_s ts_info;
+  guint32 tbm_format;
 
   /*private*/
   camera_hal_interface *hal_intf_handle;  /**< Camera HAL interface handle */
@@ -68,6 +89,7 @@ struct _GstTizenCameraSrc
   gboolean hflip;                         /**< flip camera input horizontally */
   gboolean firsttime;
   gboolean is_flushing;
+  int num_live_buffers;
 
   int cap_count_current;                  /**< current capture count */
   int cap_count_reverse;                  /**< current capture count (reverse counting) */
@@ -88,15 +110,11 @@ struct _GstTizenCameraSrc
   int rotate;                             /**< Video source rotate */
   gboolean use_rotate_caps;               /**< Use or not rotate value in caps */
 
-  GCond buffer_cond;                     /**< condition for buffer control */
-  GMutex buffer_lock;                    /**< lock for buffer control */
-  gboolean buffer_running;                /**< with lock */
-
   /* Colorbalance , CameraControl interface */
   GList *colors;
   GList *camera_controls;
 
-  /*capture property*/
+  /* capture property */
   guint32 cap_fourcc;                     /**< gstreamer fourcc value(GST_MAKE_FOURCC format) for raw capturing */
   int cap_width;                          /**< Capture width */
   int cap_height;                         /**< Capture height */
@@ -104,6 +122,11 @@ struct _GstTizenCameraSrc
   int cap_count;                          /**< Capture count */
   int cap_jpg_quality;                    /**< Capture quality for jpg compress ratio */
   gboolean cap_provide_exif;              /**< Is exif provided? */
+
+  /* buffer control */
+  GCond buffer_cond;                      /**< condition for buffer control */
+  GMutex buffer_lock;                     /**< lock for buffer control */
+  gboolean buffer_running;                /**< flag for buffer running */
 };
 
 struct _GstTizenCameraSrcClass {