Name: espp-service
Summary: ESPP service package which contains client lib. and daemon binary
-Version: 0.3.11
-Release: 1
+Version: 0.3.12
+Release: 0
Group: Multimedia/Libraries
License: Apache-2.0
Source0: %{name}-%{version}.tar.gz
BuildRequires: pkgconfig(gio-2.0)
BuildRequires: pkgconfig(json-glib-1.0)
BuildRequires: pkgconfig(esplusplayer)
+BuildRequires: pkgconfig(libtbm)
+BuildRequires: pkgconfig(mm-common)
+BuildRequires: pkgconfig(mmutil-common)
+BuildRequires: pkgconfig(mmutil-imgp)
%if "%{use_service_app}" == "1"
BuildRequires: pkgconfig(capi-appfw-service-application)
BuildRequires: pkgconfig(capi-appfw-application)
USER_SRCS = ./src/daemon/*.c ./src/common/*.c
# User Defines
-USER_DEFS = USE_DLOG USE_SERVICE_APP ESPP_SERVICE_VERSION="0.3.11"
+USER_DEFS = USE_DLOG USE_SERVICE_APP ESPP_SERVICE_VERSION="0.3.12"
# User Includes
USER_INC_DIRS = ./src/daemon ./src/common ./inc ./inc/esplusplayer_capi
return ESPP_CLIENT_ERROR_NONE;
}
+static void __snapshot_destroy_cb(gpointer data)
+{
+ espp_callback_s *cb_data = (espp_callback_s *)data;
+ LOG_DEBUG("data[%p, calllback:%p, user_data:%p]", data, cb_data->callback, cb_data->user_data);
+ g_free(data);
+}
+
int espp_client_create(espp_h *espp)
{
espp_s *_espp;
g_mutex_init(&_espp->mutex);
g_mutex_init(&_espp->cb_mutex);
- if (espp_service_client_socket_request_create(_espp) != 0) {
- g_free(_espp);
- return ESPP_CLIENT_ERROR_INVALID_OPERATION;
- }
+ _espp->snapshot_cbs = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, __snapshot_destroy_cb);
+
+ if (espp_service_client_socket_request_create(_espp) != 0)
+ goto error;
if (espp_service_client_socket_request_init_event(_espp) != 0) {
espp_service_client_socket_request_destroy(_espp);
- g_free(_espp);
- return ESPP_CLIENT_ERROR_INVALID_OPERATION;
+ goto error;
}
*espp = _espp;
LOG_INFO("espp[%p] is created", *espp);
return ESPP_CLIENT_ERROR_NONE;
+
+error:
+ g_hash_table_destroy(_espp->snapshot_cbs);
+ g_mutex_clear(&_espp->mutex);
+ g_mutex_clear(&_espp->cb_mutex);
+ g_free(_espp);
+ return ESPP_CLIENT_ERROR_INVALID_OPERATION;
}
int espp_client_destroy(espp_h espp)
return ESPP_CLIENT_ERROR_INVALID_OPERATION;
}
+ if (_espp->snapshot_cbs) {
+ g_hash_table_destroy(_espp->snapshot_cbs);
+ _espp->snapshot_cbs = NULL;
+ }
+
g_mutex_unlock(&_espp->mutex);
g_mutex_clear(&_espp->mutex);
g_mutex_clear(&_espp->cb_mutex);
return ESPP_CLIENT_ERROR_NONE;
}
+
+int espp_client_take_snapshot(espp_h espp, espp_snapshot_cb callback, void *user_data)
+{
+ espp_s *_espp = (espp_s *)espp;
+ espp_callback_s *cb_data;
+ g_autoptr(GMutexLocker) locker = NULL;
+ gint *id;
+
+ RET_VAL_IF(!espp, ESPP_CLIENT_ERROR_INVALID_PARAMETER, "espp is NULL");
+ RET_VAL_IF(!callback, ESPP_CLIENT_ERROR_INVALID_PARAMETER, "callback is NULL");
+
+ locker = g_mutex_locker_new(&_espp->mutex);
+
+ cb_data = g_new0(espp_callback_s, 1);
+ cb_data->callback = callback;
+ cb_data->user_data = user_data;
+
+ id = g_new(gint, 1);
+ *id = ++_espp->snapshot_cb_id;
+ if (!g_hash_table_insert(_espp->snapshot_cbs, id, (gpointer)cb_data)) {
+ LOG_ERROR("should not be reached here, snapshot_cb_id[%d] already exist", _espp->snapshot_cb_id);
+ /* Due to the imple. of g_hash_table_insert() in this case, we need to alloc again for id. */
+ id = g_new(gint, 1);
+ *id = _espp->snapshot_cb_id--;
+ g_hash_table_remove(_espp->snapshot_cbs, id);
+ return ESPP_CLIENT_ERROR_INVALID_OPERATION;
+ }
+
+ if (espp_service_client_socket_request_take_snapshot(_espp, _espp->snapshot_cb_id) != 0)
+ return ESPP_CLIENT_ERROR_INVALID_OPERATION;
+
+ LOG_INFO("espp[%p] snapshot_cb_id[%d] callback[%p] user_data[%p]", espp, _espp->snapshot_cb_id, callback, user_data);
+
+ return ESPP_CLIENT_ERROR_NONE;
+}
*/
typedef void (*espp_buffer_status_cb)(espp_stream_type_e stream_type, espp_buffer_status_e buffer_status, void *user_data);
+/**
+ * @brief Called when an image is captured by espp_client_take_snapshot().
+ * @remarks The @a espp is the same object for which the callback was set.\n
+ * The @a espp should not be released.\n
+ * The @a data should not be released. The @a data can be used only in the callback. To use outside, make a copy.
+ * @param[in] espp ESPP service client handle
+ * @param[in] data The snapshot image data (24-bit RGB)
+ * @param[in] width The snapshot image width
+ * @param[in] height The snapshot image height
+ * @param[in] size The size of @a data
+ * @param[in] user_data The user data passed from the callback registration function
+ * @see espp_client_take_snapshot()
+ */
+typedef void (*espp_snapshot_cb)(espp_h espp, const char *data, int width, int height, unsigned int size, void *user_data);
+
/**
* @brief Called when a H/W resource of the ESPP service client handle has been conflicted.
* @param[in] user_data The user data passed from the callback registration function
*/
int espp_client_set_decoded_video_frame_buffer_type(espp_h espp, espp_decoded_video_frame_buffer_type_e type);
+/**
+ * @brief Takes a snapshot asynchronously.
+ * @param[in] espp ESPP service client handle
+ * @param[in] callback Callback function pointer
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #ESPP_CLIENT_ERROR_NONE Successful
+ * @retval #ESPP_CLIENT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #ESPP_CLIENT_ERROR_INVALID_OPERATION Invalid operation
+ * @pre #ESPP_DECODED_VIDEO_FRAME_BUFFER_TYPE_MANUAL_COPY must be set by espp_client_set_decoded_video_frame_buffer_type() before calling this function.
+ * @see espp_client_set_decoded_video_frame_buffer_type()
+ */
+int espp_client_take_snapshot(espp_h espp, espp_snapshot_cb callback, void *user_data);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
result->ret = 0;
}
+static int __read_buffer(int fd, gchar *buffer, uint32_t size)
+{
+ int ret;
+ uint32_t total = 0;
+ char str_error[MAX_ERROR_LEN] = {'\0',};
+
+ ASSERT(fd >= 0);
+ ASSERT(buffer);
+
+ do {
+ if ((ret = read(fd, buffer + total, size - total)) < 0) {
+ strerror_r(errno, str_error, sizeof(str_error));
+ LOG_ERROR("failed to read(), fd[%d], ret[%d], err: %s", fd, ret, str_error);
+ break;
+ }
+ total += ret;
+ } while (total < size);
+
+ if (total != size) {
+ LOG_ERROR("total[%u], expected size[%u]", total, size);
+ return -1;
+ }
+
+ LOG_DEBUG("fd[%d] buffer[%p, size:%u]", fd, buffer, size);
+
+ return 0;
+}
+
+static void __handle_event_cb_snapshot(espp_s *espp, espp_service_data_from_server_s *data, espp_service_data_from_client_s *result)
+{
+ int ret;
+ int32_t cb_id;
+ uint32_t width;
+ uint32_t height;
+ uint32_t size;
+ g_autofree gchar *buffer = NULL;
+ g_autofree gint *id = NULL;
+ espp_callback_s *cb_data;
+
+ ASSERT(espp);
+ ASSERT(data);
+ ASSERT(result);
+
+ result->ret = -1;
+
+ ret = espp_service_client_msg_parse_params(data->params, data->event, &cb_id, &width, &height, &size);
+ if (ret != 0)
+ return;
+
+ LOG_INFO("cb params[cb_id:%d, width:%u, height:%u, size:%u]", cb_id, width, height, size);
+
+ buffer = g_malloc0(size);
+ if (__read_buffer(espp->event_fd, buffer, size) != 0)
+ return;
+
+ id = g_new(gint, 1);
+ *id = cb_id;
+ cb_data = g_hash_table_lookup(espp->snapshot_cbs, id);
+ if (!cb_data) {
+ LOG_ERROR("could not find cb_data of cb_id[%d]", cb_id);
+ return;
+ }
+
+ if (cb_data->callback) {
+ LOG_DEBUG(">>> cb_id[%d] callback[%p] user_data[%p]", cb_id, cb_data->callback, cb_data->user_data);
+ ((espp_snapshot_cb)(cb_data->callback))((espp_h)espp, (const char *)buffer, (int)width, (int)height, (unsigned int)size, cb_data->user_data);
+ LOG_DEBUG("<<< end of the callback");
+ }
+ result->ret = 0;
+}
+
static func_handler handlers[] = {
[ESPP_SERVICE_EVENT_MSG] = __handle_event_msg,
[ESPP_SERVICE_EVENT_CB_READY_TO_PREPARE] = __handle_event_cb_ready_to_prepare,
[ESPP_SERVICE_EVENT_CB_BUFFER_STATUS] = __handle_event_cb_buffer_status,
[ESPP_SERVICE_EVENT_CB_RESOURCE_CONFLICTED] = __handle_event_cb_resource_conflicted,
[ESPP_SERVICE_EVENT_CB_ERROR] = __handle_event_cb_error,
+ [ESPP_SERVICE_EVENT_CB_SNAPSHOT] = __handle_event_cb_snapshot,
};
static void __func_handler(espp_s *espp, espp_service_data_from_server_s *data, espp_service_data_from_client_s *result)
int fd;
int event_fd;
+ int snapshot_cb_id;
struct {
GThread *thread;
espp_callback_s buffer_status_cb;
espp_callback_s resource_conflicted_cb;
espp_callback_s error_cb;
+ GHashTable *snapshot_cbs;
} espp_s;
/* socket */
int espp_service_client_socket_request_set_buffer_size(espp_s *espp, espp_buffer_size_type_e size_type, uint64_t size);
int espp_service_client_socket_request_set_low_latency_mode(espp_s *espp, espp_low_latency_mode_e mode);
int espp_service_client_socket_request_set_decoded_video_frame_buffer_type(espp_s *espp, espp_decoded_video_frame_buffer_type_e type);
+int espp_service_client_socket_request_take_snapshot(espp_s *espp, int id);
/* event handler */
gpointer espp_service_client_event_handler_thread_func(gpointer user_data);
return 0;
}
+
+int espp_service_client_socket_request_take_snapshot(espp_s *espp, int id)
+{
+ espp_service_data_from_client_s data;
+ espp_service_data_from_server_s result;
+
+ ASSERT(espp);
+ RET_VAL_IF(espp->fd == -1, -1, "fd is -1");
+
+ FILL_SOCKET_MSG_REQUEST(data, ESPP_SERVICE_REQUEST_TAKE_SNAPSHOT);
+ FILL_SOCKET_MSG_PARAMS(data, ESPP_SERVICE_REQUEST_TAKE_SNAPSHOT, "id", id);
+ if (send_data(espp->fd, &data, &result) != 0)
+ return -1;
+
+ RET_VAL_IF_SERVER_RESULT_ERROR(result, -1);
+
+ LOG_DEBUG("espp[%p], fd[%d]", espp, espp->fd);
+
+ return 0;
+}
[ESPP_SERVICE_REQUEST_SET_BUFFER_SIZE] = { "SetBufferSize", "ik" },
[ESPP_SERVICE_REQUEST_SET_LOW_LATENCY_MODE] = { "SetLowLatencyMode", "i" },
[ESPP_SERVICE_REQUEST_SET_DECODED_VIDEO_FRAME_BUFFER_TYPE] = { "SetDecodedVideoFrameBufferType", "i" },
+ [ESPP_SERVICE_REQUEST_TAKE_SNAPSHOT] = { "TakeSnapshot", "i" },
[ESPP_SERVICE_REQUEST_SET_CALLBACK] = { "SetCallback", "i" },
};
[ESPP_SERVICE_EVENT_CB_BUFFER_STATUS] = { "BufferStatusCB", "ii" },
[ESPP_SERVICE_EVENT_CB_RESOURCE_CONFLICTED] = { "PrepareAsyncDoneCB", NULL },
[ESPP_SERVICE_EVENT_CB_ERROR] = { "ErrorCB", "i" },
+ [ESPP_SERVICE_EVENT_CB_SNAPSHOT] = { "SnapshotCB", "iuuu" },
};
const char *data_type_strs[] = {
ESPP_SERVICE_REQUEST_SET_BUFFER_SIZE,
ESPP_SERVICE_REQUEST_SET_LOW_LATENCY_MODE,
ESPP_SERVICE_REQUEST_SET_DECODED_VIDEO_FRAME_BUFFER_TYPE,
+ ESPP_SERVICE_REQUEST_TAKE_SNAPSHOT,
ESPP_SERVICE_REQUEST_SET_CALLBACK,
ESPP_SERVICE_REQUEST_NUM,
} espp_service_request_e;
ESPP_SERVICE_EVENT_CB_BUFFER_STATUS,
ESPP_SERVICE_EVENT_CB_RESOURCE_CONFLICTED,
ESPP_SERVICE_EVENT_CB_ERROR,
+ ESPP_SERVICE_EVENT_CB_SNAPSHOT,
ESPP_SERVICE_EVENT_CB_NUM,
} espp_service_event_e;
#include <esplusplayer_capi.h>
#include <esplusplayer_internal.h>
#include <inttypes.h>
+#include <tbm_surface.h>
+#include <mm_util_image.h>
+#include <mm_util_imgp.h>
+#include <mm_error.h>
+
+#define USECONDS_TO_MSECONDS(usec) ((usec) / G_GINT64_CONSTANT (1000))
+#define C(b,m) (((b) >> (m)) & 0xFF)
+#define FOURCC_STR(id) C(id,0), C(id,8), C(id,16), C(id,24)
typedef int (*set_cb_func) (esplusplayer_handle handle, void *callback, void *user_data);
typedef void (*func_handler) (handler_userdata_s *hdata, espp_service_data_from_client_s *data, espp_service_data_from_server_s *result);
+static gpointer __snapshot_work_thread(gpointer data);
+
typedef struct {
set_cb_func set_cb;
void *callback;
int fd;
int event_fd;
esplusplayer_handle espp;
+ struct {
+ GThread *thread;
+ GAsyncQueue *queue;
+ } snapshot;
} tb_data_s;
+typedef struct {
+ int32_t id;
+ uint32_t width;
+ uint32_t height;
+ uint32_t size;
+ unsigned char *data;
+} snapshot_data_s;
+
static void __handle_init_event(handler_userdata_s *hdata, espp_service_data_from_client_s *data, espp_service_data_from_server_s *result)
{
int ret;
result->ret = 0;
}
+typedef struct {
+ int cb_id;
+ bool exit;
+} queue_data_s;
+
+static void __release_qd(gpointer data)
+{
+ queue_data_s *qd = (queue_data_s *)data;
+
+ LOG_DEBUG("release qd[%p, exit:%d] done", qd, qd->exit);
+ g_free(qd);
+}
+
+static int __init_snapshot_thread(tb_data_s *tbs)
+{
+ ASSERT(tbs);
+ ASSERT(!tbs->snapshot.queue);
+ ASSERT(!tbs->snapshot.thread);
+
+ tbs->snapshot.queue = g_async_queue_new_full(__release_qd);
+
+ if (!(tbs->snapshot.thread = g_thread_try_new("__snapshot_work_thread", __snapshot_work_thread, (gpointer)tbs, NULL))) {
+ LOG_ERROR("failed to g_thread_try_new()");
+ g_async_queue_unref(tbs->snapshot.queue);
+ tbs->snapshot.queue = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __deinit_snapshot_thread(tb_data_s *tbs)
+{
+ queue_data_s *qd;
+
+ ASSERT(tbs);
+ ASSERT(tbs->snapshot.queue);
+ ASSERT(tbs->snapshot.thread);
+
+ qd = g_new0(queue_data_s, 1);
+ qd->exit = true;
+ g_async_queue_push_front(tbs->snapshot.queue, qd);
+
+ LOG_DEBUG("waiting for thread join...");
+ g_thread_join(tbs->snapshot.thread);
+ LOG_DEBUG("snapshot thread exits");
+
+ g_async_queue_unref(tbs->snapshot.queue);
+
+ tbs->snapshot.queue = NULL;
+ tbs->snapshot.thread = NULL;
+}
+
static void __handle_create(handler_userdata_s *hdata, espp_service_data_from_client_s *data, espp_service_data_from_server_s *result)
{
int ret;
return;
}
+ if (__init_snapshot_thread(tbs) != 0) {
+ g_hash_table_remove(hdata->svc->fd_table, hdata->key);
+ esplusplayer_destroy(espp);
+ return;
+ }
+
result->ret = 0;
}
static void __handle_destroy(handler_userdata_s *hdata, espp_service_data_from_client_s *data, espp_service_data_from_server_s *result)
{
+ tb_data_s *tbs;
result->ret = -1;
- RET_IF(!g_hash_table_lookup(hdata->svc->fd_table, hdata->key), "failed to g_hash_table_lookup(), key[%s]", hdata->key);
+ RET_IF(!(tbs = g_hash_table_lookup(hdata->svc->fd_table, hdata->key)), "failed to g_hash_table_lookup(), key[%s]", hdata->key);
RET_IF(esplusplayer_destroy((esplusplayer_handle)hdata->espp) != ESPLUSPLAYER_ERROR_TYPE_NONE, "failed to esplusplayer_destroy()");
ASSERT(g_hash_table_steal(hdata->svc->fd_table, hdata->key));
+ __deinit_snapshot_thread(tbs);
+
result->ret = 0;
}
result->ret = 0;
}
+static int __convert_colorspace(unsigned char *src_data, size_t src_size, int src_w, int src_h, mm_util_color_format_e src_fmt, mm_util_color_format_e dst_fmt, snapshot_data_s *result)
+{
+ int ret;
+ mm_util_image_h src_image;
+ mm_util_image_h dst_image;
+ size_t size;
+
+ RET_VAL_IF(src_data == NULL, -1, "src_data is NULL");
+ RET_VAL_IF(result == NULL, -1, "result is NULL");
+
+ ret = mm_image_create_image(src_w, src_h, src_fmt, src_data, src_size, &src_image);
+ RET_VAL_IF(ret != MM_ERROR_NONE, -1, "failed to mm_image_create_image()");
+
+ ret = mm_util_convert_colorspace(src_image, dst_fmt, &dst_image);
+ mm_image_destroy_image(src_image);
+ RET_VAL_IF(ret != MM_ERROR_NONE, -1, "failed to mm_util_convert_colorspace()");
+
+ mm_image_debug_image(dst_image, NULL);
+
+ ret = mm_image_get_image(dst_image, &result->width, &result->height, NULL, &result->data, &size);
+ mm_image_destroy_image(dst_image);
+ RET_VAL_IF(ret != MM_ERROR_NONE, -1, "failed to mm_image_get_image()");
+
+ result->size = (uint32_t)size;
+
+ LOG_INFO("src[data:%p, size:%zu, %dx%d, fmt:%d] -> dst[data:%p, size:%u, %ux%u, fmt:%d]",
+ src_data, src_size, src_w, src_h, src_fmt, result->data, result->size, result->width, result->height, dst_fmt);
+
+ return 0;
+}
+
+static int __get_mm_util_color_format(tbm_format in_format, mm_util_color_format_e *out_format)
+{
+ switch(in_format) {
+ case TBM_FORMAT_NV12:
+ *out_format = MM_UTIL_COLOR_NV12;
+ break;
+ case TBM_FORMAT_YUV420:
+ *out_format = MM_UTIL_COLOR_YUV420;
+ break;
+ case TBM_FORMAT_BGRA8888:
+ *out_format = MM_UTIL_COLOR_BGRA;
+ break;
+ case TBM_FORMAT_BGRX8888:
+ *out_format = MM_UTIL_COLOR_BGRX;
+ break;
+ case TBM_FORMAT_ARGB8888:
+ *out_format = MM_UTIL_COLOR_ARGB;
+ break;
+ default:
+ LOG_ERROR("invalid format");
+ return -1;
+ }
+ return 0;
+}
+
+static int __convert_colorspace_to_rgb24(tbm_surface_h tbm_surf, snapshot_data_s *snapshot)
+{
+ guint src_size;
+ unsigned char *dst_buffer = NULL;
+ unsigned char *tmp_dst = NULL;
+ unsigned char *tmp_src = NULL;
+ unsigned int i;
+ tbm_surface_info_s info;
+ mm_util_color_format_e src_format;
+
+ RET_VAL_IF(!tbm_surf, -1, "tbm_surf is NULL");
+ RET_VAL_IF(!snapshot, -1, "snapshot is NULL");
+
+ if (tbm_surface_get_info(tbm_surf, &info)) {
+ LOG_ERROR("failed to tbm_surface_get_info()");
+ return -1;
+ }
+
+ LOG_DEBUG("%c%c%c%c, %dx%d, size:%d, num of planes:%d",
+ FOURCC_STR(info.format), info.width, info.height, info.size, info.num_planes);
+
+ if (__get_mm_util_color_format(info.format, &src_format) < 0) {
+ LOG_ERROR("failed to __get_mm_util_color_format()");
+ return -1;
+ }
+
+ switch (src_format) {
+ case MM_UTIL_COLOR_NV12:
+ src_size = (info.width * info.height) + (info.width * (info.height >> 1));
+
+ dst_buffer = (unsigned char *)g_malloc(src_size);
+ tmp_dst = dst_buffer;
+
+ /* Y plane */
+ tmp_src = (unsigned char *)info.planes[0].ptr;
+ for (i = 0; i < info.height; i++) {
+ memcpy(tmp_dst, tmp_src, info.width);
+ tmp_dst += info.width;
+ tmp_src += info.planes[0].stride;
+ }
+ /* UV plane*/
+ tmp_src = (unsigned char *)info.planes[1].ptr;
+ for (i = 0; i < (info.height >> 1); i++) {
+ memcpy(tmp_dst, tmp_src, info.width);
+ tmp_dst += info.width;
+ tmp_src += info.planes[1].stride;
+ }
+ break;
+ case MM_UTIL_COLOR_YUV420:
+ src_size = (info.width * info.height) * 2;
+
+ dst_buffer = (unsigned char *)g_malloc(src_size);
+ tmp_dst = dst_buffer;
+
+ /* Y plane */
+ tmp_src = (unsigned char *)info.planes[0].ptr;
+ for (i = 0; i < info.height; i++) {
+ memcpy(tmp_dst, tmp_src, info.width);
+ tmp_dst += info.width;
+ tmp_src += info.planes[0].stride;
+ }
+ /* U plane */
+ tmp_src = (unsigned char *)info.planes[1].ptr;
+ for (i = 0; i < (info.height >> 1); i++) {
+ memcpy(tmp_dst, tmp_src, (info.width >> 1));
+ tmp_dst += (info.width >> 1);
+ tmp_src += info.planes[1].stride;
+ }
+ /* V plane */
+ tmp_src = (unsigned char *)info.planes[2].ptr;
+ for (i = 0; i < (info.height >> 1); i++) {
+ memcpy(tmp_dst, tmp_src, (info.width >> 1));
+ tmp_dst += (info.width >> 1);
+ tmp_src += info.planes[2].stride;
+ }
+ break;
+ case MM_UTIL_COLOR_BGRX:
+ case MM_UTIL_COLOR_BGRA:
+ case MM_UTIL_COLOR_ARGB:
+ src_size = (info.width * 4) * info.height;
+
+ dst_buffer = (unsigned char *)g_malloc(src_size);
+ memcpy(dst_buffer, info.planes[0].ptr, src_size);
+ break;
+ default:
+ LOG_ERROR("not supported format");
+ return -1;
+ }
+
+ return __convert_colorspace(dst_buffer, src_size, info.width, info.height,
+ src_format, MM_UTIL_COLOR_RGB24, snapshot);
+}
+
+static int __get_rgb24_frame(esplusplayer_handle espp, snapshot_data_s *snapshot)
+{
+ int ret;
+ esplusplayer_decoded_video_packet pkt;
+ esplusplayer_get_decoded_video_frame_status_type status;
+ gint64 start_time = g_get_monotonic_time();
+
+ ASSERT(espp);
+ ASSERT(snapshot);
+
+ ret = esplusplayer_get_decoded_video_packet(espp, &pkt, &status);
+ RET_VAL_IF(ret != ESPLUSPLAYER_ERROR_TYPE_NONE, -1, "failed to esplusplayer_get_decoded_video_packet(), ESPP[%p]", espp);
+ RET_VAL_IF(status != ESPLUSPLAYER_GET_DECVIDEOFRAME_STATUS_SUCCESS, -1, "failed to esplusplayer_get_decoded_video_packet(), ESPP[%p], status[%d]", espp, status);
+ LOG_DEBUG("elapsed: %"G_GINT64_FORMAT" ms (esplusplayer_get_decoded_video_packet())",
+ USECONDS_TO_MSECONDS(g_get_monotonic_time() - start_time));
+
+ if (__convert_colorspace_to_rgb24((tbm_surface_h)pkt.surface_data, snapshot) < 0)
+ goto exit;
+ LOG_DEBUG("elapsed: %"G_GINT64_FORMAT" ms (__convert_colorspace_to_rgb24())",
+ USECONDS_TO_MSECONDS(g_get_monotonic_time() - start_time));
+
+ LOG_INFO("ESPP[%p], snapshot[%ux%u, size:%u, data:%p]",
+ espp, snapshot->width, snapshot->height, snapshot->size, snapshot->data);
+exit:
+ if (esplusplayer_decoded_buffer_destroy(espp, &pkt) != ESPLUSPLAYER_ERROR_TYPE_NONE)
+ LOG_WARNING("failed to esplusplayer_decoded_buffer_destroy()");
+
+ return 0;
+}
+
+static void __snapshot_cb(tb_data_s *tbs, snapshot_data_s *snapshot)
+{
+ espp_service_data_from_server_s data = {0, };
+
+ ASSERT(tbs);
+ ASSERT(snapshot);
+
+ LOG_DEBUG("event_fd[%d], ESPP[%p]", tbs->event_fd, tbs->espp);
+
+ FILL_SOCKET_MSG_EVENT(data, ESPP_SERVICE_EVENT_CB_SNAPSHOT);
+ FILL_SOCKET_MSG_PARAMS(data, ESPP_SERVICE_EVENT_CB_SNAPSHOT,
+ "id", snapshot->id, "width", snapshot->width, "height", snapshot->height, "size", snapshot->size);
+
+ espp_service_send_data(tbs->event_fd, &data);
+ espp_service_send_buffer(tbs->event_fd, snapshot->data, snapshot->size);
+}
+
+static gpointer __snapshot_work_thread(gpointer data)
+{
+ tb_data_s *tbs = (tb_data_s *)data;
+ queue_data_s *qd;
+
+ while (1) {
+ snapshot_data_s snapshot = {-1, 0, 0, 0, NULL};
+
+ LOG_DEBUG("wait for data...");
+ if (!(qd = g_async_queue_pop(tbs->snapshot.queue))) {
+ LOG_ERROR("qd is NULL");
+ break;
+ }
+ LOG_INFO("process qd[%p, cb_id:%d, exit:%d]", qd, qd->cb_id, qd->exit);
+ if (qd->exit) {
+ __release_qd(qd);
+ break;
+ }
+
+ snapshot.id = qd->cb_id;
+ if (__get_rgb24_frame(tbs->espp, &snapshot) == 0) {
+ __snapshot_cb(tbs, &snapshot);
+ g_free(snapshot.data);
+ }
+ __release_qd(qd);
+ }
+
+ LOG_DEBUG("exit");
+ return NULL;
+}
+
+static void __handle_take_snapshot(handler_userdata_s *hdata, espp_service_data_from_client_s *data, espp_service_data_from_server_s *result)
+{
+ int ret;
+ int id;
+ tb_data_s *tbs;
+ queue_data_s *qd;
+
+ result->ret = -1;
+
+ RET_IF(!(tbs = g_hash_table_lookup(hdata->svc->fd_table, hdata->key)), "failed to g_hash_table_lookup(), key[%s]", hdata->key);
+
+ ASSERT(tbs->snapshot.queue);
+
+ ret = espp_service_msg_parse_params(data->params, data->request, &id);
+ if (ret != 0)
+ return;
+
+ qd = g_new0(queue_data_s, 1);
+ qd->cb_id = id;
+ g_async_queue_push(tbs->snapshot.queue, qd);
+
+ LOG_INFO("qd[%p, cb_id:%d]", qd, id);
+
+ result->ret = 0;
+}
+
static void __ready_to_prepare_cb(const int type, void *user_data)
{
handler_userdata_s *hdata = (handler_userdata_s *)user_data;
[ESPP_SERVICE_REQUEST_SET_BUFFER_SIZE] = __handle_set_buffer_size,
[ESPP_SERVICE_REQUEST_SET_LOW_LATENCY_MODE] = __handle_set_low_latency_mode,
[ESPP_SERVICE_REQUEST_SET_DECODED_VIDEO_FRAME_BUFFER_TYPE] = __handle_set_decoded_video_frame_buffer_type,
+ [ESPP_SERVICE_REQUEST_TAKE_SNAPSHOT] = __handle_take_snapshot,
[ESPP_SERVICE_REQUEST_SET_CALLBACK] = __handle_set_callback,
};
void espp_service_deinit_socket(espp_service_s *svc);
int espp_service_send_data(int fd, espp_service_data_from_server_s *data);
int espp_service_read_buffer(int fd, char *buffer, uint32_t size);
+int espp_service_send_buffer(int fd, const unsigned char *buffer, uint32_t size);
/* handler */
int espp_service_func_handler(handler_userdata_s *hdata, espp_service_data_from_client_s *data, espp_service_data_from_server_s *result);
return 0;
}
+int espp_service_send_buffer(int fd, const unsigned char *buffer, uint32_t size)
+{
+ char str_error[MAX_ERROR_LEN] = {'\0',};
+
+ ASSERT(fd >= 0);
+ ASSERT(buffer);
+ ASSERT(size > 0);
+
+ if (write(fd, buffer, size) < 0) {
+ strerror_r(errno, str_error, sizeof(str_error));
+ LOG_ERROR("failed to write(), fd[%d], err: %s", fd, str_error);
+ return -1;
+ }
+
+ LOG_DEBUG("fd[%d] buffer[%p] size[%u]", fd, buffer, size);
+
+ return 0;
+}
+
int espp_service_read_buffer(int fd, char *buffer, uint32_t size)
{
int ret;
thread_dep = dependency('threads', required: true)
espp_dep = dependency('esplusplayer', required: true)
-daemon_deps += [thread_dep, espp_dep]
+tbm_dep = dependency('libtbm', required: true)
+mm_common_dep = dependency('mm-common', required: true)
+mm_util_dep = dependency('mmutil-common', required: true)
+mmutil_imgp_dep = dependency('mmutil-imgp', required: true)
+
+daemon_deps += [thread_dep, espp_dep, tbm_dep, mm_common_dep, mm_util_dep, mmutil_imgp_dep]
executable('espp-service',
espp_service_sources,
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<manifest xmlns="http://tizen.org/ns/packages" api-version="7.0" package="com.samsung.tizen.espp-service" version="0.3.11">
+<manifest xmlns="http://tizen.org/ns/packages" api-version="7.0" package="com.samsung.tizen.espp-service" version="0.3.12">
<profile name="mobile"/>
<description>espp-service</description>
<service-application appid="com.samsung.tizen.espp-service" auto-restart="false" exec="espp-service" multiple="false" nodisplay="false" on-boot="false" taskmanage="false" type="capp">