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
#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
/******************************************************************************
* 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) {
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);
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;
}
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) {
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 {
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);
}
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");
return GST_FLOW_FLUSHING;
}
- /* set timestamp and duration */
- gst_tizencamerasrc_get_timeinfo(camerasrc, *buffer);
-
if (camerasrc->firsttime) {
camerasrc->firsttime = FALSE;
}
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);
}
+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) {
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;
}
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");
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.");
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);