From de8a18c10c58e64776dd37364d0737dc5a9aae1e Mon Sep 17 00:00:00 2001 From: Jeongmo Yang Date: Wed, 13 Mar 2024 15:15:50 +0900 Subject: [PATCH] Add new internal API to enable extra video convert element [Version] 0.6.44 [Issue Type] New feature Change-Id: If3f76f120d6c709892bf217fddfff7d59da7080f Signed-off-by: Jeongmo Yang --- CMakeLists.txt | 4 +- include/media_codec_internal.h | 2 + include/media_codec_port.h | 13 +++ include/media_codec_port_gst.h | 4 + packaging/capi-media-codec.spec | 2 +- src/media_codec_internal.c | 15 +++ src/media_codec_port.c | 46 +++++++++- src/media_codec_port_gst.c | 199 ++++++++++++++++++++++++++++++++++++---- 8 files changed, 258 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3734ece..c42c0b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,8 +53,8 @@ INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR}) INSTALL( DIRECTORY ${INC_DIR}/ DESTINATION include/media FILES_MATCHING - PATTERN "media_codec_*.h" EXCLUDE - PATTERN "${INC_DIR}/*.h" + PATTERN "${INC_DIR}/media_codec.h" + PATTERN "${INC_DIR}/media_codec_internal.h" ) SET(PC_NAME ${fw_name}) diff --git a/include/media_codec_internal.h b/include/media_codec_internal.h index 87eac43..aa96597 100644 --- a/include/media_codec_internal.h +++ b/include/media_codec_internal.h @@ -45,6 +45,8 @@ extern "C" { */ int mediacodec_foreach_supported_codec_static(mediacodec_supported_codec_cb callback, void *user_data); +int mediacodec_enable_extra_video_converter(mediacodec_h mediacodec, gboolean enable, const char *converter_name, int crop_x, int crop_y, int crop_w, int crop_h); + /** * @} */ diff --git a/include/media_codec_port.h b/include/media_codec_port.h index d13531c..fede8d2 100644 --- a/include/media_codec_port.h +++ b/include/media_codec_port.h @@ -179,6 +179,15 @@ typedef struct mc_video_port_definition_t { gint framerate; } mc_video_port_definition_t; +typedef struct mc_extra_converter_t { + gboolean enable; + gchar *name; + gint crop_x; + gint crop_y; + gint crop_w; + gint crop_h; +} mc_extra_converter_t; + /* Codec Private data */ struct _mc_handle_t { int state; /**< mc current state */ @@ -209,6 +218,8 @@ struct _mc_handle_t { int num_supported_encoder; mc_ini_t *ini; + + mc_extra_converter_t extra_converter; }; /*=========================================================================================== @@ -260,6 +271,8 @@ int mc_unset_eos_cb(MMHandleType mediacodec); int mc_set_buffer_status_cb(MMHandleType mediacodec, mediacodec_buffer_status_cb callback, void* user_data); int mc_unset_buffer_status_cb(MMHandleType mediacodec); +int mc_enable_extra_video_converter(MMHandleType mediacodec, gboolean enable, const char *converter_name, int crop_x, int crop_y, int crop_w, int crop_h); + int _mediacodec_foreach_supported_codec(mediacodec_supported_codec_cb callback, void* user_data); void _mc_create_codec_map_from_ini(mc_handle_t *mc_handle, mc_codec_spec_t *spec_emul); diff --git a/include/media_codec_port_gst.h b/include/media_codec_port_gst.h index 3f63bc2..c095ada 100644 --- a/include/media_codec_port_gst.h +++ b/include/media_codec_port_gst.h @@ -148,6 +148,8 @@ struct _mc_gst_core_t { void* user_data[_MEDIACODEC_EVENT_TYPE_NUM]; GstVideoInfo *video_info; + + mc_extra_converter_t *extra_converter; }; struct _GstMCBuffer { @@ -170,6 +172,8 @@ mc_ret_e mc_gst_flush_buffers(mc_handle_t *mc_handle); mc_ret_e mc_gst_get_packet_pool(mc_handle_t *mc_handle, media_packet_pool_h *packet_pool); +mc_ret_e mc_gst_set_property_array_int(GstElement *element, const gchar *property_name, gint *array, guint array_length); + #ifdef __cplusplus } #endif diff --git a/packaging/capi-media-codec.spec b/packaging/capi-media-codec.spec index c41bb7b..bed5b52 100644 --- a/packaging/capi-media-codec.spec +++ b/packaging/capi-media-codec.spec @@ -4,7 +4,7 @@ Name: capi-media-codec Summary: A Media Codec library in Tizen Native API -Version: 0.6.43 +Version: 0.6.44 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/media_codec_internal.c b/src/media_codec_internal.c index bdf24a5..66af04d 100644 --- a/src/media_codec_internal.c +++ b/src/media_codec_internal.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -108,3 +109,17 @@ int mediacodec_foreach_supported_codec_static(mediacodec_supported_codec_cb call ERROR: return MEDIACODEC_ERROR_INVALID_PARAMETER; } + +int mediacodec_enable_extra_video_converter(mediacodec_h mediacodec, gboolean enable, const char *converter_name, int crop_x, int crop_y, int crop_w, int crop_h) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s *handle = (mediacodec_s *)mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE); + + int ret = mc_enable_extra_video_converter(handle->mc_handle, enable, converter_name, crop_x, crop_y, crop_w, crop_h); + + if (ret != MEDIACODEC_ERROR_NONE) + return __convert_error_code_internal(ret, (char *)__FUNCTION__); + else + return MEDIACODEC_ERROR_NONE; +} diff --git a/src/media_codec_port.c b/src/media_codec_port.c index 34c0d7f..b736853 100644 --- a/src/media_codec_port.c +++ b/src/media_codec_port.c @@ -107,12 +107,13 @@ int mc_destroy(MMHandleType mediacodec) mc_handle->is_prepared = false; - /* free mediacodec structure */ - if (mc_handle) { - g_free((void *)mc_handle); - mc_handle = NULL; + if (mc_handle->extra_converter.name) { + g_free(mc_handle->extra_converter.name); + mc_handle->extra_converter.name = NULL; } + g_free((void *)mc_handle); + return ret; } @@ -793,6 +794,43 @@ int mc_unset_buffer_status_cb(MMHandleType mediacodec) return MC_ERROR_NONE; } +int mc_enable_extra_video_converter(MMHandleType mediacodec, gboolean enable, const char *converter_name, int crop_x, int crop_y, int crop_w, int crop_h) +{ + mc_handle_t *mc_handle = (mc_handle_t *) mediacodec; + + if (!mc_handle) { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + if (enable && !converter_name) { + LOGE("It's enabled, but converter name is NULL"); + return MC_INVALID_ARG; + } + + LOGI("enable: %d", enable); + mc_handle->extra_converter.enable = enable; + + if (enable) { + if (mc_handle->extra_converter.name) { + LOGI("free converter name old[%s]", mc_handle->extra_converter.name); + g_free(mc_handle->extra_converter.name); + mc_handle->extra_converter.name = NULL; + } + + LOGI("element name: %s", converter_name); + mc_handle->extra_converter.name = g_strdup(converter_name); + + LOGI("crop[%d,%d,%dx%d]", crop_x, crop_y, crop_w, crop_h); + mc_handle->extra_converter.crop_x = crop_x; + mc_handle->extra_converter.crop_y = crop_y; + mc_handle->extra_converter.crop_w = crop_w; + mc_handle->extra_converter.crop_h = crop_h; + } + + return MC_ERROR_NONE; +} + int _mediacodec_foreach_supported_codec(mediacodec_supported_codec_cb callback, void *user_data) { int i; diff --git a/src/media_codec_port_gst.c b/src/media_codec_port_gst.c index 74fd638..e2954ec 100644 --- a/src/media_codec_port_gst.c +++ b/src/media_codec_port_gst.c @@ -185,6 +185,7 @@ static int(*adec_wma_vtable[])() = {&__mc_fill_input_buffer_with_packet, static int(*aenc_opus_vtable[])() = {&__mc_fill_input_buffer_with_packet, /* Opus Encoder Vtable */ &__mc_fill_aenc_packet_with_output_buffer}; +#define MEDIACODEC_CROP_ARRAY_LENGTH 4 #define MEDIACODEC_ELEMENT_SET_STATE(x_element, x_state) \ do { \ LOGD("setting state [%s:%d] to [%s]\n", #x_state, x_state, GST_ELEMENT_NAME(x_element)); \ @@ -1147,6 +1148,8 @@ static gboolean _mc_gst_video_info_check_and_new(mc_gst_core_t *core, GstMCBuffe { int i = 0; gchar *caps_str = NULL; + tbm_surface_h surface = NULL; + tbm_surface_info_s sinfo = {0, }; if (!core || !mcbuffer) { LOGE("NULL core[%p] or mcbuffer[%p]", core, mcbuffer); @@ -1166,9 +1169,19 @@ static gboolean _mc_gst_video_info_check_and_new(mc_gst_core_t *core, GstMCBuffe return FALSE; } - for (i = 0 ; i < GST_VIDEO_INFO_N_PLANES(core->video_info) ; i++) { - GST_VIDEO_INFO_PLANE_OFFSET(core->video_info, i) = 0; - media_packet_get_video_stride_width(mcbuffer->packet, i, &GST_VIDEO_INFO_PLANE_STRIDE(core->video_info, i)); + if (media_packet_get_tbm_surface(mcbuffer->packet, &surface) != MEDIA_PACKET_ERROR_NONE) { + LOGE("get surface failed"); + return FALSE; + } + + if (tbm_surface_get_info(surface, &sinfo) != TBM_SURFACE_ERROR_NONE) { + LOGE("get surface info failed"); + return FALSE; + } + + for (i = 0 ; i < sinfo.num_planes ; i++) { + GST_VIDEO_INFO_PLANE_OFFSET(core->video_info, i) = sinfo.planes[i].offset; + GST_VIDEO_INFO_PLANE_STRIDE(core->video_info, i) = sinfo.planes[i].stride; LOGI("[%d] offset[%zu], stride[%d]", i, GST_VIDEO_INFO_PLANE_OFFSET(core->video_info, i), @@ -1877,6 +1890,7 @@ mc_ret_e mc_gst_prepare(mc_handle_t *mc_handle) new_core->codec_id = id; new_core->codec_type = &codec_map[i].type; new_core->mc_caps_new = video ? &_mc_gst_vid_caps_new : &_mc_gst_aud_caps_new; + new_core->extra_converter = &mc_handle->extra_converter; new_core->bufmgr = tbm_bufmgr_init(new_core->drm_fd); if (new_core->bufmgr == NULL) { @@ -2202,6 +2216,97 @@ ERROR: return FALSE; } +static GstElement *__mc_gst_extra_converter_new(mc_extra_converter_t *extra_converter) +{ + GstElement *element = NULL; + gint array[MEDIACODEC_CROP_ARRAY_LENGTH] = {0, }; + + if (!extra_converter) { + LOGE("NULL extra converter"); + return NULL; + } + + LOGI("extra converter[%s]", extra_converter->name); + + element = gst_element_factory_make(extra_converter->name, NULL); + if (!element) { + LOGE("create element[%s] failed", extra_converter->name); + return NULL; + } + + array[0] = extra_converter->crop_x; + array[1] = extra_converter->crop_y; + array[2] = extra_converter->crop_w; + array[3] = extra_converter->crop_h; + + if (mc_gst_set_property_array_int(element, + "crop", array, MEDIACODEC_CROP_ARRAY_LENGTH) != MC_ERROR_NONE) { + gst_object_unref(element); + return NULL; + } + + LOGI("set crop to extra converter[%d,%d,%dx%d]", + array[0], array[1], array[2], array[3] ); + + return element; +} + + +#ifdef TIZEN_FEATURE_ENABLE_DUMP_SOURCE +static GstPadProbeReturn __dump_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) +{ + static int count = 0; + int i = 0; + const gchar *dump_path = (const gchar *)u_data; + GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info); + GstMemory *memory = NULL; + FILE *fp = NULL; + tbm_surface_h surface = NULL; + tbm_surface_info_s sinfo = {0, }; + + if (!dump_path) { + LOGW("NULL path"); + return GST_PAD_PROBE_OK; + } + + if (count++ > 10) { + LOGW("[%s] SKIP DUMP", dump_path); + return GST_PAD_PROBE_OK; + } + + memory = gst_buffer_peek_memory(buffer, 0); + + if (!gst_is_tizen_memory(memory)) { + LOGW("Not tizen memory"); + return GST_PAD_PROBE_OK; + } + + surface = gst_tizen_memory_get_surface(memory); + if (!surface) { + LOGW("No surface"); + return GST_PAD_PROBE_OK; + } + + fp = fopen(dump_path, "a"); + if (!fp) { + LOGW("file open failed[%s]", dump_path); + return GST_PAD_PROBE_OK; + } + + tbm_surface_get_info(surface, &sinfo); + + for (i = 0 ; i < sinfo.num_planes ; i++) { + LOGI("[dump:%s] write plane[%d] size[%u]", dump_path, i, sinfo.planes[i].size); + fwrite(sinfo.planes[i].ptr, 1, sinfo.planes[i].size, fp); + } + + fclose(fp); + + return GST_PAD_PROBE_OK; +} +#endif /* TIZEN_FEATURE_ENABLE_DUMP_SOURCE */ + + mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t *core, const gchar *factory_name) { int i = 0; @@ -2243,31 +2348,22 @@ mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t *core, const gchar *factory_name) if (!core->video && core->encoder) { core->audioconvert = gst_element_factory_make("audioconvert", NULL); - if (!core->audioconvert) { LOGE("audioconvert can't create"); goto ERROR; } core->audioresample = gst_element_factory_make("audioresample", NULL); - if (!core->audioresample) { LOGE("audioresample can't create"); goto ERROR; } } - if (core->video && core->encoder) { - core->videoconvert = gst_element_factory_make("videoconvert", NULL); - + if (core->video && core->encoder && core->extra_converter->enable) { + core->videoconvert = __mc_gst_extra_converter_new(core->extra_converter); if (!core->videoconvert) { - LOGE("videoconvert can't create"); - goto ERROR; - } - - core->videoscale = gst_element_factory_make("videoscale", NULL); - if (!core->videoscale) { - LOGE("videoscale can't create"); + LOGE("create[%s] failed", core->extra_converter->name); goto ERROR; } } @@ -2296,12 +2392,22 @@ mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t *core, const gchar *factory_name) goto ERROR; } } else if (core->video && core->encoder) { - gst_bin_add_many(GST_BIN(core->pipeline), core->appsrc, core->capsfilter, core->codec, core->fakesink, NULL); + if (core->extra_converter->enable) { + gst_bin_add_many(GST_BIN(core->pipeline), core->appsrc, core->capsfilter, core->videoconvert, core->codec, core->fakesink, NULL); - /* link elements */ - if (!(gst_element_link_many(core->appsrc, core->codec, core->fakesink, NULL))) { - LOGE("gst_element_link_many is failed"); - goto ERROR; + /* link elements */ + if (!(gst_element_link_many(core->appsrc, core->videoconvert, core->codec, core->fakesink, NULL))) { + LOGE("gst_element_link_many is failed"); + goto ERROR; + } + } else { + gst_bin_add_many(GST_BIN(core->pipeline), core->appsrc, core->capsfilter, core->codec, core->fakesink, NULL); + + /* link elements */ + if (!(gst_element_link_many(core->appsrc, core->codec, core->fakesink, NULL))) { + LOGE("gst_element_link_many is failed"); + goto ERROR; + } } } else { gst_bin_add_many(GST_BIN(core->pipeline), core->appsrc, core->capsfilter, core->codec, core->fakesink, NULL); @@ -2313,6 +2419,26 @@ mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t *core, const gchar *factory_name) } } +#ifdef TIZEN_FEATURE_ENABLE_DUMP_SOURCE + { + GstPad *pad = NULL; + + pad = gst_element_get_static_pad(core->videoconvert, "sink"); + if (pad) { + gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, __dump_probe, "/tmp/input.dump", NULL); + gst_object_unref(pad); + pad = NULL; + } + + pad = gst_element_get_static_pad(core->videoconvert, "src"); + if (pad) { + gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, __dump_probe, "/tmp/output.dump", NULL); + gst_object_unref(pad); + pad = NULL; + } + } +#endif /* TIZEN_FEATURE_ENABLE_DUMP_SOURCE */ + /* connect signals, bus watcher */ bus = gst_pipeline_get_bus(GST_PIPELINE(core->pipeline)); core->bus_watch_id = gst_bus_add_watch(bus, __mc_gst_bus_callback, core); @@ -3653,3 +3779,36 @@ mc_ret_e mc_gst_get_packet_pool(mc_handle_t *mc_handle, media_packet_pool_h *pac *packet_pool = pool; return MC_ERROR_NONE; } + +mc_ret_e mc_gst_set_property_array_int(GstElement *element, const gchar *property_name, gint *array, guint array_length) +{ + guint i = 0; + GValue value = G_VALUE_INIT; + GValue tmp = G_VALUE_INIT; + + if (!element || !property_name || !array) { + LOGE("NULL param[%p,%p,%p]", element, property_name, array); + return MC_PARAM_ERROR; + } + + g_value_init(&value, GST_TYPE_ARRAY); + g_value_init(&tmp, G_TYPE_INT); + + LOGI("set element[%s], property[%s], array_length[%d]", + GST_ELEMENT_NAME(element), property_name, array_length); + + gst_value_array_init(&value, array_length); + + for (i = 0 ; i < array_length ; i++) { + LOGI(" array[%u] %d", i, array[i]); + g_value_set_int(&tmp, array[i]); + gst_value_array_append_value(&value, &tmp); + } + + g_object_set_property(G_OBJECT(element), property_name, &value); + + g_value_unset(&tmp); + g_value_unset(&value); + + return MC_ERROR_NONE; +} -- 2.7.4