summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--include/camera.h14
-rw-r--r--include/camera_private.h10
-rw-r--r--packaging/capi-media-camera.spec3
-rwxr-xr-xsrc/camera.c543
-rw-r--r--test/multimedia_camera_test.c38
6 files changed, 555 insertions, 55 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bfa1a5f..ac57dd2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,7 +9,7 @@ SET(service "media")
SET(submodule "camera")
# for package file
-SET(dependents "libtbm dlog mm-common capi-base-common capi-media-tool mm-camcorder ecore elementary mmsvc-camera")
+SET(dependents "libtbm dlog mm-common capi-base-common capi-media-tool mm-camcorder ecore elementary mmsvc-camera gstreamer-1.0")
SET(pc_dependents "capi-base-common capi-media-tool libtbm evas ecore elementary")
SET(fw_name "${project_prefix}-${service}-${submodule}")
diff --git a/include/camera.h b/include/camera.h
index 154458a..dfaed59 100644
--- a/include/camera.h
+++ b/include/camera.h
@@ -517,7 +517,7 @@ typedef void (*camera_focus_changed_cb)(camera_focus_state_e state, void *user_d
* @brief Called to register for notifications about delivering a copy of the new preview frame when every preview frame is displayed.
* @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
*
- * @remarks This function is issued in the context of gstreamer so the UI update code should not be directly invoked.\n
+ * @remarks This function is issued in the context of internal framework so the UI update code should not be directly invoked.\n
* If the camera is used as a recorder then this callback function won't be called.
*
* @param[in] frame The reference pointer to preview stream data
@@ -533,7 +533,7 @@ typedef void (*camera_preview_cb)(camera_preview_data_s *frame, void *user_data)
* @brief Called to register for notifications about delivering media packet when every preview frame is displayed.
* @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
*
- * @remarks This function is issued in the context of gstreamer so the UI update code should not be directly invoked.\n
+ * @remarks This function is issued in the context of internal framework so the UI update code should not be directly invoked.\n
* If the camera is used as a recorder then this callback function won't be called.\n
* and the packet should be released by media_packet_destroy() after use.
*
@@ -1549,10 +1549,12 @@ bool camera_is_supported_media_packet_preview_cb(camera_h camera);
* @remarks This callback does not work in the video recorder mode.\n
* This function should be called before previewing (see camera_start_preview()).\n
* A registered callback is called on the internal thread of the camera.\n
- * A video frame can be retrieved using a registered callback.\n
- * The callback function holds the same buffer that will be drawn on the display device.\n
- * So if you change the buffer in a registerd callback, it will be displayed on the device\n
- * and the buffer is only available in a registerd callback.
+ * A video frame can be retrieved using a registered callback,\n
+ * and the buffer is only available in a registerd callback.\n
+ * Since tizen 3.0, if you change the buffer in a registered callback,\n
+ * it could not be displayed on the device in case of copied buffer.\n
+ * and if camera_is_supported_media_packet_preview_cb() returns false,\n
+ * it's copied buffer case.
* @param[in] camera The handle to the camera
* @param[in] callback The callback function to be registered
* @param[in] user_data The user data to be passed to the callback function
diff --git a/include/camera_private.h b/include/camera_private.h
index 3339ae8..913b9f8 100644
--- a/include/camera_private.h
+++ b/include/camera_private.h
@@ -25,6 +25,7 @@
#include <muse_camera.h>
#include <mm_camcorder.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -76,6 +77,8 @@ typedef struct _callback_cb_info {
gint *activating;
tbm_bufmgr bufmgr;
GQueue *event_queue;
+ gint prev_state;
+ media_format_h pkt_fmt;
} callback_cb_info_s;
typedef struct _camera_event_s {
@@ -101,6 +104,13 @@ typedef struct _camera_cli_s {
#endif /* #ifdef HAVE_WAYLAND */
} camera_cli_s;
+typedef struct _camera_media_packet_data {
+ int tbm_key;
+ tbm_bo bo;
+ tbm_bo buffer_bo[BUFFER_MAX_PLANE_NUM];
+ int num_buffer_key;
+} camera_media_packet_data;
+
typedef enum {
MUSE_CAMERA_CLIENT_SYNC_CB_HANDLER,
MUSE_CAMERA_CLIENT_USER_CALLBACK,
diff --git a/packaging/capi-media-camera.spec b/packaging/capi-media-camera.spec
index 4a7a777..75d142f 100644
--- a/packaging/capi-media-camera.spec
+++ b/packaging/capi-media-camera.spec
@@ -3,7 +3,7 @@
Name: capi-media-camera
Summary: A Camera API
-Version: 0.2.20
+Version: 0.2.21
Release: 0
Group: Multimedia/API
License: Apache-2.0
@@ -21,6 +21,7 @@ BuildRequires: pkgconfig(ecore)
BuildRequires: pkgconfig(evas)
BuildRequires: pkgconfig(capi-media-tool)
BuildRequires: pkgconfig(mm-camcorder)
+BuildRequires: pkgconfig(gstreamer-1.0)
%if %{with wayland}
BuildRequires: pkgconfig(ecore-wayland)
%endif
diff --git a/src/camera.c b/src/camera.c
index b3a5e3a..830a667 100755
--- a/src/camera.c
+++ b/src/camera.c
@@ -29,6 +29,9 @@
//#include <glib.h>
#include <dlog.h>
#include <Elementary.h>
+#include <tbm_surface_internal.h>
+#include <gst/gst.h>
+#include <mm_camcorder.h>
#include <mm_camcorder_client.h>
#include <Evas.h>
#ifdef HAVE_WAYLAND
@@ -225,7 +228,7 @@ static int _import_tbm_key(tbm_bufmgr bufmgr, unsigned int tbm_key, tbm_bo *bo,
static void _release_imported_bo(tbm_bo *bo)
{
if (bo == NULL || *bo == NULL) {
- LOGE("NULL bo");
+ LOGW("NULL bo");
return;
}
@@ -274,6 +277,174 @@ static int _client_wait_for_cb_return(muse_camera_api_e api, callback_cb_info_s
return ret;
}
+int _camera_get_tbm_surface_format(int in_format, uint32_t *out_format)
+{
+ if (in_format <= MM_PIXEL_FORMAT_INVALID ||
+ in_format >= MM_PIXEL_FORMAT_NUM ||
+ out_format == NULL) {
+ LOGE("INVALID_PARAMETER : in_format %d, out_format ptr %p", in_format, out_format);
+ return CAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ switch (in_format) {
+ case MM_PIXEL_FORMAT_NV12:
+ case MM_PIXEL_FORMAT_NV12T:
+ *out_format = TBM_FORMAT_NV12;
+ break;
+ case MM_PIXEL_FORMAT_NV16:
+ *out_format = TBM_FORMAT_NV16;
+ break;
+ case MM_PIXEL_FORMAT_NV21:
+ *out_format = TBM_FORMAT_NV21;
+ break;
+ case MM_PIXEL_FORMAT_YUYV:
+ *out_format = TBM_FORMAT_YUYV;
+ break;
+ case MM_PIXEL_FORMAT_UYVY:
+ case MM_PIXEL_FORMAT_ITLV_JPEG_UYVY:
+ *out_format = TBM_FORMAT_UYVY;
+ break;
+ case MM_PIXEL_FORMAT_422P:
+ *out_format = TBM_FORMAT_YUV422;
+ break;
+ case MM_PIXEL_FORMAT_I420:
+ *out_format = TBM_FORMAT_YUV420;
+ break;
+ case MM_PIXEL_FORMAT_YV12:
+ *out_format = TBM_FORMAT_YVU420;
+ break;
+ case MM_PIXEL_FORMAT_RGB565:
+ *out_format = TBM_FORMAT_RGB565;
+ break;
+ case MM_PIXEL_FORMAT_RGB888:
+ *out_format = TBM_FORMAT_RGB888;
+ break;
+ case MM_PIXEL_FORMAT_RGBA:
+ *out_format = TBM_FORMAT_RGBA8888;
+ break;
+ case MM_PIXEL_FORMAT_ARGB:
+ *out_format = TBM_FORMAT_ARGB8888;
+ break;
+ default:
+ LOGE("invalid in_format %d", in_format);
+ return CAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ return CAMERA_ERROR_NONE;
+}
+
+
+int _camera_get_media_packet_mimetype(int in_format, media_format_mimetype_e *mimetype)
+{
+ if (in_format <= MM_PIXEL_FORMAT_INVALID ||
+ in_format >= MM_PIXEL_FORMAT_NUM ||
+ mimetype == NULL) {
+ LOGE("INVALID_PARAMETER : in_format %d, mimetype ptr %p", in_format, mimetype);
+ return CAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ switch (in_format) {
+ case MM_PIXEL_FORMAT_NV12:
+ case MM_PIXEL_FORMAT_NV12T:
+ *mimetype = MEDIA_FORMAT_NV12;
+ break;
+ case MM_PIXEL_FORMAT_NV16:
+ *mimetype = MEDIA_FORMAT_NV16;
+ break;
+ case MM_PIXEL_FORMAT_NV21:
+ *mimetype = MEDIA_FORMAT_NV21;
+ break;
+ case MM_PIXEL_FORMAT_YUYV:
+ *mimetype = MEDIA_FORMAT_YUYV;
+ break;
+ case MM_PIXEL_FORMAT_UYVY:
+ case MM_PIXEL_FORMAT_ITLV_JPEG_UYVY:
+ *mimetype = MEDIA_FORMAT_UYVY;
+ break;
+ case MM_PIXEL_FORMAT_422P:
+ *mimetype = MEDIA_FORMAT_422P;
+ break;
+ case MM_PIXEL_FORMAT_I420:
+ *mimetype = MEDIA_FORMAT_I420;
+ break;
+ case MM_PIXEL_FORMAT_YV12:
+ *mimetype = MEDIA_FORMAT_YV12;
+ break;
+ case MM_PIXEL_FORMAT_RGB565:
+ *mimetype = MEDIA_FORMAT_RGB565;
+ break;
+ case MM_PIXEL_FORMAT_RGB888:
+ *mimetype = MEDIA_FORMAT_RGB888;
+ break;
+ case MM_PIXEL_FORMAT_RGBA:
+ *mimetype = MEDIA_FORMAT_RGBA;
+ break;
+ case MM_PIXEL_FORMAT_ARGB:
+ *mimetype = MEDIA_FORMAT_ARGB;
+ break;
+ default:
+ LOGE("invalid in_format %d", in_format);
+ return CAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ return CAMERA_ERROR_NONE;
+}
+
+int _camera_media_packet_finalize(media_packet_h pkt, int error_code, void *user_data)
+{
+ int i = 0;
+ int ret = 0;
+ callback_cb_info_s *cb_info = (callback_cb_info_s *)user_data;
+ camera_media_packet_data *mp_data = NULL;
+ tbm_surface_h tsurf = NULL;
+
+ if (pkt == NULL || cb_info == NULL) {
+ LOGE("invalid parameter buffer %p, cb_info %p", pkt, cb_info);
+ return MEDIA_PACKET_FINALIZE;
+ }
+
+ ret = media_packet_get_extra(pkt, (void **)&mp_data);
+ if (ret != MEDIA_PACKET_ERROR_NONE) {
+ LOGE("media_packet_get_extra failed 0x%x", ret);
+ return MEDIA_PACKET_FINALIZE;
+ }
+
+ /*LOGD("mp_data %p", mp_data);*/
+
+ if (mp_data) {
+ int tbm_key = mp_data->tbm_key;
+
+ /* release imported bo */
+ for (i = 0 ; i < mp_data->num_buffer_key ; i++) {
+ tbm_bo_unref(mp_data->buffer_bo[i]);
+ mp_data->buffer_bo[i] = NULL;
+ }
+
+ /* unmap and unref tbm bo */
+ _release_imported_bo(&mp_data->bo);
+
+ /* return buffer */
+ muse_camera_msg_send1_no_return(MUSE_CAMERA_API_RETURN_BUFFER,
+ cb_info->fd, cb_info,
+ INT, tbm_key);
+
+ mp_data = NULL;
+ }
+
+ ret = media_packet_get_tbm_surface(pkt, &tsurf);
+ if (ret != MEDIA_PACKET_ERROR_NONE) {
+ LOGE("media_packet_get_tbm_surface failed 0x%x", ret);
+ return MEDIA_PACKET_FINALIZE;
+ }
+
+ if (tsurf) {
+ tbm_surface_destroy(tsurf);
+ tsurf = NULL;
+ }
+
+ return MEDIA_PACKET_FINALIZE;
+}
+
static void _client_user_callback(callback_cb_info_s *cb_info, char *recvMsg, muse_camera_event_e event)
{
int param1 = 0;
@@ -331,12 +502,24 @@ static void _client_user_callback(callback_cb_info_s *cb_info, char *recvMsg, mu
((camera_capture_completed_cb)cb_info->user_cb[event])(cb_info->user_data[event]);
break;
case MUSE_CAMERA_EVENT_TYPE_PREVIEW:
+ case MUSE_CAMERA_EVENT_TYPE_MEDIA_PACKET_PREVIEW:
{
+ camera_preview_data_s frame;
unsigned char *buf_pos = NULL;
- camera_preview_data_s *frame = NULL;
+ MMCamcorderVideoStreamDataType *stream = NULL;
+ int i = 0;
int total_size = 0;
+ int num_buffer_key = 0;
+ int buffer_key[BUFFER_MAX_PLANE_NUM] = {0, };
+ tbm_bo buffer_bo[BUFFER_MAX_PLANE_NUM] = {NULL, };
+ tbm_bo_handle buffer_bo_handle[BUFFER_MAX_PLANE_NUM] = {{.ptr = NULL}, };
+ camera_media_packet_data *mp_data = NULL;
muse_camera_msg_get(tbm_key, recvMsg);
+ muse_camera_msg_get(num_buffer_key, recvMsg);
+ muse_camera_msg_get_array(buffer_key, recvMsg);
+
+ memset(&frame, 0x0, sizeof(camera_preview_data_s));
if (tbm_key <= 0) {
LOGE("invalid key %d", tbm_key);
@@ -345,58 +528,314 @@ static void _client_user_callback(callback_cb_info_s *cb_info, char *recvMsg, mu
/* import tbm bo and get virtual address */
if (!_import_tbm_key(cb_info->bufmgr, tbm_key, &bo, &bo_handle)) {
+ LOGE("failed to import key %d", tbm_key);
+
+ muse_camera_msg_send1_no_return(MUSE_CAMERA_API_RETURN_BUFFER,
+ cb_info->fd, cb_info,
+ INT, tbm_key);
break;
}
buf_pos = (unsigned char *)bo_handle.ptr;
- frame = (camera_preview_data_s *)buf_pos;
- buf_pos += sizeof(camera_preview_data_s);
-
- switch (frame->num_of_planes) {
- case 1:
- frame->data.single_plane.yuv = buf_pos;
- total_size = frame->data.single_plane.size;
- case 2:
- frame->data.double_plane.y = buf_pos;
- buf_pos += frame->data.double_plane.y_size;
- frame->data.double_plane.uv = buf_pos;
- total_size = frame->data.double_plane.y_size + \
- frame->data.double_plane.uv_size;
- case 3:
- frame->data.triple_plane.y = buf_pos;
- buf_pos += frame->data.triple_plane.y_size;
- frame->data.triple_plane.u = buf_pos;
- buf_pos += frame->data.triple_plane.u_size;
- frame->data.triple_plane.v = buf_pos;
- total_size = frame->data.triple_plane.y_size + \
- frame->data.triple_plane.u_size + \
- frame->data.triple_plane.v_size;
- default:
- break;
+ /* get stream info */
+ stream = (MMCamcorderVideoStreamDataType *)buf_pos;
+
+ for (i = 0 ; i < num_buffer_key ; i++) {
+ /* import buffer bo and get virtual address */
+ if (!_import_tbm_key(cb_info->bufmgr, buffer_key[i], &buffer_bo[i], &buffer_bo_handle[i])) {
+ LOGE("failed to import buffer key %d", buffer_key[i]);
+
+ /* release imported bo */
+ for (i -= 1 ; i >= 0 ; i--) {
+ _release_imported_bo(&buffer_bo[i]);
+ }
+ _release_imported_bo(&bo);
+
+ /* send return buffer */
+ muse_camera_msg_send1_no_return(MUSE_CAMERA_API_RETURN_BUFFER,
+ cb_info->fd, cb_info,
+ INT, tbm_key);
+ return;
+ }
}
- LOGD("PREVIEW_CB - format %d, %dx%d, size %d plane num %d",
- frame->format, frame->width, frame->height, total_size, frame->num_of_planes);
+ if (cb_info->user_cb[MUSE_CAMERA_EVENT_TYPE_PREVIEW]) {
+ /* set frame info */
+ if (stream->format == MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) {
+ frame.format = MM_PIXEL_FORMAT_UYVY;
+ } else {
+ frame.format = stream->format;
+ }
+ frame.width = stream->width;
+ frame.height = stream->height;
+ frame.timestamp = stream->timestamp;
+ frame.num_of_planes = stream->num_planes;
+
+ if (num_buffer_key == 0) {
+ /* non-zero copy */
+ buf_pos += sizeof(MMCamcorderVideoStreamDataType);
+ switch (stream->num_planes) {
+ case 1:
+ frame.data.single_plane.yuv = buf_pos;
+ frame.data.single_plane.size = stream->data.yuv420.length_yuv;
+ total_size = stream->data.yuv420.length_yuv;
+ case 2:
+ frame.data.double_plane.y = buf_pos;
+ frame.data.double_plane.y_size = stream->data.yuv420sp.length_y;
+ buf_pos += stream->data.yuv420sp.length_y;
+ frame.data.double_plane.uv = buf_pos;
+ frame.data.double_plane.uv_size = stream->data.yuv420sp.length_uv;
+ total_size = stream->data.yuv420sp.length_y + \
+ stream->data.yuv420sp.length_uv;
+ case 3:
+ frame.data.triple_plane.y = buf_pos;
+ frame.data.triple_plane.y_size = stream->data.yuv420p.length_y;
+ buf_pos += stream->data.yuv420p.length_y;
+ frame.data.triple_plane.u = buf_pos;
+ frame.data.triple_plane.u_size = stream->data.yuv420p.length_u;
+ buf_pos += stream->data.yuv420p.length_u;
+ frame.data.triple_plane.v = buf_pos;
+ frame.data.triple_plane.v_size = stream->data.yuv420p.length_v;
+ total_size = stream->data.yuv420p.length_y + \
+ stream->data.yuv420p.length_u + \
+ stream->data.yuv420p.length_v;
+ default:
+ break;
+ }
+ } else {
+ /* zero copy */
+ switch (stream->num_planes) {
+ case 1:
+ frame.data.single_plane.yuv = buffer_bo_handle[0].ptr;
+ frame.data.single_plane.size = stream->data.yuv420.length_yuv;
+ total_size = stream->data.yuv420.length_yuv;
+ case 2:
+ frame.data.double_plane.y = buffer_bo_handle[0].ptr;
+ if (stream->num_planes == (unsigned int)num_buffer_key) {
+ frame.data.double_plane.uv = buffer_bo_handle[1].ptr;
+ } else {
+ frame.data.double_plane.uv = buffer_bo_handle[0].ptr + stream->data.yuv420sp.length_y;
+ }
+ frame.data.double_plane.y_size = stream->data.yuv420sp.length_y;
+ frame.data.double_plane.uv_size = stream->data.yuv420sp.length_uv;
+ total_size = stream->data.yuv420sp.length_y + \
+ stream->data.yuv420sp.length_uv;
+ case 3:
+ frame.data.triple_plane.y = buffer_bo_handle[0].ptr;
+ if (stream->num_planes == (unsigned int)num_buffer_key) {
+ frame.data.triple_plane.u = buffer_bo_handle[1].ptr;
+ frame.data.triple_plane.v = buffer_bo_handle[2].ptr;
+ } else {
+ frame.data.triple_plane.u = buffer_bo_handle[0].ptr + stream->data.yuv420p.length_y;
+ frame.data.triple_plane.v = buffer_bo_handle[1].ptr + stream->data.yuv420p.length_u;
+ }
+ frame.data.triple_plane.y_size = stream->data.yuv420p.length_y;
+ frame.data.triple_plane.u_size = stream->data.yuv420p.length_u;
+ frame.data.triple_plane.v_size = stream->data.yuv420p.length_v;
+ total_size = stream->data.yuv420p.length_y + \
+ stream->data.yuv420p.length_u + \
+ stream->data.yuv420p.length_v;
+ default:
+ break;
+ }
+ }
- ((camera_preview_cb)cb_info->user_cb[event])(frame, cb_info->user_data[event]);
+ /*
+ LOGD("PREVIEW_CB - format %d, %dx%d, size %d plane num %d",
+ frame.format, frame.width, frame.height, total_size, frame.num_of_planes);
+ */
- LOGD("PREVIEW_CB retuned");
+ ((camera_preview_cb)cb_info->user_cb[event])(&frame, cb_info->user_data[event]);
- /* unmap and unref tbm bo */
- _release_imported_bo(&bo);
+ /*LOGD("PREVIEW_CB retuned");*/
+ }
- /* return buffer */
- muse_camera_msg_send1_no_return(MUSE_CAMERA_API_RETURN_BUFFER,
- cb_info->fd, cb_info,
- INT, tbm_key);
+ if (cb_info->user_cb[MUSE_CAMERA_EVENT_TYPE_MEDIA_PACKET_PREVIEW]) {
+ media_packet_h pkt = NULL;
+ tbm_surface_h tsurf = NULL;
+ uint32_t bo_format = 0;
+ int ret = 0;
+ media_format_mimetype_e mimetype = MEDIA_FORMAT_NV12;
+ bool make_pkt_fmt = false;
+ tbm_surface_info_s tsurf_info;
+
+ memset(&tsurf_info, 0x0, sizeof(tbm_surface_info_s));
+
+ /* unmap buffer bo */
+ for (i = 0 ; i < num_buffer_key ; i++) {
+ if (buffer_bo[i]) {
+ tbm_bo_unmap(buffer_bo[i]);
+ }
+ }
+
+ /* create tbm surface */
+ for (i = 0 ; i < BUFFER_MAX_PLANE_NUM ; i++) {
+ tsurf_info.planes[i].stride = stream->stride[i];
+ }
+
+ /* get tbm surface format */
+ ret = _camera_get_tbm_surface_format(stream->format, &bo_format);
+ ret |= _camera_get_media_packet_mimetype(stream->format, &mimetype);
+
+ if (num_buffer_key > 0 && ret == CAMERA_ERROR_NONE) {
+ tsurf_info.width = stream->width;
+ tsurf_info.height = stream->height;
+ tsurf_info.format = bo_format;
+ tsurf_info.bpp = tbm_surface_internal_get_bpp(bo_format);
+ tsurf_info.num_planes = tbm_surface_internal_get_num_planes(bo_format);
+
+ switch (bo_format) {
+ case TBM_FORMAT_NV12:
+ case TBM_FORMAT_NV21:
+ tsurf_info.planes[0].size = stream->stride[0] * stream->elevation[0];
+ tsurf_info.planes[1].size = stream->stride[1] * stream->elevation[1];
+ tsurf_info.planes[0].offset = 0;
+ if (num_buffer_key == 1) {
+ tsurf_info.planes[1].offset = tsurf_info.planes[0].size;
+ }
+ tsurf_info.size = tsurf_info.planes[0].size + tsurf_info.planes[1].size;
+ break;
+ case TBM_FORMAT_YUV420:
+ case TBM_FORMAT_YVU420:
+ tsurf_info.planes[0].size = stream->stride[0] * stream->elevation[0];
+ tsurf_info.planes[1].size = stream->stride[1] * stream->elevation[1];
+ tsurf_info.planes[2].size = stream->stride[2] * stream->elevation[2];
+ tsurf_info.planes[0].offset = 0;
+ if (num_buffer_key == 1) {
+ tsurf_info.planes[1].offset = tsurf_info.planes[0].size;
+ tsurf_info.planes[2].offset = tsurf_info.planes[0].size + tsurf_info.planes[1].size;
+ }
+ tsurf_info.size = tsurf_info.planes[0].size + tsurf_info.planes[1].size + tsurf_info.planes[2].size;
+ break;
+ case TBM_FORMAT_UYVY:
+ case TBM_FORMAT_YUYV:
+ tsurf_info.planes[0].size = (stream->stride[0] * stream->elevation[0]) << 1;
+ tsurf_info.planes[0].offset = 0;
+ tsurf_info.size = tsurf_info.planes[0].size;
+ break;
+ default:
+ break;
+ }
+
+ tsurf = tbm_surface_internal_create_with_bos(&tsurf_info, buffer_bo, num_buffer_key);
+ /*LOGD("tbm surface %p", tsurf);*/
+ }
+
+ if (tsurf) {
+ /* check media packet format */
+ if (cb_info->pkt_fmt) {
+ int pkt_fmt_width = 0;
+ int pkt_fmt_height = 0;
+ media_format_mimetype_e pkt_fmt_mimetype = MEDIA_FORMAT_NV12;
+
+ media_format_get_video_info(cb_info->pkt_fmt, &pkt_fmt_mimetype, &pkt_fmt_width, &pkt_fmt_height, NULL, NULL);
+ if (pkt_fmt_mimetype != mimetype ||
+ pkt_fmt_width != stream->width ||
+ pkt_fmt_height != stream->height) {
+ LOGW("different format. current 0x%x, %dx%d, new 0x%x, %dx%d",
+ pkt_fmt_mimetype, pkt_fmt_width, pkt_fmt_height, mimetype, stream->width, stream->height);
+ media_format_unref(cb_info->pkt_fmt);
+ cb_info->pkt_fmt = NULL;
+ make_pkt_fmt = true;
+ }
+ } else {
+ make_pkt_fmt = true;
+ }
+
+ /* create packet format */
+ if (make_pkt_fmt) {
+ LOGW("make new pkt_fmt - mimetype 0x%x, %dx%d", mimetype, stream->width, stream->height);
+ ret = media_format_create(&cb_info->pkt_fmt);
+ if (ret == MEDIA_FORMAT_ERROR_NONE) {
+ ret = media_format_set_video_mime(cb_info->pkt_fmt, mimetype);
+ ret |= media_format_set_video_width(cb_info->pkt_fmt, stream->width);
+ ret |= media_format_set_video_height(cb_info->pkt_fmt, stream->height);
+ LOGW("media_format_set_video_mime,width,height ret : 0x%x", ret);
+ } else {
+ LOGW("media_format_create failed");
+ }
+ }
+
+ /* create media packet */
+ ret = media_packet_create_from_tbm_surface(cb_info->pkt_fmt,
+ tsurf,
+ (media_packet_finalize_cb)_camera_media_packet_finalize,
+ (void *)cb_info,
+ &pkt);
+ if (ret != MEDIA_PACKET_ERROR_NONE) {
+ LOGE("media_packet_create_from_tbm_surface failed");
+
+ tbm_surface_destroy(tsurf);
+ tsurf = NULL;
+ }
+ } else {
+ LOGE("failed to create tbm surface %dx%d, format %d, num_buffer_key %d",
+ stream->width, stream->height, stream->format, num_buffer_key);
+ }
+
+ if (pkt) {
+ /*LOGD("media packet %p, internal buffer %p", pkt, stream->internal_buffer);*/
+
+ mp_data = g_new0(camera_media_packet_data, 1);
+ if (mp_data) {
+ mp_data->tbm_key = tbm_key;
+ mp_data->num_buffer_key = num_buffer_key;
+ mp_data->bo = bo;
+ for (i = 0 ; i < num_buffer_key ; i++) {
+ mp_data->buffer_bo[i] = buffer_bo[i];
+ }
+
+ /* set media packet data */
+ ret = media_packet_set_extra(pkt, (void *)mp_data);
+ if (ret != MEDIA_PACKET_ERROR_NONE) {
+ LOGE("media_packet_set_extra failed");
+
+ if (mp_data) {
+ g_free(mp_data);
+ mp_data = NULL;
+ }
+
+ media_packet_destroy(pkt);
+ pkt = NULL;
+ } else {
+ int e_type = MUSE_CAMERA_EVENT_TYPE_MEDIA_PACKET_PREVIEW;
+
+ /* set timestamp : msec -> nsec */
+ if (media_packet_set_pts(pkt, (uint64_t)(stream->timestamp) * 1000000) != MEDIA_PACKET_ERROR_NONE) {
+ LOGW("media_packet_set_pts failed");
+ }
+
+ /* call media packet callback */
+ ((camera_media_packet_preview_cb)cb_info->user_cb[e_type])(pkt, cb_info->user_data[e_type]);
+ }
+ } else {
+ LOGE("failed to alloc media packet data");
+ }
+ }
+ }
+
+ /* send message for preview callback return */
+ muse_camera_msg_send_no_return(MUSE_CAMERA_API_PREVIEW_CB_RETURN, cb_info->fd, cb_info);
+
+ if (mp_data == NULL) {
+ /* release imported bo */
+ for (i = 0 ; i < num_buffer_key ; i++) {
+ _release_imported_bo(&buffer_bo[i]);
+ }
+
+ /* unmap and unref tbm bo */
+ _release_imported_bo(&bo);
+
+ /* return buffer */
+ muse_camera_msg_send1_no_return(MUSE_CAMERA_API_RETURN_BUFFER,
+ cb_info->fd, cb_info,
+ INT, tbm_key);
- LOGD("return buffer Done");
+ /*LOGD("return buffer Done");*/
+ }
}
break;
- case MUSE_CAMERA_EVENT_TYPE_MEDIA_PACKET_PREVIEW:
- ((camera_media_packet_preview_cb)cb_info->user_cb[event])(NULL, cb_info->user_data[event]);
- break;
case MUSE_CAMERA_EVENT_TYPE_HDR_PROGRESS:
{
int percent = 0;
@@ -855,6 +1294,7 @@ static void *_client_cb_handler(gpointer data)
int i = 0;
int str_pos = 0;
int prev_pos = 0;
+ int prev_state = CAMERA_STATE_NONE;
callback_cb_info_s *cb_info = (callback_cb_info_s *)data;
char *recvMsg = NULL;
char **parseStr = NULL;
@@ -924,8 +1364,6 @@ static void *_client_cb_handler(gpointer data)
strcpy(cb_info->recvApiMsg, parseStr[i]);
LOGD("cb_info->recvApiMsg : [%s]", cb_info->recvApiMsg);
cb_info->activating[api] = 1;
- g_cond_signal(&(cb_info->pCond[api]));
- g_mutex_unlock(&(cb_info->pMutex[api]));
if (api == MUSE_CAMERA_API_CREATE) {
if (muse_camera_msg_get(ret, cb_info->recvApiMsg)) {
@@ -945,7 +1383,13 @@ static void *_client_cb_handler(gpointer data)
} else {
LOGE("failed to get api return");
}
+ } else if (api == MUSE_CAMERA_API_START_PREVIEW) {
+ muse_camera_msg_get(prev_state, cb_info->recvApiMsg);
+ cb_info->prev_state = prev_state;
}
+
+ g_cond_signal(&(cb_info->pCond[api]));
+ g_mutex_unlock(&(cb_info->pMutex[api]));
} else if(api == MUSE_CAMERA_CB_EVENT) {
int event = -1;
int class = -1;
@@ -1098,15 +1542,21 @@ static void _client_callback_destroy(callback_cb_info_s * cb_info)
tbm_bufmgr_deinit(cb_info->bufmgr);
cb_info->bufmgr = NULL;
}
-
if (cb_info->pCond) {
g_free(cb_info->pCond);
+ cb_info->pCond = NULL;
}
if (cb_info->pMutex) {
g_free(cb_info->pMutex);
+ cb_info->pMutex = NULL;
}
if (cb_info->activating) {
g_free(cb_info->activating);
+ cb_info->activating = NULL;
+ }
+ if (cb_info->pkt_fmt) {
+ media_format_unref(cb_info->pkt_fmt);
+ cb_info->pkt_fmt = NULL;
}
g_free(cb_info);
@@ -1231,6 +1681,8 @@ ErrorExit:
}
_camera_remove_idle_event_all(pc->cb_info);
_client_callback_destroy(pc->cb_info);
+ pc->cb_info = NULL;
+
#ifdef HAVE_WAYLAND
if (pc->wl_info) {
g_free(pc->wl_info);
@@ -1253,7 +1705,6 @@ int camera_start_preview(camera_h camera)
muse_camera_api_e api = MUSE_CAMERA_API_START_PREVIEW;
camera_cli_s *pc = (camera_cli_s *)camera;
int sock_fd = 0;
- int prev_state = CAMERA_STATE_NONE;
char caps[MUSE_CAMERA_MSG_MAX_LENGTH] = {0};
if (camera == NULL) {
@@ -1286,9 +1737,7 @@ int camera_start_preview(camera_h camera)
return ret;
}
- muse_camera_msg_get(prev_state, pc->cb_info->recvMsg);
-
- if (prev_state == CAMERA_STATE_CREATED) {
+ if (pc->cb_info->prev_state == CAMERA_STATE_CREATED) {
muse_camera_msg_get_string(caps, pc->cb_info->recvMsg);
if (caps == NULL) {
LOGE("failed to get caps string");
diff --git a/test/multimedia_camera_test.c b/test/multimedia_camera_test.c
index 2357d30..69070b9 100644
--- a/test/multimedia_camera_test.c
+++ b/test/multimedia_camera_test.c
@@ -1316,6 +1316,42 @@ static gboolean init_handle()
return TRUE;
}
+
+void _preview_cb(camera_preview_data_s *frame, void *user_data)
+{
+#if 0
+ FILE *fp = fopen("/opt/usr/media/test.yuv", "a");
+ if (fp == NULL) {
+ g_print("\n============ file open failed ===========================\n");
+ return;
+ }
+
+ switch (frame->num_of_planes) {
+ case 1:
+ fwrite(frame->data.single_plane.yuv, 1, frame->data.single_plane.size, fp);
+ case 2:
+ fwrite(frame->data.double_plane.y, 1, frame->data.double_plane.y_size, fp);
+ fwrite(frame->data.double_plane.uv, 1, frame->data.double_plane.uv_size, fp);
+ case 3:
+ fwrite(frame->data.triple_plane.y, 1, frame->data.triple_plane.y_size, fp);
+ fwrite(frame->data.triple_plane.u, 1, frame->data.triple_plane.u_size, fp);
+ fwrite(frame->data.triple_plane.v, 1, frame->data.triple_plane.v_size, fp);
+ default:
+ break;
+ }
+
+ g_print("file write done ---\n");
+
+ fclose(fp);
+ fp = NULL;
+#else
+ g_print("----- preview callback - format %d, %dx%d, num plane %d\n",
+ frame->format, frame->width, frame->height, frame->num_of_planes);
+#endif
+
+ return;
+}
+
/**
* This function is to change camcorder mode.
*
@@ -1392,6 +1428,8 @@ static gboolean mode_change()
camera_set_display_mode(hcamcorder->camera,0 ); //MM_DISPLAY_METHOD_LETTER_BOX
camera_set_display(hcamcorder->camera, CAMERA_DISPLAY_TYPE_OVERLAY, GET_DISPLAY(eo));
+ //camera_set_preview_cb(hcamcorder->camera, _preview_cb, hcamcorder->camera);
+
camera_start_preview(hcamcorder->camera);
g_get_current_time(&current_time);
timersub(&current_time, &previous_time, &res);