From b9c04567203ab4ac2bb98db26ac2a697da3cb2e0 Mon Sep 17 00:00:00 2001 From: "Hyuntae, Kim" Date: Thu, 9 Jun 2016 14:45:00 +0900 Subject: [PATCH 1/1] [libmm-camcorder] Resource manager symbolic code added Change-Id: I4f8e2343dbd8a9f059c4207ff83e7c005bcc90bd --- configure.ac | 19 ++++ packaging/libmm-camcorder.spec | 7 +- src/Makefile.am | 5 ++ src/include/mm_camcorder_internal.h | 12 +++ src/mm_camcorder_gstcommon.c | 48 +++++++++- src/mm_camcorder_internal.c | 173 ++++++++++++++++++++++++++++++++++++ test/Makefile.am | 4 + 7 files changed, 266 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 4810d16..3fb1db6 100644 --- a/configure.ac +++ b/configure.ac @@ -116,6 +116,25 @@ PKG_CHECK_MODULES(TBM, libtbm) AC_SUBST(TBM_CFLAGS) AC_SUBST(TBM_LIBS) +AC_ARG_ENABLE(rm, AC_HELP_STRING([--enable-rm], [enable rm]), +[ + case "${enableval}" in + yes) RM_SUPPORT=yes ;; + no) RM_SUPPORT=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-rm) ;; + esac +],[RM_SUPPORT=no]) +if test "x$RM_SUPPORT" = "xyes"; then +PKG_CHECK_MODULES(RM, tv-resource-manager) +AC_SUBST(RM_CFLAGS) +AC_SUBST(RM_LIBS) + +PKG_CHECK_MODULES(AUL, aul) +AC_SUBST(AUL_CFLAGS) +AC_SUBST(AUL_LIBS) +fi +AM_CONDITIONAL([RM_SUPPORT], [test "x$RM_SUPPORT" = "xyes"]) + PKG_CHECK_MODULES(STORAGE, storage) AC_SUBST(STORAGE_CFLAGS) AC_SUBST(STORAGE_LIBS) diff --git a/packaging/libmm-camcorder.spec b/packaging/libmm-camcorder.spec index cfeb567..47a19d9 100644 --- a/packaging/libmm-camcorder.spec +++ b/packaging/libmm-camcorder.spec @@ -2,7 +2,7 @@ Name: libmm-camcorder Summary: Camera and recorder library -Version: 0.10.54 +Version: 0.10.55 Release: 0 Group: Multimedia/Libraries License: Apache-2.0 @@ -30,6 +30,9 @@ BuildRequires: pkgconfig(storage) %if "%{TIZEN_PRODUCT_TV}" != "1" BuildRequires: pkgconfig(murphy-resource) BuildRequires: pkgconfig(murphy-glib) +%else +BuildRequires: pkgconfig(tv-resource-manager) +BuildRequires: pkgconfig(aul) %endif BuildRequires: pkgconfig(ttrace) BuildRequires: pkgconfig(libtzplatform-config) @@ -65,6 +68,8 @@ export CFLAGS+=" -D_LARGEFILE64_SOURCE -DSYSCONFDIR=\\\"%{_sysconfdir}\\\" -DTZ_ %endif %if "%{TIZEN_PRODUCT_TV}" != "1" --enable-murphy \ +%else + --enable-rm \ %endif --disable-static make %{?jobs:-j%jobs} diff --git a/src/Makefile.am b/src/Makefile.am index b894f82..7939523 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -84,6 +84,11 @@ libmmfcamcorder_la_CFLAGS += $(MURPHY_RESOURCE_CFLAGS) $(MURPHY_GLIB_CFLAGS) -D_ libmmfcamcorder_la_LIBADD += $(MURPHY_RESOURCE_LIBS) $(MURPHY_GLIB_LIBS) endif +if RM_SUPPORT +libmmfcamcorder_la_CFLAGS += $(RM_CFLAGS) $(AUL_CFLAGS) -D_MMCAMCORDER_RM_SUPPORT +libmmfcamcorder_la_LIBADD += $(RM_LIBS) $(AUL_LIBS) +endif + install-exec-hook: mkdir -p $(DESTDIR)$(prefix)/share/sounds/mm-camcorder && \ cp $(srcdir)/../sounds/* $(DESTDIR)$(prefix)/share/sounds/mm-camcorder/ diff --git a/src/include/mm_camcorder_internal.h b/src/include/mm_camcorder_internal.h index bc1af5e..a90a4e9 100644 --- a/src/include/mm_camcorder_internal.h +++ b/src/include/mm_camcorder_internal.h @@ -60,6 +60,11 @@ #include "mm_camcorder_configure.h" #include "mm_camcorder_sound.h" +#ifdef _MMCAMCORDER_RM_SUPPORT +/* rm (resource manager)*/ +#include +#endif /* _MMCAMCORDER_RM_SUPPORT */ + #ifdef __cplusplus extern "C" { #endif @@ -664,6 +669,9 @@ typedef struct mmf_camcorder { #endif /* _MMCAMCORDER_ENABLE_IDLE_MESSAGE_CALLBACK */ camera_conf *conf_main; /**< Camera configure Main structure */ camera_conf *conf_ctrl; /**< Camera configure Control structure */ +#ifdef _MMCAMCORDER_RM_SUPPORT + int rm_handle; /**< Resource manager handle */ +#endif /* _MMCAMCORDER_RM_SUPPORT */ guint pipeline_cb_event_id; /**< Event source ID of pipeline message callback */ guint encode_pipeline_cb_event_id; /**< Event source ID of encode pipeline message callback */ guint setting_event_id; /**< Event source ID of attributes setting to sensor */ @@ -739,6 +747,10 @@ typedef struct mmf_camcorder { dpm_restriction_policy_h dpm_policy; /**< DPM restriction policy handle */ int dpm_camera_cb_id; /**< DPM camera policy changed callback id */ +#ifdef _MMCAMCORDER_RM_SUPPORT + rm_category_request_s request_resources; + rm_device_return_s returned_devices; +#endif /* _MMCAMCORDER_RM_SUPPORT */ int reserved[4]; /**< reserved */ } mmf_camcorder_t; diff --git a/src/mm_camcorder_gstcommon.c b/src/mm_camcorder_gstcommon.c index 02df73a..1d7c2f3 100644 --- a/src/mm_camcorder_gstcommon.c +++ b/src/mm_camcorder_gstcommon.c @@ -183,6 +183,10 @@ int _mmcamcorder_create_preview_elements(MMHandleType handle) char *err_name = NULL; char *socket_path = NULL; int socket_path_len; +#ifdef _MMCAMCORDER_RM_SUPPORT + int decoder_index = 0; + char decoder_name[20] = {'\0',}; +#endif /* _MMCAMCORDER_RM_SUPPORT */ GList *element_list = NULL; @@ -312,10 +316,18 @@ int _mmcamcorder_create_preview_elements(MMHandleType handle) if (videodecoder_name) { _mmcam_dbg_log("video decoder element [%s], recreate decoder %d", videodecoder_name, hcamcorder->recreate_decoder); +#ifdef _MMCAMCORDER_RM_SUPPORT + if (hcamcorder->request_resources.category_id[0] == RM_CATEGORY_VIDEO_DECODER_SUB) + decoder_index = 1; + snprintf(decoder_name, sizeof(decoder_name)-1, "%s%d", videodecoder_name, decoder_index); + _mmcam_dbg_log("encoded preview decoder_name %s", decoder_name); + /* create decoder element */ + _MMCAMCORDER_ELEMENT_MAKE(sc, sc->element, _MMCAMCORDER_VIDEOSRC_DECODE, decoder_name, "videosrc_decode", element_list, err); +#else /* _MMCAMCORDER_RM_SUPPORT */ /* create decoder element */ _MMCAMCORDER_ELEMENT_MAKE(sc, sc->element, _MMCAMCORDER_VIDEOSRC_DECODE, videodecoder_name, "videosrc_decode", element_list, err); - +#endif /* _MMCAMCORDER_RM_SUPPORT */ _mmcamcorder_conf_set_value_element_property(sc->element[_MMCAMCORDER_VIDEOSRC_DECODE].gst, sc->VideodecoderElementH264); } else { _mmcam_dbg_err("failed to get video decoder element name from %p", sc->VideodecoderElementH264); @@ -1239,6 +1251,9 @@ int _mmcamcorder_videosink_window_set(MMHandleType handle, type_element* Videosi int zoom_attr = 0; int zoom_level = 0; int do_scaling = FALSE; +#ifdef _MMCAMCORDER_RM_SUPPORT + int display_scaler = 0; +#endif /* _MMCAMCORDER_RM_SUPPORT */ int *overlay = NULL; gulong xid; char *err_name = NULL; @@ -1301,6 +1316,12 @@ int _mmcamcorder_videosink_window_set(MMHandleType handle, type_element* Videosi _mmcam_dbg_warn("Handle is NULL. Set xid as 0.. but, it's not recommended."); gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(vsink), 0); } +#ifdef _MMCAMCORDER_RM_SUPPORT + if (hcamcorder->request_resources.category_id[0] == RM_CATEGORY_VIDEO_DECODER_SUB) + display_scaler = 1; + + MMCAMCORDER_G_OBJECT_SET(vsink, "device-scaler", display_scaler); +#endif /* _MMCAMCORDER_RM_SUPPORT */ } else if (!strcmp(videosink_name, "evasimagesink") || !strcmp(videosink_name, "evaspixmapsink")) { _mmcam_dbg_log("videosink : %s, handle : %p", videosink_name, overlay); @@ -1319,6 +1340,12 @@ int _mmcamcorder_videosink_window_set(MMHandleType handle, type_element* Videosi gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(vsink), (guintptr)wl_info->global_surface_id); gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(vsink), wl_info->window_x, wl_info->window_y, wl_info->window_width, wl_info->window_height); +#ifdef _MMCAMCORDER_RM_SUPPORT + if (hcamcorder->request_resources.category_id[0] == RM_CATEGORY_VIDEO_DECODER_SUB) + display_scaler = 1; + + MMCAMCORDER_G_OBJECT_SET(vsink, "device-scaler", display_scaler); +#endif /* _MMCAMCORDER_RM_SUPPORT */ } else { _mmcam_dbg_warn("Handle is NULL. skip setting."); } @@ -2653,6 +2680,10 @@ bool _mmcamcorder_recreate_decoder_for_encoded_preview(MMHandleType handle) _MMCamcorderSubContext *sc = NULL; mmf_camcorder_t *hcamcorder = NULL; const char *videodecoder_name = NULL; +#ifdef _MMCAMCORDER_RM_SUPPORT + char decoder_name[20] = {'\0',}; + int decoder_index = 0; +#endif /* _MMCAMCORDER_RM_SUPPORT */ if ((void *)handle == NULL) { _mmcam_dbg_warn("handle is NULL"); @@ -2709,12 +2740,27 @@ bool _mmcamcorder_recreate_decoder_for_encoded_preview(MMHandleType handle) ((GObject *)sc->element[_MMCAMCORDER_VIDEOSRC_DECODE].gst)->ref_count); } +#ifdef _MMCAMCORDER_RM_SUPPORT + if (hcamcorder->request_resources.category_id[0] == RM_CATEGORY_VIDEO_DECODER_SUB) + decoder_index = 1; + + snprintf(decoder_name, sizeof(decoder_name)-1, "%s%d", videodecoder_name, decoder_index); + _mmcam_dbg_log("encoded preview decoder_name %s", decoder_name); + /* create decoder */ + sc->element[_MMCAMCORDER_VIDEOSRC_DECODE].gst = gst_element_factory_make(decoder_name, "videosrc_decode"); + if (sc->element[_MMCAMCORDER_VIDEOSRC_DECODE].gst == NULL) { + _mmcam_dbg_err("Decoder[%s] creation fail", decoder_name); + return FALSE; + } +#else /* _MMCAMCORDER_RM_SUPPORT */ /* create new decoder */ sc->element[_MMCAMCORDER_VIDEOSRC_DECODE].gst = gst_element_factory_make(videodecoder_name, "videosrc_decode"); if (sc->element[_MMCAMCORDER_VIDEOSRC_DECODE].gst == NULL) { _mmcam_dbg_err("Decoder [%s] creation fail", videodecoder_name); return FALSE; } +#endif /* _MMCAMCORDER_RM_SUPPORT */ + _mmcamcorder_conf_set_value_element_property(sc->element[_MMCAMCORDER_VIDEOSRC_DECODE].gst, sc->VideodecoderElementH264); sc->element[_MMCAMCORDER_VIDEOSRC_DECODE].id = _MMCAMCORDER_VIDEOSRC_DECODE; g_object_weak_ref(G_OBJECT(sc->element[_MMCAMCORDER_VIDEOSRC_DECODE].gst), diff --git a/src/mm_camcorder_internal.c b/src/mm_camcorder_internal.c index 6403c29..0baf5d9 100644 --- a/src/mm_camcorder_internal.c +++ b/src/mm_camcorder_internal.c @@ -46,6 +46,9 @@ #include #endif /* _MMCAMCORDER_MURPHY_SUPPORT */ +#ifdef _MMCAMCORDER_RM_SUPPORT +#include +#endif /* _MMCAMCORDER_RM_SUPPORT */ /*--------------------------------------------------------------------------------------- | LOCAL VARIABLE DEFINITIONS for internal | @@ -75,6 +78,10 @@ static gint __mmcamcorder_gst_handle_core_error(MMHandleType handle, int cod static gint __mmcamcorder_gst_handle_resource_warning(MMHandleType handle, GstMessage *message , GError *error); static gboolean __mmcamcorder_handle_gst_warning(MMHandleType handle, GstMessage *message, GError *error); +#ifdef _MMCAMCORDER_RM_SUPPORT +rm_cb_result _mmcamcorder_rm_callback(int handle, rm_callback_type event_src, + rm_device_request_s *info, void *cb_data); +#endif /* _MMCAMCORDER_RM_SUPPORT */ #ifdef _MMCAMCORDER_USE_SET_ATTR_CB static gboolean __mmcamcorder_set_attr_to_camsensor_cb(gpointer data); #endif /* _MMCAMCORDER_USE_SET_ATTR_CB */ @@ -616,6 +623,9 @@ int _mmcamcorder_destroy(MMHandleType handle) int ret = MM_ERROR_NONE; int state = MM_CAMCORDER_STATE_NONE; int state_FROM = MM_CAMCORDER_STATE_NULL; +#ifdef _MMCAMCORDER_RM_SUPPORT + int iret = RM_OK; +#endif /* _MMCAMCORDER_RM_SUPPORT */ mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); @@ -712,6 +722,14 @@ int _mmcamcorder_destroy(MMHandleType handle) _mmcam_dbg_log("no need to unregister sound focus.[%d, id %d]", hcamcorder->sound_focus_register, hcamcorder->sound_focus_id); } +#ifdef _MMCAMCORDER_RM_SUPPORT + if (hcamcorder->rm_handle != 0) { + iret = rm_unregister(hcamcorder->rm_handle); + if (iret != RM_OK) + _mmcam_dbg_err("rm_unregister() failed"); + hcamcorder->rm_handle = 0; + } +#endif /* _MMCAMCORDER_RM_SUPPORT */ /* release model_name */ if (hcamcorder->model_name) { @@ -807,6 +825,9 @@ int _mmcamcorder_realize(MMHandleType handle) const char *videosink_name = NULL; char *socket_path = NULL; int socket_path_len; +#ifdef _MMCAMCORDER_RM_SUPPORT + int iret = RM_OK; +#endif /* _MMCAMCORDER_RM_SUPPORT */ mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); @@ -899,6 +920,79 @@ int _mmcamcorder_realize(MMHandleType handle) _mmcam_dbg_log("no need to register sound focus"); } +#ifdef _MMCAMCORDER_RM_SUPPORT + int preview_format = MM_PIXEL_FORMAT_NV12; + int qret = RM_OK; + int qret_avail = RM_OK; + rm_consumer_info rci; + int app_pid = 0; + int resource_count = 0; + + mm_camcorder_get_attributes(handle, NULL, + MMCAM_PID_FOR_SOUND_FOCUS, &app_pid, + NULL); + rci.app_pid = app_pid; + aul_app_get_appid_bypid(rci.app_pid, rci.app_id, sizeof(rci.app_id)); + + /* RM register */ + if (hcamcorder->rm_handle == 0) { + iret = rm_register((rm_resource_cb)_mmcamcorder_rm_callback, (void*)hcamcorder, + &(hcamcorder->rm_handle), &rci); + if (iret != RM_OK) { + _mmcam_dbg_err("rm_register fail"); + ret = MM_ERROR_POLICY_BLOCKED; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + } + + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_FORMAT, &preview_format, + NULL); + + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO && preview_format == MM_PIXEL_FORMAT_ENCODED_H264) { + + resource_count = 0; + memset(&hcamcorder->request_resources, 0x0, sizeof(rm_category_request_s)); + memset(&hcamcorder->returned_devices, 0x0, sizeof(rm_device_return_s)); + hcamcorder->request_resources.state[resource_count] = RM_STATE_EXCLUSIVE; + hcamcorder->request_resources.category_id[resource_count] = RM_CATEGORY_VIDEO_DECODER; + _mmcam_dbg_log("request video decoder resource - device category 0x%x",hcamcorder->request_resources.category_id[resource_count]); + + resource_count++; + hcamcorder->request_resources.state[resource_count] = RM_STATE_EXCLUSIVE; + hcamcorder->request_resources.category_id[resource_count] = RM_CATEGORY_SCALER; + hcamcorder->request_resources.request_num = resource_count + 1; + _mmcam_dbg_log("request scaler resource - device category 0x%x",hcamcorder->request_resources.category_id[resource_count]); + + + qret = rm_query(hcamcorder->rm_handle, RM_QUERY_ALLOCATION, &(hcamcorder->request_resources), &qret_avail); + + if (qret != RM_OK || qret_avail != RM_OK) { + _mmcam_dbg_log("Resource manager main device request fail"); + + resource_count = 0; + hcamcorder->request_resources.category_id[resource_count] = RM_CATEGORY_VIDEO_DECODER_SUB; + _mmcam_dbg_log("request video decoder resource - device category 0x%x",hcamcorder->request_resources.category_id[resource_count]); + + resource_count++; + hcamcorder->request_resources.category_id[resource_count] = RM_CATEGORY_SCALER_SUB; + _mmcam_dbg_log("request scaler resource - device category 0x%x",hcamcorder->request_resources.category_id[resource_count]); + } + + resource_count++; + hcamcorder->request_resources.state[resource_count] = RM_STATE_EXCLUSIVE; + hcamcorder->request_resources.category_id[resource_count] = RM_CATEGORY_CAMERA; + hcamcorder->request_resources.request_num = resource_count + 1; + _mmcam_dbg_log("request camera resource - device category 0x%x",hcamcorder->request_resources.category_id[resource_count]); + + iret = rm_allocate_resources(hcamcorder->rm_handle, &(hcamcorder->request_resources), &hcamcorder->returned_devices); + if (iret != RM_OK) { + _mmcam_dbg_err("Resource allocation request failed"); + ret = MM_ERROR_POLICY_BLOCKED; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + } +#endif /* _MMCAMCORDER_RM_SUPPORT */ /* alloc sub context */ hcamcorder->sub_context = _mmcamcorder_alloc_subcontext(hcamcorder->type); @@ -1115,6 +1209,27 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: } } } +#ifdef _MMCAMCORDER_RM_SUPPORT + if (hcamcorder->rm_handle) { + if (hcamcorder->returned_devices.allocated_num > 0) { + int idx = 0; + rm_device_request_s requested; + memset(&requested, 0x0, sizeof(rm_device_request_s)); + requested.request_num = hcamcorder->returned_devices.allocated_num; + for (idx = 0; idx < requested.request_num; idx++) { + requested.device_id[idx] = hcamcorder->returned_devices.device_id[idx]; + } + iret = rm_deallocate_resources(hcamcorder->rm_handle, &requested); + if (iret != RM_OK) + _mmcam_dbg_err("Resource deallocation request failed "); + } + /* unregister RM */ + int ires = rm_unregister(hcamcorder->rm_handle); + if (ires != RM_OK) + _mmcam_dbg_err("rm_unregister() failed"); + hcamcorder->rm_handle = 0; + } +#endif /* _MMCAMCORDER_RM_SUPPORT*/ _ERR_CAMCORDER_CMD_PRECON: _mmcam_dbg_err("Realize fail (type %d, state %d, ret %x)", @@ -1182,6 +1297,22 @@ int _mmcamcorder_unrealize(MMHandleType handle) } #endif /* _MMCAMCORDER_MURPHY_SUPPORT */ +#ifdef _MMCAMCORDER_RM_SUPPORT + if (hcamcorder->rm_handle && (hcamcorder->returned_devices.allocated_num > 0)) { + int iret = RM_OK; + int idx = 0; + rm_device_request_s requested; + memset(&requested, 0x0, sizeof(rm_device_request_s)); + requested.request_num = hcamcorder->returned_devices.allocated_num; + for (idx = 0; idx < requested.request_num; idx++) { + requested.device_id[idx] = hcamcorder->returned_devices.device_id[idx]; + } + iret = rm_deallocate_resources(hcamcorder->rm_handle, &requested); + if (iret != RM_OK) + _mmcam_dbg_err("Resource deallocation request failed "); + } +#endif /* _MMCAMCORDER_RM_SUPPORT*/ + /* Deinitialize main context member */ hcamcorder->command = NULL; @@ -4030,3 +4161,45 @@ int _mmcamcorder_get_video_caps(MMHandleType handle, char **caps) return MM_ERROR_NONE; } +#ifdef _MMCAMCORDER_RM_SUPPORT +rm_cb_result _mmcamcorder_rm_callback(int handle, rm_callback_type event_src, + rm_device_request_s *info, void* cb_data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(cb_data); + int current_state = MM_CAMCORDER_STATE_NONE; + rm_cb_result cb_res = RM_CB_RESULT_OK; + + mmf_return_val_if_fail((MMHandleType)hcamcorder, RM_CB_RESULT_OK); + + current_state = _mmcamcorder_get_state((MMHandleType)hcamcorder); + if (current_state <= MM_CAMCORDER_STATE_NONE || + current_state >= MM_CAMCORDER_STATE_NUM) { + _mmcam_dbg_err("Abnormal state. Or null handle. (%p, %d)", hcamcorder, current_state); + } + + _MMCAMCORDER_LOCK_ASM(hcamcorder); + + /* set value to inform a status is changed by RM */ + hcamcorder->state_change_by_system = _MMCAMCORDER_STATE_CHANGE_BY_RM; + + /* set RM event code for sending it to application */ + hcamcorder->interrupt_code = event_src; + + _mmcam_dbg_log("RM conflict callback : event code 0x%x", event_src); + switch (event_src) { + case RM_CALLBACK_TYPE_RESOURCE_CONFLICT: + case RM_CALLBACK_TYPE_RESOURCE_CONFLICT_UD: + __mmcamcorder_force_stop(hcamcorder); + break; + default: + break; + } + + /* restore value */ + hcamcorder->state_change_by_system = _MMCAMCORDER_STATE_CHANGE_NORMAL; + + _MMCAMCORDER_UNLOCK_ASM(hcamcorder); + + return cb_res; +} +#endif /* _MMCAMCORDER_RM_SUPPORT */ \ No newline at end of file diff --git a/test/Makefile.am b/test/Makefile.am index 12e9e57..ab50b32 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -22,3 +22,7 @@ mm_camcorder_testsuite_LDADD = $(top_builddir)/src/libmmfcamcorder.la \ $(MM_COMMON_LIBS)\ $(MM_SOUND_LIBS) +if RM_SUPPORT +mm_camcorder_testsuite_CFLAGS += $(RM_CFLAGS) -D_MMCAMCORDER_RM_SUPPORT +mm_camcorder_testsuite_LDADD += $(RM_LIBS) +endif \ No newline at end of file -- 2.7.4