From: YeJin Cho Date: Thu, 23 Jul 2015 11:14:31 +0000 (+0900) Subject: 1. Split audiobin/videobin into decodebin/sinkbin X-Git-Tag: accepted/tizen/mobile/20150804.062906~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c37dac02748d9bd80ace723d693ac1dcfc58d64a;p=platform%2Fcore%2Fmultimedia%2Flibmm-wfd.git 1. Split audiobin/videobin into decodebin/sinkbin 2. Remove unused attribute : hdcp_handle Change-Id: I9ba668bf765973768b20b65780735f153c380234 Signed-off-by: YeJin Cho --- diff --git a/common/mm_wfd_attrs.c b/common/mm_wfd_attrs.c index 2de2253..5d43efb 100755 --- a/common/mm_wfd_attrs.c +++ b/common/mm_wfd_attrs.c @@ -305,15 +305,6 @@ _mmwfd_construct_attribute(MMHandleType handle) 4096 }, { - (char *)"hdcp_handle", - MM_ATTRS_TYPE_DATA, - MM_ATTRS_FLAG_RW, - (void *) NULL, - MM_ATTRS_VALID_TYPE_NONE, - 0, - 0 - }, - { (char *)"hdcp_version", MM_ATTRS_TYPE_INT, MM_ATTRS_FLAG_RW, diff --git a/packaging/libmm-wfd.spec b/packaging/libmm-wfd.spec index 38b4035..7faa7aa 100755 --- a/packaging/libmm-wfd.spec +++ b/packaging/libmm-wfd.spec @@ -1,6 +1,6 @@ Name: libmm-wfd Summary: Multimedia Framework Wifi-Display Library -Version: 0.2.179 +Version: 0.2.180 Release: 0 Group: System/Libraries License: Apache License 2.0 diff --git a/sink/include/mm_wfd_sink_manager.h b/sink/include/mm_wfd_sink_manager.h index 77489a3..b28fade 100755 --- a/sink/include/mm_wfd_sink_manager.h +++ b/sink/include/mm_wfd_sink_manager.h @@ -55,15 +55,26 @@ extern "C" { wfd_sink->waiting_cmd = FALSE; \ } while (0); -#define WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink, cmd) \ +#define WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, cmd) \ do {\ - if (wfd_sink->manager_thread_cmd != WFD_SINK_MANAGER_CMD_EXIT) {\ - wfd_sink->manager_thread_cmd |= cmd;\ - if (wfd_sink->waiting_cmd) {\ - wfd_sink_debug("send command signal to manager thread with %x command\n", &(wfd_sink->manager_thread_cmd));\ + WFD_SINK_MANAGER_LOCK(wfd_sink);\ + if (cmd == WFD_SINK_MANAGER_CMD_EXIT) {\ + g_list_free(wfd_sink->manager_thread_cmd);\ + }\ + wfd_sink->manager_thread_cmd = g_list_append(wfd_sink->manager_thread_cmd, GINT_TO_POINTER(cmd)); \ + WFD_SINK_MANAGER_UNLOCK(wfd_sink);\ + } while (0); + +#define WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink) \ + do {\ + WFD_SINK_MANAGER_LOCK(wfd_sink);\ + if (wfd_sink->waiting_cmd) {\ + if (wfd_sink->manager_thread_cmd) {\ + wfd_sink_debug("send command signal to manager thread \n");\ g_cond_signal(&((wfd_sink)->manager_thread_cond));\ }\ }\ + WFD_SINK_MANAGER_UNLOCK(wfd_sink);\ } while (0); /** diff --git a/sink/include/mm_wfd_sink_priv.h b/sink/include/mm_wfd_sink_priv.h index 5be6d31..f7c0249 100755 --- a/sink/include/mm_wfd_sink_priv.h +++ b/sink/include/mm_wfd_sink_priv.h @@ -46,36 +46,47 @@ enum WFDSinkMainElementID { WFD_SINK_M_NUM }; -/* audio pipeline's element id */ -enum WFDSinkAudioElementID { - WFD_SINK_A_BIN = 0, /* NOTE : WFD_SINK_A_BIN should be zero */ - WFD_SINK_A_QUEUE, - WFD_SINK_A_HDCP, - WFD_SINK_A_AAC_PARSE, - WFD_SINK_A_AAC_DEC, - WFD_SINK_A_AC3_PARSE, - WFD_SINK_A_AC3_DEC, - WFD_SINK_A_LPCM_CONVERTER, - WFD_SINK_A_LPCM_FILTER, - WFD_SINK_A_CAPSFILTER, - WFD_SINK_A_RESAMPLER, - WFD_SINK_A_VOLUME, - WFD_SINK_A_SINK, - WFD_SINK_A_NUM +/* audio decodebin's element id */ +enum WFDSinkAudioDecodeBinElementID { + WFD_SINK_A_D_BIN = 0, /* NOTE : WFD_SINK_A_D_BIN should be zero */ + WFD_SINK_A_D_QUEUE, + WFD_SINK_A_D_HDCP, + WFD_SINK_A_D_AAC_PARSE, + WFD_SINK_A_D_AAC_DEC, + WFD_SINK_A_D_AC3_PARSE, + WFD_SINK_A_D_AC3_DEC, + WFD_SINK_A_D_LPCM_CONVERTER, + WFD_SINK_A_D_LPCM_FILTER, + WFD_SINK_A_D_NUM }; -/* video pipeline's element id */ -enum WFDSinkVideoElementID { - WFD_SINK_V_BIN = 0, /* NOTE : WFD_SINK_V_BIN should be zero */ - WFD_SINK_V_QUEUE, - WFD_SINK_V_HDCP, - WFD_SINK_V_PARSE, - WFD_SINK_V_CAPSSETTER, - WFD_SINK_V_DEC, - WFD_SINK_V_CONVERT, - WFD_SINK_V_CAPSFILTER, - WFD_SINK_V_SINK, - WFD_SINK_V_NUM +/* audio sinkbin's element id */ +enum WFDSinkAudioSinkBinElementID { + WFD_SINK_A_S_BIN = 0, /* NOTE : WFD_SINK_A_S_BIN should be zero */ + WFD_SINK_A_S_RESAMPLER, + WFD_SINK_A_S_VOLUME, + WFD_SINK_A_S_SINK, + WFD_SINK_A_S_NUM +}; + +/* video decodebin's element id */ +enum WFDSinkVideoDecodeBinElementID { + WFD_SINK_V_D_BIN = 0, /* NOTE : WFD_SINK_V_D_BIN should be zero */ + WFD_SINK_V_D_QUEUE, + WFD_SINK_V_D_HDCP, + WFD_SINK_V_D_PARSE, + WFD_SINK_V_D_CAPSSETTER, + WFD_SINK_V_D_DEC, + WFD_SINK_V_D_NUM +}; + +/* video sinkbin's element id */ +enum WFDSinkVideoSinkBinElementID { + WFD_SINK_V_S_BIN = 0, /* NOTE : WFD_SINK_V_S_BIN should be zero */ + WFD_SINK_V_S_CONVERT, + WFD_SINK_V_S_FILTER, + WFD_SINK_V_S_SINK, + WFD_SINK_V_S_NUM }; /** @@ -100,11 +111,11 @@ typedef enum { * */ typedef enum { WFD_SINK_MANAGER_CMD_NONE = 0, - WFD_SINK_MANAGER_CMD_LINK_A_BIN = (1 << 0), - WFD_SINK_MANAGER_CMD_LINK_V_BIN = (1 << 1), - WFD_SINK_MANAGER_CMD_PREPARE_A_BIN = (1 << 2), - WFD_SINK_MANAGER_CMD_PREPARE_V_BIN = (1 << 3), - WFD_SINK_MANAGER_CMD_EXIT = (1 << 8) + WFD_SINK_MANAGER_CMD_LINK_A_DECODEBIN, + WFD_SINK_MANAGER_CMD_LINK_V_DECODEBIN, + WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE, + WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE, + WFD_SINK_MANAGER_CMD_EXIT, } WFDSinkManagerCMDType; /** @@ -149,8 +160,10 @@ typedef struct { typedef struct { MMWFDSinkGstElement *mainbin; - MMWFDSinkGstElement *audiobin; - MMWFDSinkGstElement *videobin; + MMWFDSinkGstElement *a_decodebin; + MMWFDSinkGstElement *v_decodebin; + MMWFDSinkGstElement *a_sinkbin; + MMWFDSinkGstElement *v_sinkbin; } MMWFDSinkGstPipelineInfo; typedef struct { @@ -164,9 +177,8 @@ typedef struct { typedef struct { /* gstreamer pipeline */ MMWFDSinkGstPipelineInfo *pipeline; - gint added_av_pad_num; - gboolean audio_bin_is_linked; - gboolean video_bin_is_linked; + gboolean audio_decodebin_is_linked; + gboolean video_decodebin_is_linked; GstPad *prev_audio_dec_src_pad; GstPad *next_audio_dec_sink_pad; @@ -203,16 +215,14 @@ typedef struct { MMWFDMessageCallback msg_cb; void *msg_user_data; - /* audio session manager related variables */ - GList *resource_list; - /* video resolution for negotiation */ MMWFDSinkResolution supportive_resolution; GThread *manager_thread; GMutex manager_thread_mutex; GCond manager_thread_cond; - WFDSinkManagerCMDType manager_thread_cmd; + GList *manager_thread_cmd; + gboolean manager_thread_exit; } mm_wfd_sink_t; @@ -229,10 +239,10 @@ int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback c int _mm_wfd_sink_get_resource(mm_wfd_sink_t *wfd_sink); int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution); -int __mm_wfd_sink_link_audiobin(mm_wfd_sink_t *wfd_sink); -int __mm_wfd_sink_link_videobin(mm_wfd_sink_t *wfd_sink); -int __mm_wfd_sink_prepare_videobin(mm_wfd_sink_t *wfd_sink); -int __mm_wfd_sink_prepare_audiobin(mm_wfd_sink_t *wfd_sink); +int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink); +int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink); +int __mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink); +int __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink); const gchar *_mm_wfds_sink_get_state_name(MMWFDSinkStateType state); diff --git a/sink/mm_wfd_sink_manager.c b/sink/mm_wfd_sink_manager.c index 737cfd6..f9a8c86 100755 --- a/sink/mm_wfd_sink_manager.c +++ b/sink/mm_wfd_sink_manager.c @@ -32,15 +32,16 @@ int _mm_wfd_sink_init_manager(mm_wfd_sink_t *wfd_sink) wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - /* create capture mutex */ + /* create manager mutex */ g_mutex_init(&(wfd_sink->manager_thread_mutex)); /* create capture cond */ g_cond_init(&(wfd_sink->manager_thread_cond)); - wfd_sink->manager_thread_cmd = WFD_SINK_MANAGER_CMD_NONE; + wfd_sink->manager_thread_cmd = NULL; + wfd_sink->manager_thread_exit = FALSE; - /* create video capture thread */ + /* create manager thread */ wfd_sink->manager_thread = g_thread_new("__mm_wfd_sink_manager_thread", __mm_wfd_sink_manager_thread, (gpointer)wfd_sink); if (wfd_sink->manager_thread == NULL) { @@ -65,11 +66,10 @@ int _mm_wfd_sink_release_manager(mm_wfd_sink_t *wfd_sink) wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - /* release capture thread */ + /* release manager thread */ if (wfd_sink->manager_thread) { - WFD_SINK_MANAGER_LOCK(wfd_sink); - WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); - WFD_SINK_MANAGER_UNLOCK(wfd_sink); + WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); + WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); wfd_sink_debug("waitting for manager thread exit"); g_thread_join(wfd_sink->manager_thread); @@ -87,18 +87,15 @@ static gpointer __mm_wfd_sink_manager_thread(gpointer data) { mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data; - gboolean link_auido_bin = FALSE; - gboolean link_video_bin = FALSE; - gboolean set_ready_audio_bin = FALSE; - gboolean set_ready_video_bin = FALSE; - + WFDSinkManagerCMDType cmd = WFD_SINK_MANAGER_CMD_NONE; + GList *walk = NULL; wfd_sink_debug_fenter(); wfd_sink_return_val_if_fail(wfd_sink, NULL); - if (wfd_sink->manager_thread_cmd & WFD_SINK_MANAGER_CMD_EXIT) { - wfd_sink->manager_thread_cmd = WFD_SINK_MANAGER_CMD_EXIT; + if (wfd_sink->manager_thread_exit) { + wfd_sink_debug("exit manager thread..."); return NULL; } @@ -108,64 +105,51 @@ __mm_wfd_sink_manager_thread(gpointer data) WFD_SINK_MANAGER_LOCK(wfd_sink); WFD_SINK_MANAGER_WAIT_CMD(wfd_sink); - wfd_sink_debug("got command %x", wfd_sink->manager_thread_cmd); - - if (wfd_sink->manager_thread_cmd & WFD_SINK_MANAGER_CMD_EXIT) { - wfd_sink_debug("exiting manager thread"); - goto EXIT; - } - - /* check command */ - link_auido_bin = wfd_sink->manager_thread_cmd & WFD_SINK_MANAGER_CMD_LINK_A_BIN; - link_video_bin = wfd_sink->manager_thread_cmd & WFD_SINK_MANAGER_CMD_LINK_V_BIN; - set_ready_audio_bin = wfd_sink->manager_thread_cmd & WFD_SINK_MANAGER_CMD_PREPARE_A_BIN; - if (set_ready_audio_bin && !link_auido_bin && !wfd_sink->audio_bin_is_linked) { - wfd_sink_error("audio bin is not linked... wait for command for linking audiobin"); - WFD_SINK_MANAGER_UNLOCK(wfd_sink); - continue; - } - set_ready_video_bin = wfd_sink->manager_thread_cmd & WFD_SINK_MANAGER_CMD_PREPARE_V_BIN; - if (set_ready_video_bin && !link_video_bin && !wfd_sink->video_bin_is_linked) { - wfd_sink_error("video bin is not linked... wait for command for linking videobin."); - WFD_SINK_MANAGER_UNLOCK(wfd_sink); - continue; - } - - /* link audio bin*/ - if (link_auido_bin) { - wfd_sink_debug("try to link audiobin."); - if (MM_ERROR_NONE != __mm_wfd_sink_link_audiobin(wfd_sink)) { - wfd_sink_error("failed to link audiobin.....\n"); - goto EXIT; - } - } - - /* link video bin*/ - if (link_video_bin) { - wfd_sink_debug("try to link videobin."); - if (MM_ERROR_NONE != __mm_wfd_sink_link_videobin(wfd_sink)) { - wfd_sink_error("failed to link videobin.....\n"); - goto EXIT; - } - } - - if (set_ready_audio_bin) { - wfd_sink_debug("try to prepare audiobin."); - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiobin(wfd_sink)) { - wfd_sink_error("failed to prepare audiobin.....\n"); - goto EXIT; - } - } - - if (set_ready_video_bin) { - wfd_sink_debug("try to prepare videobin."); - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videobin(wfd_sink)) { - wfd_sink_error("failed to prepare videobin.....\n"); - goto EXIT; + for (walk = wfd_sink->manager_thread_cmd; walk; walk = g_list_next (walk)) { + cmd = GPOINTER_TO_INT(walk->data); + + wfd_sink_debug("got command %d", cmd); + + switch (cmd) { + case WFD_SINK_MANAGER_CMD_LINK_A_DECODEBIN: + wfd_sink_debug("try to link audio decodebin."); + if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to link audio decodebin.....\n"); + goto EXIT; + } + break; + case WFD_SINK_MANAGER_CMD_LINK_V_DECODEBIN: + wfd_sink_debug("try to link video decodebin."); + if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to link video decodebin.....\n"); + goto EXIT; + } + break; + case WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE: + wfd_sink_debug("try to prepare audio pipeline."); + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink)) { + wfd_sink_error("failed to prepare audio pipeline.....\n"); + goto EXIT; + } + break; + case WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE: + wfd_sink_debug("try to prepare video pipeline."); + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink)) { + wfd_sink_error("failed to prepare video pipeline.....\n"); + goto EXIT; + } + break; + case WFD_SINK_MANAGER_CMD_EXIT: + wfd_sink_debug("exiting manager thread"); + goto EXIT; + break; + default: + break; } } - wfd_sink->manager_thread_cmd = WFD_SINK_MANAGER_CMD_NONE; + g_list_free(wfd_sink->manager_thread_cmd); + wfd_sink->manager_thread_cmd = NULL; WFD_SINK_MANAGER_UNLOCK(wfd_sink); } @@ -175,7 +159,7 @@ __mm_wfd_sink_manager_thread(gpointer data) return NULL; EXIT: - wfd_sink->manager_thread_cmd = WFD_SINK_MANAGER_CMD_EXIT; + wfd_sink->manager_thread_exit = TRUE; WFD_SINK_MANAGER_UNLOCK(wfd_sink); diff --git a/sink/mm_wfd_sink_priv.c b/sink/mm_wfd_sink_priv.c index db11fe6..101b766 100755 --- a/sink/mm_wfd_sink_priv.c +++ b/sink/mm_wfd_sink_priv.c @@ -33,8 +33,12 @@ /* gstreamer */ static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink); static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink); -static int __mm_wfd_sink_create_videobin(mm_wfd_sink_t *wfd_sink); -static int __mm_wfd_sink_create_audiobin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink); static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink); static int __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async); @@ -60,7 +64,7 @@ int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink) /* create handle */ new_wfd_sink = g_malloc0(sizeof(mm_wfd_sink_t)); if (!new_wfd_sink) { - wfd_sink_error("failed to allocate memory for wi-fi display sink\n"); + wfd_sink_error("failed to allocate memory for wi-fi display sink"); return MM_ERROR_WFD_NO_FREE_SPACE; } @@ -68,9 +72,8 @@ int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink) new_wfd_sink->attrs = 0; new_wfd_sink->pipeline = NULL; - new_wfd_sink->added_av_pad_num = 0; - new_wfd_sink->audio_bin_is_linked = FALSE; - new_wfd_sink->video_bin_is_linked = FALSE; + new_wfd_sink->audio_decodebin_is_linked = FALSE; + new_wfd_sink->video_decodebin_is_linked = FALSE; new_wfd_sink->prev_audio_dec_src_pad = NULL; new_wfd_sink->next_audio_dec_sink_pad = NULL; @@ -104,12 +107,10 @@ int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink) new_wfd_sink->cmd = MM_WFD_SINK_COMMAND_CREATE; new_wfd_sink->waiting_cmd = FALSE; - /* Initialize resource related */ - new_wfd_sink->resource_list = NULL; - /* Initialize manager related */ new_wfd_sink->manager_thread = NULL; - new_wfd_sink->manager_thread_cmd = WFD_SINK_MANAGER_CMD_NONE; + new_wfd_sink->manager_thread_cmd = NULL; + new_wfd_sink->manager_thread_exit = FALSE; /* Initialize video resolution */ new_wfd_sink->supportive_resolution = MM_WFD_SINK_RESOLUTION_UNKNOWN; @@ -118,14 +119,14 @@ int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink) new_wfd_sink->attrs = _mmwfd_construct_attribute((MMHandleType)new_wfd_sink); if (!new_wfd_sink->attrs) { MMWFDSINK_FREEIF(new_wfd_sink); - wfd_sink_error("failed to set attribute\n"); + wfd_sink_error("failed to set attribute"); return MM_ERROR_WFD_INTERNAL; } /* load ini for initialize */ result = mm_wfd_sink_ini_load(&new_wfd_sink->ini); if (result != MM_ERROR_NONE) { - wfd_sink_error("failed to load ini file\n"); + wfd_sink_error("failed to load ini file"); goto fail_to_load_ini; } new_wfd_sink->need_to_reset_basetime = new_wfd_sink->ini.enable_reset_basetime; @@ -133,14 +134,14 @@ int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink) /* initialize manager */ result = _mm_wfd_sink_init_manager(new_wfd_sink); if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to init manager : %d\n", result); + wfd_sink_error("failed to init manager : %d", result); goto fail_to_init; } /* initialize gstreamer */ result = __mm_wfd_sink_init_gstreamer(new_wfd_sink); if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to init gstreamer : %d\n", result); + wfd_sink_error("failed to init gstreamer : %d", result); goto fail_to_init; } @@ -181,28 +182,42 @@ int _mm_wfd_sink_prepare(mm_wfd_sink_t *wfd_sink) /* create main pipeline */ result = __mm_wfd_sink_create_pipeline(wfd_sink); if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to create pipeline : %d\n", result); + wfd_sink_error("failed to create pipeline : %d", result); + goto fail_to_create; + } + + /* create video decodebin */ + result = __mm_wfd_sink_create_video_decodebin(wfd_sink); + if (result < MM_ERROR_NONE) { + wfd_sink_error("failed to create video decodebin", result); + goto fail_to_create; + } + + /* create video sinkbin */ + result = __mm_wfd_sink_create_video_sinkbin(wfd_sink); + if (result < MM_ERROR_NONE) { + wfd_sink_error("failed to create video sinkbin", result); goto fail_to_create; } - /* create videobin */ - result = __mm_wfd_sink_create_videobin(wfd_sink); + /* create audio decodebin */ + result = __mm_wfd_sink_create_audio_decodebin(wfd_sink); if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to create videobin : %d\n", result); + wfd_sink_error("fail to create audio decodebin : %d", result); goto fail_to_create; } - /* create audiobin */ - result = __mm_wfd_sink_create_audiobin(wfd_sink); + /* create audio sinkbin */ + result = __mm_wfd_sink_create_audio_sinkbin(wfd_sink); if (result < MM_ERROR_NONE) { - wfd_sink_error("fail to create audiobin : %d\n", result); + wfd_sink_error("fail to create audio sinkbin : %d", result); goto fail_to_create; } /* set pipeline READY state */ result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_READY, TRUE); if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to set state : %d\n", result); + wfd_sink_error("failed to set state : %d", result); goto fail_to_create; } @@ -240,7 +255,7 @@ int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri) /* check current wi-fi display sink state */ MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_CONNECT); - wfd_sink_debug("try to connect to %s.....\n", GST_STR_NULL(uri)); + wfd_sink_debug("try to connect to %s.....", GST_STR_NULL(uri)); /* set uri to wfdrtspsrc */ g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst), "location", uri, NULL); @@ -248,7 +263,7 @@ int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri) /* set pipeline PAUSED state */ result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PAUSED, TRUE); if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to set state : %d\n", result); + wfd_sink_error("failed to set state : %d", result); return result; } @@ -274,7 +289,7 @@ int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink) result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PLAYING, TRUE); if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to set state : %d\n", result); + wfd_sink_error("failed to set state : %d", result); return result; } @@ -345,13 +360,11 @@ int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink) /* check current wi-fi display sink state */ MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DISCONNECT); - WFD_SINK_MANAGER_LOCK(wfd_sink) ; - WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); - WFD_SINK_MANAGER_UNLOCK(wfd_sink); + WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); + WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "close", NULL); - wfd_sink_debug_fleave(); return result; @@ -368,17 +381,16 @@ int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink) /* check current wi-fi display sink state */ MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_UNPREPARE); - WFD_SINK_MANAGER_LOCK(wfd_sink) ; - WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); - WFD_SINK_MANAGER_UNLOCK(wfd_sink); + WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); + WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); /* release pipeline */ result = __mm_wfd_sink_destroy_pipeline(wfd_sink); if (result != MM_ERROR_NONE) { - wfd_sink_error("failed to destory pipeline\n"); + wfd_sink_error("failed to destory pipeline"); return MM_ERROR_WFD_INTERNAL; } else { - wfd_sink_debug("success to destory pipeline\n"); + wfd_sink_debug("success to destory pipeline"); } /* set state */ @@ -407,7 +419,7 @@ int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink) _mmwfd_deconstruct_attribute(wfd_sink->attrs); if (MM_ERROR_NONE != _mm_wfd_sink_release_manager(wfd_sink)) { - wfd_sink_error("failed to release manager\n"); + wfd_sink_error("failed to release manager"); return MM_ERROR_WFD_INTERNAL; } @@ -451,7 +463,7 @@ static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink) argc = calloc(1, sizeof(gint)); argv = calloc(max_argc, sizeof(gchar *)); if (!argc || !argv) { - wfd_sink_error("failed to allocate memory for wfdsink\n"); + wfd_sink_error("failed to allocate memory for wfdsink"); MMWFDSINK_FREEIF(argv); MMWFDSINK_FREEIF(argc); @@ -474,22 +486,22 @@ static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink) /* check ini */ for (i = 0; i < 5; i++) { if (strlen(wfd_sink->ini.gst_param[i]) > 2) { - wfd_sink_debug("set %s\n", wfd_sink->ini.gst_param[i]); + wfd_sink_debug("set %s", wfd_sink->ini.gst_param[i]); argv[*argc] = g_strdup(wfd_sink->ini.gst_param[i]); (*argc)++; } } - wfd_sink_debug("initializing gstreamer with following parameter\n"); - wfd_sink_debug("argc : %d\n", *argc); + wfd_sink_debug("initializing gstreamer with following parameter"); + wfd_sink_debug("argc : %d", *argc); for (i = 0; i < *argc; i++) { - wfd_sink_debug("argv[%d] : %s\n", i, argv[i]); + wfd_sink_debug("argv[%d] : %s", i, argv[i]); } /* initializing gstreamer */ if (!gst_init_check(argc, &argv, &err)) { - wfd_sink_error("failed to initialize gstreamer: %s\n", + wfd_sink_error("failed to initialize gstreamer: %s", err ? err->message : "unknown error occurred"); if (err) g_error_free(err); @@ -552,7 +564,7 @@ _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) wfd_sink_return_val_if_fail(wfd_sink, FALSE); wfd_sink_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE); - wfd_sink_debug("got %s from %s \n", + wfd_sink_debug("got %s from %s", GST_STR_NULL(GST_MESSAGE_TYPE_NAME(msg)), GST_STR_NULL(GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)))); @@ -564,8 +576,8 @@ _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) /* get error code */ gst_message_parse_error(msg, &error, &debug); - wfd_sink_error("error : %s\n", error->message); - wfd_sink_error("debug : %s\n", debug); + wfd_sink_error("error : %s", error->message); + wfd_sink_error("debug : %s", debug); MMWFDSINK_FREEIF(debug); g_error_free(error); @@ -578,8 +590,8 @@ _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) gst_message_parse_warning(msg, &error, &debug); - wfd_sink_error("warning : %s\n", error->message); - wfd_sink_error("debug : %s\n", debug); + wfd_sink_warning("warning : %s", error->message); + wfd_sink_warning("debug : %s", debug); MMWFDSINK_FREEIF(debug); g_error_free(error); @@ -610,14 +622,14 @@ _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) newstate = (GstState)vnewstate->data[0].v_int; pending = (GstState)vpending->data[0].v_int; - wfd_sink_debug("state changed [%s] : %s--->%s final : %s\n", + wfd_sink_debug("state changed [%s] : %s--->%s final : %s", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), gst_element_state_get_name((GstState)oldstate), gst_element_state_get_name((GstState)newstate), gst_element_state_get_name((GstState)pending)); if (oldstate == newstate) { - wfd_sink_error("pipeline reports state transition to old state\n"); + wfd_sink_debug("pipeline reports state transition to old state"); break; } @@ -649,14 +661,14 @@ _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) if (wfd_sink->clock) { if (wfd_sink->clock != clock) - wfd_sink_debug("clock is changed! [%s] -->[%s]\n", + wfd_sink_debug("clock is changed! [%s] -->[%s]", GST_STR_NULL(GST_OBJECT_NAME(wfd_sink->clock)), GST_STR_NULL(GST_OBJECT_NAME(clock))); else - wfd_sink_debug("same clock is selected again! [%s] \n", + wfd_sink_debug("same clock is selected again! [%s]", GST_STR_NULL(GST_OBJECT_NAME(clock))); } else { - wfd_sink_debug("new clock [%s] was selected in the pipeline\n", + wfd_sink_debug("new clock [%s] was selected in the pipeline", (GST_STR_NULL(GST_OBJECT_NAME(clock)))); } @@ -680,9 +692,9 @@ _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) structure_name = gst_structure_get_name(message_structure); if (structure_name) { - wfd_sink_debug("got element specific message[%s]\n", GST_STR_NULL(structure_name)); + wfd_sink_debug("got element specific message[%s]", GST_STR_NULL(structure_name)); if (g_strrstr(structure_name, "GstUDPSrcTimeout")) { - wfd_sink_error("Got %s, post error message\n", GST_STR_NULL(structure_name)); + wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name)); MMWFDSINK_POST_MESSAGE(wfd_sink, MM_ERROR_WFD_INTERNAL, MMWFDSINK_CURRENT_STATE(wfd_sink)); @@ -696,7 +708,7 @@ _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) gchar *category = NULL, *text = NULL; gst_message_parse_progress(msg, &type, &category, &text); - wfd_sink_debug("%s : %s \n", GST_STR_NULL(category), GST_STR_NULL(text)); + wfd_sink_debug("%s : %s ", GST_STR_NULL(category), GST_STR_NULL(text)); switch (type) { case GST_PROGRESS_TYPE_START: @@ -718,35 +730,35 @@ _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) break; case GST_PROGRESS_TYPE_ERROR: if (category && !strcmp(category, "open")) { - wfd_sink_error("got error : %s\n", GST_STR_NULL(text)); + wfd_sink_error("got error : %s", GST_STR_NULL(text)); /*_mm_wfd_sink_disconnect (wfd_sink); */ MMWFDSINK_POST_MESSAGE(wfd_sink, MM_ERROR_WFD_INTERNAL, MMWFDSINK_CURRENT_STATE(wfd_sink)); } else if (category && !strcmp(category, "play")) { - wfd_sink_error("got error : %s\n", GST_STR_NULL(text)); + wfd_sink_error("got error : %s", GST_STR_NULL(text)); /*_mm_wfd_sink_disconnect (wfd_sink); */ MMWFDSINK_POST_MESSAGE(wfd_sink, MM_ERROR_WFD_INTERNAL, MMWFDSINK_CURRENT_STATE(wfd_sink)); } else if (category && !strcmp(category, "pause")) { - wfd_sink_error("got error : %s\n", GST_STR_NULL(text)); + wfd_sink_error("got error : %s", GST_STR_NULL(text)); /*_mm_wfd_sink_disconnect (wfd_sink); */ MMWFDSINK_POST_MESSAGE(wfd_sink, MM_ERROR_WFD_INTERNAL, MMWFDSINK_CURRENT_STATE(wfd_sink)); } else if (category && !strcmp(category, "close")) { - wfd_sink_error("got error : %s\n", GST_STR_NULL(text)); + wfd_sink_error("got error : %s", GST_STR_NULL(text)); /*_mm_wfd_sink_disconnect (wfd_sink); */ MMWFDSINK_POST_MESSAGE(wfd_sink, MM_ERROR_WFD_INTERNAL, MMWFDSINK_CURRENT_STATE(wfd_sink)); } else { - wfd_sink_error("got error : %s\n", GST_STR_NULL(text)); + wfd_sink_error("got error : %s", GST_STR_NULL(text)); } break; default: - wfd_sink_error("progress message has no type\n"); + wfd_sink_error("progress message has no type"); return ret; } @@ -755,10 +767,10 @@ _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) } break; case GST_MESSAGE_ASYNC_START: - wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg))); + wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s", gst_element_get_name(GST_MESSAGE_SRC(msg))); break; case GST_MESSAGE_ASYNC_DONE: - wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg))); + wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s", gst_element_get_name(GST_MESSAGE_SRC(msg))); break; case GST_MESSAGE_UNKNOWN: case GST_MESSAGE_INFO: @@ -780,7 +792,7 @@ _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) case GST_MESSAGE_ANY: break; default: - wfd_sink_debug("unhandled message\n"); + wfd_sink_debug("unhandled message"); break; } @@ -806,14 +818,14 @@ __mm_wfd_sink_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket, if (need_prepare) gst_element_set_state(GST_ELEMENT(element->gst), GST_STATE_READY); - if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) { - wfd_sink_error("failed to add element [%s] to bin [%s]\n", + if (!gst_bin_add(GST_BIN(bin), GST_ELEMENT(element->gst))) { + wfd_sink_error("failed to add element [%s] to bin [%s]", GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))), GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin)))); return 0; } - wfd_sink_debug("add element [%s] to bin [%s]\n", + wfd_sink_debug("add element [%s] to bin [%s]", GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))), GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin)))); @@ -846,12 +858,12 @@ __mm_wfd_sink_gst_element_link_bucket(GList *element_bucket) if (element && element->gst) { if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) { - wfd_sink_debug("linking [%s] to [%s] success\n", + wfd_sink_debug("linking [%s] to [%s] success", GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))), GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)))); successful_link_count++; } else { - wfd_sink_error("linking [%s] to [%s] failed\n", + wfd_sink_error("linking [%s] to [%s] failed", GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))), GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)))); return -1; @@ -981,12 +993,12 @@ __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd) return MM_ERROR_NONE; no_operation: - wfd_sink_debug("already %s state, nothing to do.\n", MMWFDSINK_STATE_GET_NAME(cur_state)); + wfd_sink_debug("already %s state, nothing to do.", MMWFDSINK_STATE_GET_NAME(cur_state)); return MM_ERROR_WFD_NO_OP; /* ERRORS */ invalid_state: - wfd_sink_error("current state is invalid.\n", MMWFDSINK_STATE_GET_NAME(cur_state)); + wfd_sink_error("current state is invalid.", MMWFDSINK_STATE_GET_NAME(cur_state)); return MM_ERROR_WFD_INVALID_STATE; } @@ -997,7 +1009,7 @@ static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType s wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); if (MMWFDSINK_CURRENT_STATE(wfd_sink) == state) { - wfd_sink_error("already state(%s)\n", MMWFDSINK_STATE_GET_NAME(state)); + wfd_sink_error("already state(%s)", MMWFDSINK_STATE_GET_NAME(state)); MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE; return MM_ERROR_NONE; } @@ -1040,30 +1052,30 @@ __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboole wfd_sink_return_val_if_fail(state > GST_STATE_VOID_PENDING, MM_ERROR_WFD_INVALID_ARGUMENT); - wfd_sink_debug("try to set %s state \n", gst_element_state_get_name(state)); + wfd_sink_debug("try to set %s state ", gst_element_state_get_name(state)); result = gst_element_set_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, state); if (result == GST_STATE_CHANGE_FAILURE) { - wfd_sink_error("fail to set %s state....\n", gst_element_state_get_name(state)); + wfd_sink_error("fail to set %s state....", gst_element_state_get_name(state)); return MM_ERROR_WFD_INTERNAL; } if (!async) { - wfd_sink_debug("wait for changing state is completed \n"); + wfd_sink_debug("wait for changing state is completed "); result = gst_element_get_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND); if (result == GST_STATE_CHANGE_FAILURE) { - wfd_sink_error("fail to get state within %d seconds....\n", wfd_sink->ini.state_change_timeout); + wfd_sink_error("fail to get state within %d seconds....", wfd_sink->ini.state_change_timeout); __mm_wfd_sink_dump_pipeline_state(wfd_sink); return MM_ERROR_WFD_INTERNAL; } else if (result == GST_STATE_CHANGE_NO_PREROLL) { - wfd_sink_debug("successfully changed state but is not able to provide data yet\n"); + wfd_sink_debug("successfully changed state but is not able to provide data yet"); } - wfd_sink_debug("cur state is %s, pending state is %s\n", + wfd_sink_debug("cur state is %s, pending state is %s", gst_element_state_get_name(cur_state), gst_element_state_get_name(pending_state)); } @@ -1094,26 +1106,41 @@ _mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink) if (GST_CLOCK_TIME_IS_VALID(base_time)) { - wfd_sink_debug("set pipeline base_time as now [%"GST_TIME_FORMAT"]\n", GST_TIME_ARGS(base_time)); + wfd_sink_debug("set pipeline base_time as now [%"GST_TIME_FORMAT"]", GST_TIME_ARGS(base_time)); for (i = 0; i < WFD_SINK_M_NUM; i++) { if (wfd_sink->pipeline->mainbin[i].gst) gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[i].gst), base_time); } - if (wfd_sink->pipeline->videobin) { - for (i = 0; i < WFD_SINK_V_NUM; i++) { - if (wfd_sink->pipeline->videobin[i].gst) - gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->videobin[i].gst), base_time); + if (wfd_sink->pipeline->v_decodebin) { + for (i = 0; i < WFD_SINK_V_D_NUM; i++) { + if (wfd_sink->pipeline->v_decodebin[i].gst) + gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_decodebin[i].gst), base_time); + } + } + + if (wfd_sink->pipeline->v_sinkbin) { + for (i = 0; i < WFD_SINK_V_S_NUM; i++) { + if (wfd_sink->pipeline->v_sinkbin[i].gst) + gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_sinkbin[i].gst), base_time); + } + } + + if (wfd_sink->pipeline->a_decodebin) { + for (i = 0; i < WFD_SINK_A_D_NUM; i++) { + if (wfd_sink->pipeline->a_decodebin[i].gst) + gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_decodebin[i].gst), base_time); } } - if (wfd_sink->pipeline->audiobin) { - for (i = 0; i < WFD_SINK_A_NUM; i++) { - if (wfd_sink->pipeline->audiobin[i].gst) - gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->audiobin[i].gst), base_time); + if (wfd_sink->pipeline->a_sinkbin) { + for (i = 0; i < WFD_SINK_A_S_NUM; i++) { + if (wfd_sink->pipeline->a_sinkbin[i].gst) + gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_sinkbin[i].gst), base_time); } } + wfd_sink->need_to_reset_basetime = FALSE; } @@ -1123,37 +1150,66 @@ _mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink) } int -__mm_wfd_sink_prepare_videobin(mm_wfd_sink_t *wfd_sink) +__mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink) { - GstElement *videobin = NULL; + GstElement *bin = NULL; wfd_sink_debug_fenter(); wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline, + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, MM_ERROR_WFD_NOT_INITIALIZED); - if (wfd_sink->pipeline->videobin == NULL) { - if (MM_ERROR_NONE != __mm_wfd_sink_create_videobin(wfd_sink)) { - wfd_sink_error("failed to create videobin....\n"); + /* check video decodebin is linked */ + if (!wfd_sink->video_decodebin_is_linked) { + /* check video decodebin is created */ + if (wfd_sink->pipeline->v_decodebin == NULL) { + if (MM_ERROR_NONE != __mm_wfd_sink_create_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to create video decodebin...."); + goto ERROR; + } + } + + if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to link video decodebin....."); goto ERROR; } } - if (!wfd_sink->video_bin_is_linked) { - if (MM_ERROR_NONE != __mm_wfd_sink_link_videobin(wfd_sink)) { - wfd_sink_error("failed to link video decoder.....\n"); + /* check video sinkbin is created */ + if (wfd_sink->pipeline->v_sinkbin == NULL) { + if (MM_ERROR_NONE != __mm_wfd_sink_create_video_sinkbin(wfd_sink)) { + wfd_sink_error("failed to create video sinkbin...."); goto ERROR; } } - videobin = wfd_sink->pipeline->videobin[WFD_SINK_V_BIN].gst; + /* set video decodebin state as READY */ + if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) { + bin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst; + if (GST_STATE(bin) <= GST_STATE_NULL) { + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) { + wfd_sink_error("failed to set state(READY) to video decodebin"); + goto ERROR; + } + } + } else { + wfd_sink_warning("going on without video decodebin...."); + } - if (GST_STATE(videobin) <= GST_STATE_NULL) { - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(videobin, GST_STATE_READY)) { - wfd_sink_error("failed to set state(READY) to %s\n", GST_STR_NULL(GST_ELEMENT_NAME(videobin))); - goto ERROR; + /* set video sinkbin state as READY */ + if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) { + bin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst; + if (GST_STATE(bin) <= GST_STATE_NULL) { + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) { + wfd_sink_error("failed to set state(READY) to video sinkbin"); + goto ERROR; + } } + } else { + wfd_sink_warning("going on without video sinkbin...."); } wfd_sink_debug_fleave(); @@ -1171,9 +1227,9 @@ ERROR: } int -__mm_wfd_sink_prepare_audiobin(mm_wfd_sink_t *wfd_sink) +__mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink) { - MMWFDSinkGstElement *audiobin = NULL; + GstElement *bin = NULL; wfd_sink_debug_fenter(); @@ -1181,28 +1237,54 @@ __mm_wfd_sink_prepare_audiobin(mm_wfd_sink_t *wfd_sink) wfd_sink->pipeline, MM_ERROR_WFD_NOT_INITIALIZED); - if (wfd_sink->pipeline->audiobin == NULL) { - if (MM_ERROR_NONE != __mm_wfd_sink_create_audiobin(wfd_sink)) { - wfd_sink_error("failed to create audiobin....\n"); + /* check audio decodebin is linked */ + if (!wfd_sink->audio_decodebin_is_linked) { + /* check audio decodebin is created */ + if (wfd_sink->pipeline->a_decodebin == NULL) { + if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to create audio decodebin...."); + goto ERROR; + } + } + + if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to link audio decodebin....."); goto ERROR; } } - if (!wfd_sink->audio_bin_is_linked) { - if (MM_ERROR_NONE != __mm_wfd_sink_link_audiobin(wfd_sink)) { - wfd_sink_error("failed to link audio decoder.....\n"); + /* check audio sinkbin is created */ + if (wfd_sink->pipeline->a_sinkbin == NULL) { + if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_sinkbin(wfd_sink)) { + wfd_sink_error("failed to create audio sinkbin...."); goto ERROR; } } - audiobin = wfd_sink->pipeline->audiobin; + /* set audio decodebin state as READY */ + if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) { + bin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst; + if (GST_STATE(bin) <= GST_STATE_NULL) { + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) { + wfd_sink_error("failed to set state(READY) to audio decodebin"); + goto ERROR; + } + } + } else { + wfd_sink_warning("going on without audio decodebin...."); + } - if (GST_STATE(audiobin) <= GST_STATE_NULL) { - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(audiobin[WFD_SINK_A_BIN].gst, GST_STATE_READY)) { - wfd_sink_error("failed to set state(READY) to %s\n", - GST_STR_NULL(GST_ELEMENT_NAME(audiobin))); - goto ERROR; + /* set audio sinkbin state as READY */ + if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) { + bin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst; + if (GST_STATE(bin ) <= GST_STATE_NULL) { + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin , GST_STATE_READY)) { + wfd_sink_error("failed to set state(READY) to audio sinkbin"); + goto ERROR; + } } + } else { + wfd_sink_warning("going on without audio sinkbin...."); } wfd_sink_debug_fleave(); @@ -1243,7 +1325,7 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d GST_PAD_PROBE_DROP); if (!wfd_sink->clock) { - wfd_sink_warning("pipeline did not select clock, yet\n"); + wfd_sink_warning("pipeline did not select clock, yet"); return GST_PAD_PROBE_OK; } @@ -1253,9 +1335,9 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d /* calculate current runninig time */ current_time = gst_clock_get_time(wfd_sink->clock); if (g_strrstr(GST_OBJECT_NAME(pad), "video")) - base_time = gst_element_get_base_time(wfd_sink->pipeline->videobin[WFD_SINK_V_BIN].gst); + base_time = gst_element_get_base_time(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst); else if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) - base_time = gst_element_get_base_time(wfd_sink->pipeline->audiobin[WFD_SINK_A_BIN].gst); + base_time = gst_element_get_base_time(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst); start_time = gst_element_get_start_time(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); if (GST_CLOCK_TIME_IS_VALID(current_time) && GST_CLOCK_TIME_IS_VALID(start_time) && @@ -1263,7 +1345,7 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d running_time = current_time - (start_time + base_time); } else { wfd_sink_debug("current time %"GST_TIME_FORMAT", start time %"GST_TIME_FORMAT - " base time %"GST_TIME_FORMAT"\n", GST_TIME_ARGS(current_time), + " base time %"GST_TIME_FORMAT"", GST_TIME_ARGS(current_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time)); return GST_PAD_PROBE_OK; } @@ -1271,16 +1353,16 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d /* calculate this buffer rendering time */ buffer = gst_pad_probe_info_get_buffer(info); if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer)) { - wfd_sink_error("buffer timestamp is invalid.\n"); + wfd_sink_warning("buffer timestamp is invalid."); return GST_PAD_PROBE_OK; } if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) { - if (wfd_sink->pipeline && wfd_sink->pipeline->audiobin && wfd_sink->pipeline->audiobin[WFD_SINK_A_SINK].gst) - g_object_get(G_OBJECT(wfd_sink->pipeline->audiobin[WFD_SINK_A_SINK].gst), "ts-offset", &ts_offset, NULL); + if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst) + g_object_get(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", &ts_offset, NULL); } else if (g_strrstr(GST_OBJECT_NAME(pad), "video")) { - if (wfd_sink->pipeline && wfd_sink->pipeline->videobin && wfd_sink->pipeline->videobin[WFD_SINK_V_SINK].gst) - g_object_get(G_OBJECT(wfd_sink->pipeline->videobin[WFD_SINK_V_SINK].gst), "ts-offset", &ts_offset, NULL); + if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst) + g_object_get(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", &ts_offset, NULL); } render_time = GST_BUFFER_TIMESTAMP(buffer); @@ -1291,7 +1373,7 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d diff = GST_CLOCK_DIFF(running_time, render_time); if (diff < 0) { /* this buffer could be NOT rendered */ - wfd_sink_debug("%s : diff time : -%" GST_TIME_FORMAT "\n", + wfd_sink_debug("%s : diff time : -%" GST_TIME_FORMAT "", GST_STR_NULL((GST_OBJECT_NAME(pad))), GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time))); } else { @@ -1310,7 +1392,7 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d wfd_sink->audio_buffer_count++; wfd_sink->audio_accumulated_gap += diff; } else { - wfd_sink_warning("invalid buffer type.. \n"); + wfd_sink_warning("invalid buffer type.. "); return GST_PAD_PROBE_DROP; } @@ -1344,12 +1426,12 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d video_minus_compensation = FALSE; } } else { - wfd_sink_debug("first update video average gap(%lld) \n", video_avgrage_gap); + wfd_sink_debug("first update video average gap(%lld) ", video_avgrage_gap); wfd_sink->video_average_gap = video_avgrage_gap; } } else { wfd_sink_debug("there is no video buffer flow during %"GST_TIME_FORMAT - " ~ %" GST_TIME_FORMAT"\n", + " ~ %" GST_TIME_FORMAT"", GST_TIME_ARGS(wfd_sink->last_buffer_timestamp), GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); } @@ -1367,12 +1449,12 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d audio_minus_compensation = FALSE; } } else { - wfd_sink_debug("first update audio average gap(%lld) \n", audio_avgrage_gap); + wfd_sink_debug("first update audio average gap(%lld) ", audio_avgrage_gap); wfd_sink->audio_average_gap = audio_avgrage_gap; } } else { wfd_sink_debug("there is no audio buffer flow during %"GST_TIME_FORMAT - " ~ %" GST_TIME_FORMAT"\n", + " ~ %" GST_TIME_FORMAT"", GST_TIME_ARGS(wfd_sink->last_buffer_timestamp), GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); } @@ -1407,7 +1489,7 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d avgrage_gap_diff = audio_avgrage_gap_diff; } - wfd_sink_debug("average diff gap difference beween audio:%s%lld and video:%s%lld \n", + wfd_sink_debug("average diff gap difference beween audio:%s%lld and video:%s%lld ", audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff, video_minus_compensation ? "-" : "", video_avgrage_gap_diff); @@ -1420,16 +1502,16 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d ts_offset += avgrage_gap_diff; wfd_sink_debug("do timestamp compensation : %s%lld (ts-offset : %" - GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")\n", + GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")", minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time)); - if (wfd_sink->pipeline && wfd_sink->pipeline->audiobin && wfd_sink->pipeline->audiobin[WFD_SINK_A_SINK].gst) - g_object_set(G_OBJECT(wfd_sink->pipeline->audiobin[WFD_SINK_A_SINK].gst), "ts-offset", (gint64)ts_offset, NULL); - if (wfd_sink->pipeline && wfd_sink->pipeline->videobin && wfd_sink->pipeline->videobin[WFD_SINK_V_SINK].gst) - g_object_set(G_OBJECT(wfd_sink->pipeline->videobin[WFD_SINK_V_SINK].gst), "ts-offset", (gint64)ts_offset, NULL); + if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst) + g_object_set(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL); + if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst) + g_object_set(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL); } else { - wfd_sink_debug("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")\n", + wfd_sink_debug("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")", minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset)); } @@ -1441,7 +1523,7 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer); } } else { - wfd_sink_debug("first update last buffer timestamp :%" GST_TIME_FORMAT" \n", + wfd_sink_debug("first update last buffer timestamp :%" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer); } @@ -1455,15 +1537,24 @@ __mm_wfd_sink_demux_pad_added(GstElement *ele, GstPad *pad, gpointer data) { mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data; gchar *name = gst_pad_get_name(pad); + GstElement *pipeline = NULL; + GstElement *decodebin = NULL; GstElement *sinkbin = NULL; GstPad *sinkpad = NULL; + GstPad *srcpad = NULL; wfd_sink_debug_fenter(); - wfd_sink_return_if_fail(wfd_sink && wfd_sink->pipeline); + wfd_sink_return_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); + + pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst; + /* take decodebin/sinkbin */ if (name[0] == 'v') { - wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad...\n"); + wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad..."); MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL); @@ -1473,19 +1564,17 @@ __mm_wfd_sink_demux_pad_added(GstElement *ele, GstPad *pad, gpointer data) (gpointer)wfd_sink, NULL); - if (GST_STATE(wfd_sink->pipeline->videobin[WFD_SINK_V_BIN].gst) <= GST_STATE_NULL) { - wfd_sink_debug("need to prepare videobin"); - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videobin(wfd_sink)) { - wfd_sink_error("failed to prepare videobin....\n"); - goto ERROR; - } + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink)) { + wfd_sink_error("failed to prepare video pipeline...."); + goto ERROR; } - sinkbin = wfd_sink->pipeline->videobin[WFD_SINK_V_BIN].gst; - - wfd_sink->added_av_pad_num++; + if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) + decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst; + if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) + sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst; } else if (name[0] == 'a') { - wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad...\n"); + wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad..."); MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL); @@ -1495,65 +1584,110 @@ __mm_wfd_sink_demux_pad_added(GstElement *ele, GstPad *pad, gpointer data) (gpointer)wfd_sink, NULL); - if (GST_STATE(wfd_sink->pipeline->audiobin[WFD_SINK_A_BIN].gst) <= GST_STATE_NULL) { - wfd_sink_debug("need to prepare audiobin"); - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiobin(wfd_sink)) { - wfd_sink_error("failed to prepare audiobin....\n"); - goto ERROR; - } + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink)) { + wfd_sink_error("failed to prepare audio pipeline...."); + goto ERROR; } - sinkbin = wfd_sink->pipeline->audiobin[WFD_SINK_A_BIN].gst; - - wfd_sink->added_av_pad_num++; + if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) + decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst; + if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) + sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst; } else { - wfd_sink_error("not handling.....\n\n\n"); + wfd_sink_error("unexceptable pad is added!!!"); + return; } + srcpad = gst_object_ref(pad); - if (sinkbin) { - wfd_sink_debug("add %s to pipeline.\n", - GST_STR_NULL(GST_ELEMENT_NAME(sinkbin))); - - /* add */ - if (!gst_bin_add(GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst), sinkbin)) { - wfd_sink_error("failed to add sinkbin to pipeline\n"); + /* add decodebin and link */ + if (decodebin) { + if (!gst_bin_add(GST_BIN(pipeline), decodebin)) { + wfd_sink_error("failed to add %s to pipeline", + GST_STR_NULL(GST_ELEMENT_NAME(decodebin))); goto ERROR; } - wfd_sink_debug("link %s .\n", GST_STR_NULL(GST_ELEMENT_NAME(sinkbin))); - - /* link */ - sinkpad = gst_element_get_static_pad(GST_ELEMENT_CAST(sinkbin), "sink"); + sinkpad = gst_element_get_static_pad(decodebin, "sink"); if (!sinkpad) { - wfd_sink_error("failed to get pad from sinkbin\n"); + wfd_sink_error("failed to get sink pad from %s", + GST_STR_NULL(GST_ELEMENT_NAME(decodebin))); + goto ERROR; + } + + if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { + wfd_sink_error("failed to link %s and %s", + GST_STR_NULL(GST_PAD_NAME(srcpad)), + GST_STR_NULL(GST_PAD_NAME(sinkpad))); goto ERROR; } + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; - if (GST_PAD_LINK_OK != gst_pad_link_full(pad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) { - wfd_sink_error("failed to link sinkbin\n"); + srcpad = gst_element_get_static_pad (decodebin, "src"); + if (!srcpad) { + wfd_sink_error("failed to get src pad from %s", + GST_STR_NULL(GST_ELEMENT_NAME(decodebin))); goto ERROR; } + } else { + wfd_sink_warning("going on without decodebin..."); + } - wfd_sink_debug("sync state %s with pipeline .\n", - GST_STR_NULL(GST_ELEMENT_NAME(sinkbin))); + /* add sinkbin and link */ + if (sinkbin) { + if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) { + wfd_sink_error("failed to add %s to pipeline", + GST_STR_NULL(GST_ELEMENT_NAME(sinkbin))); + goto ERROR; + } - /* run */ - if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(sinkbin))) { - wfd_sink_error("failed to sync sinkbin state with parent \n"); + sinkpad = gst_element_get_static_pad(sinkbin, "sink"); + if (!sinkpad) { + wfd_sink_error("failed to get sink pad from %s", + GST_STR_NULL(GST_ELEMENT_NAME(sinkbin))); goto ERROR; } + if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { + wfd_sink_error("failed to link %s and %s", + GST_STR_NULL(GST_PAD_NAME(srcpad)), + GST_STR_NULL(GST_PAD_NAME(sinkpad))); + goto ERROR; + } + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; gst_object_unref(GST_OBJECT(sinkpad)); sinkpad = NULL; + } else { + wfd_sink_error("there is no sinkbin..."); + goto ERROR; } - if (wfd_sink->added_av_pad_num == 2) { - wfd_sink_debug("whole pipeline is constructed. \n"); + /* run */ + if (decodebin) { + if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(decodebin))) { + wfd_sink_error("failed to sync %s state with parent", + GST_STR_NULL(GST_PAD_NAME(decodebin))); + goto ERROR; + } + } + + if (sinkbin) { + if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(sinkbin))) { + wfd_sink_error("failed to sync %s state with parent", + GST_STR_NULL(GST_PAD_NAME(sinkbin))); + goto ERROR; + } + } - /* generate dot file of the constructed pipeline of wifi display sink */ - MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "constructed-pipeline"); + if (name[0] == 'v') { + MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "video-pad-added-pipeline"); + } else if (name[0] == 'a') { + MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "audio-pad-added-pipeline"); } MMWFDSINK_FREEIF(name); @@ -1566,6 +1700,10 @@ __mm_wfd_sink_demux_pad_added(GstElement *ele, GstPad *pad, gpointer data) ERROR: MMWFDSINK_FREEIF(name); + if (srcpad) + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + if (sinkpad) gst_object_unref(GST_OBJECT(sinkpad)); sinkpad = NULL; @@ -1605,10 +1743,11 @@ static void __mm_wfd_sink_update_stream_info(GstElement *wfdrtspsrc, GstStructure *str, gpointer data) { mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data; - WFDSinkManagerCMDType cmd = WFD_SINK_MANAGER_CMD_NONE; MMWFDSinkStreamInfo *stream_info = NULL; gint is_valid_audio_format = FALSE; gint is_valid_video_format = FALSE; + MMWFDSinkAudioCodec audio_codec = MM_WFD_SINK_AUDIO_CODEC_NONE; + MMWFDSinkVideoCodec video_codec = MM_WFD_SINK_VIDEO_CODEC_NONE; gchar *audio_format; gchar *video_format; @@ -1619,6 +1758,9 @@ __mm_wfd_sink_update_stream_info(GstElement *wfdrtspsrc, GstStructure *str, gpoi stream_info = &wfd_sink->stream_info; + audio_codec = wfd_sink->stream_info.audio_stream_info.codec; + video_codec = wfd_sink->stream_info.video_stream_info.codec; + if (gst_structure_has_field(str, "audio_format")) { is_valid_audio_format = TRUE; audio_format = g_strdup(gst_structure_get_string(str, "audio_format")); @@ -1629,7 +1771,7 @@ __mm_wfd_sink_update_stream_info(GstElement *wfdrtspsrc, GstStructure *str, gpoi else if (g_strrstr(audio_format, "LPCM")) stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_LPCM; else { - wfd_sink_error("invalid audio format(%s)...\n", audio_format); + wfd_sink_error("invalid audio format(%s)...", audio_format); is_valid_audio_format = FALSE; } @@ -1641,9 +1783,15 @@ __mm_wfd_sink_update_stream_info(GstElement *wfdrtspsrc, GstStructure *str, gpoi if (gst_structure_has_field(str, "audio_bitwidth")) gst_structure_get_int(str, "audio_bitwidth", &stream_info->audio_stream_info.bitwidth); - cmd = cmd | WFD_SINK_MANAGER_CMD_LINK_A_BIN; + if (audio_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) { + if (audio_codec != stream_info->audio_stream_info.codec) { + wfd_sink_debug("audio codec is changed...need to change audio decodebin"); + } + } else { + WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE); + } - wfd_sink_debug("audio_format : %s \n \t rate : %d \n \t channels : %d \n \t bitwidth : %d \n \t \n", + wfd_sink_debug("audio_format : %s \n \t rate : %d \n \t channels : %d \n \t bitwidth : %d \n \t", audio_format, stream_info->audio_stream_info.sample_rate, stream_info->audio_stream_info.channels, @@ -1655,7 +1803,7 @@ __mm_wfd_sink_update_stream_info(GstElement *wfdrtspsrc, GstStructure *str, gpoi is_valid_video_format = TRUE; video_format = g_strdup(gst_structure_get_string(str, "video_format")); if (!g_strrstr(video_format, "H264")) { - wfd_sink_error("invalid video format(%s)...\n", video_format); + wfd_sink_error("invalid video format(%s)...", video_format); is_valid_video_format = FALSE; } @@ -1669,9 +1817,15 @@ __mm_wfd_sink_update_stream_info(GstElement *wfdrtspsrc, GstStructure *str, gpoi if (gst_structure_has_field(str, "video_framerate")) gst_structure_get_int(str, "video_framerate", &stream_info->video_stream_info.frame_rate); - cmd = cmd | WFD_SINK_MANAGER_CMD_LINK_V_BIN; + if (video_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) { + if (video_codec != stream_info->video_stream_info.codec) { + wfd_sink_debug("video codec is changed...need to change video decodebin"); + } + } else { + WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE); + } - wfd_sink_debug("video_format : %s \n \t width : %d \n \t height : %d \n \t frame_rate : %d \n \t \n", + wfd_sink_debug("video_format : %s \n \t width : %d \n \t height : %d \n \t frame_rate : %d \n \t", video_format, stream_info->video_stream_info.width, stream_info->video_stream_info.height, @@ -1679,11 +1833,7 @@ __mm_wfd_sink_update_stream_info(GstElement *wfdrtspsrc, GstStructure *str, gpoi } } - if (cmd != WFD_SINK_MANAGER_CMD_NONE) { - WFD_SINK_MANAGER_LOCK(wfd_sink); - WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink, cmd); - WFD_SINK_MANAGER_UNLOCK(wfd_sink); - } + WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); wfd_sink_debug_fleave(); } @@ -1693,7 +1843,6 @@ static int __mm_wfd_sink_prepare_wfdrtspsrc(mm_wfd_sink_t *wfd_sink, GstElement GstStructure *audio_param = NULL; GstStructure *video_param = NULL; GstStructure *hdcp_param = NULL; - void *hdcp_handle = NULL; gint hdcp_version = 0; gint hdcp_port = 0; guint CEA_resolution = 0; @@ -1709,8 +1858,8 @@ static int __mm_wfd_sink_prepare_wfdrtspsrc(mm_wfd_sink_t *wfd_sink, GstElement g_object_set(G_OBJECT(wfdrtspsrc), "debug", wfd_sink->ini.set_debug_property, NULL); g_object_set(G_OBJECT(wfdrtspsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL); g_object_set(G_OBJECT(wfdrtspsrc), "do-request", wfd_sink->ini.enable_retransmission, NULL); - g_object_set(G_OBJECT(wfdrtspsrc), "udp-buffer-size", 2097152, NULL); g_object_set(G_OBJECT(wfdrtspsrc), "enable-pad-probe", wfd_sink->ini.enable_wfdrtspsrc_pad_probe, NULL); + g_object_set(G_OBJECT(wfdrtspsrc), "udp-buffer-size", 2097152, NULL); audio_param = gst_structure_new("audio_param", "audio_codec", G_TYPE_UINT, wfd_sink->ini.audio_codec, @@ -1744,10 +1893,9 @@ static int __mm_wfd_sink_prepare_wfdrtspsrc(mm_wfd_sink_t *wfd_sink, GstElement "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.video_framerate_control_support, NULL); - mm_attrs_get_data_by_name(wfd_sink->attrs, "hdcp_handle", &hdcp_handle); mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version); mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port); - wfd_sink_debug("set hdcp version %d with %d port\n", hdcp_version, hdcp_port); + wfd_sink_debug("set hdcp version %d with %d port", hdcp_version, hdcp_port); hdcp_param = gst_structure_new("hdcp_param", "hdcp_version", G_TYPE_INT, hdcp_version, @@ -1784,6 +1932,41 @@ static int __mm_wfd_sink_prepare_demux(mm_wfd_sink_t *wfd_sink, GstElement *demu return MM_ERROR_NONE; } +static void +__mm_wfd_sink_queue_overrun(GstElement *element, gpointer u_data) +{ + wfd_sink_debug_fenter(); + + return_if_fail(element); + + wfd_sink_warning("%s is overrun", + GST_STR_NULL(GST_ELEMENT_NAME(element))); + + wfd_sink_debug_fleave(); + + return; +} + +static void __mm_wfd_sink_prepare_queue(mm_wfd_sink_t *wfd_sink, GstElement *queue) +{ + wfd_sink_debug_fenter(); + + wfd_sink_return_if_fail(wfd_sink); + wfd_sink_return_if_fail(queue); + + /* set maximum buffer size of queue as 3sec */ + g_object_set(G_OBJECT(queue), "max-size-bytes", 0, NULL); + g_object_set(G_OBJECT(queue), "max-size-buffers", 0, NULL); + g_object_set(G_OBJECT(queue), "max-size-time", (guint64)3000000000ULL, NULL); + g_signal_connect(queue, "overrun", + G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink); + + wfd_sink_debug_fleave(); + + return; +} + + static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink) { MMWFDSinkGstElement *mainbin = NULL; @@ -1814,7 +1997,7 @@ static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink) mainbin[WFD_SINK_M_PIPE].id = WFD_SINK_M_PIPE; mainbin[WFD_SINK_M_PIPE].gst = gst_pipeline_new("wfdsink"); if (!mainbin[WFD_SINK_M_PIPE].gst) { - wfd_sink_error("failed to create pipeline\n"); + wfd_sink_error("failed to create pipeline"); goto CREATE_ERROR; } @@ -1823,7 +2006,7 @@ static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink) MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_SRC].gst, "src"); if (mainbin[WFD_SINK_M_SRC].gst) { if (MM_ERROR_NONE != __mm_wfd_sink_prepare_wfdrtspsrc(wfd_sink, mainbin[WFD_SINK_M_SRC].gst)) { - wfd_sink_error("failed to prepare wfdrtspsrc...\n"); + wfd_sink_error("failed to prepare wfdrtspsrc..."); goto CREATE_ERROR; } } @@ -1840,27 +2023,27 @@ static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink) MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEMUX].gst, "sink"); if (mainbin[WFD_SINK_M_DEMUX].gst) { if (MM_ERROR_NONE != __mm_wfd_sink_prepare_demux(wfd_sink, mainbin[WFD_SINK_M_DEMUX].gst)) { - wfd_sink_error("failed to prepare demux...\n"); + wfd_sink_error("failed to prepare demux..."); goto CREATE_ERROR; } } /* adding created elements to pipeline */ if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(mainbin[WFD_SINK_M_PIPE].gst), element_bucket, FALSE)) { - wfd_sink_error("failed to add elements\n"); + wfd_sink_error("failed to add elements"); goto CREATE_ERROR; } /* linking elements in the bucket by added order. */ if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { - wfd_sink_error("failed to link elements\n"); + wfd_sink_error("failed to link elements"); goto CREATE_ERROR; } /* connect bus callback */ bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst)); if (!bus) { - wfd_sink_error("cannot get bus from pipeline.\n"); + wfd_sink_error("cannot get bus from pipeline."); goto CREATE_ERROR; } @@ -1882,7 +2065,7 @@ static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink) /* ERRORS */ CREATE_ERROR: - wfd_sink_error("ERROR : releasing pipeline\n"); + wfd_sink_error("ERROR : releasing pipeline"); if (element_bucket) g_list_free(element_bucket); @@ -1908,7 +2091,7 @@ CREATE_ERROR: } } - /* release audiobin with it's childs */ + /* release mainbin with it's childs */ if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst) gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst)); @@ -1919,133 +2102,158 @@ CREATE_ERROR: return MM_ERROR_WFD_INTERNAL; } -int __mm_wfd_sink_link_audiobin(mm_wfd_sink_t *wfd_sink) +int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink) { - MMWFDSinkGstElement *audiobin = NULL; + MMWFDSinkGstElement *a_decodebin = NULL; MMWFDSinkGstElement *first_element = NULL; MMWFDSinkGstElement *last_element = NULL; - gint audio_codec = MM_WFD_SINK_AUDIO_CODEC_NONE; GList *element_bucket = NULL; GstPad *sinkpad = NULL; GstPad *srcpad = NULL; + GstPad *ghostpad = NULL; wfd_sink_debug_fenter(); wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->pipeline && - wfd_sink->pipeline->audiobin && - wfd_sink->pipeline->audiobin[WFD_SINK_A_BIN].gst, + wfd_sink->pipeline->a_decodebin && + wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(wfd_sink->prev_audio_dec_src_pad && - wfd_sink->next_audio_dec_sink_pad, - MM_ERROR_WFD_INTERNAL); - if (wfd_sink->audio_bin_is_linked) { - wfd_sink_debug("audiobin is already linked... nothing to do\n"); + if (wfd_sink->audio_decodebin_is_linked) { + wfd_sink_debug("audio decodebin is already linked... nothing to do"); return MM_ERROR_NONE; } - /* take audiobin */ - audiobin = wfd_sink->pipeline->audiobin; + /* take audio decodebin */ + a_decodebin = wfd_sink->pipeline->a_decodebin; + + /* check audio queue */ + if (a_decodebin[WFD_SINK_A_D_QUEUE].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_QUEUE]); + + /* check audio hdcp */ + if (a_decodebin[WFD_SINK_A_D_HDCP].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_HDCP]); /* check audio codec */ - audio_codec = wfd_sink->stream_info.audio_stream_info.codec; - switch (audio_codec) { + switch (wfd_sink->stream_info.audio_stream_info.codec) { case MM_WFD_SINK_AUDIO_CODEC_LPCM: - if (audiobin[WFD_SINK_A_LPCM_CONVERTER].gst) - element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_LPCM_CONVERTER]); - if (audiobin[WFD_SINK_A_LPCM_FILTER].gst) - element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_LPCM_FILTER]); + if (a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER]); + if (a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst) { + GstCaps *caps = NULL; + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_FILTER]); + caps = gst_caps_new_simple("audio/x-raw", + "rate", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.sample_rate, + "channels", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.channels, + "format", G_TYPE_STRING, "S16BE", NULL); + + g_object_set(G_OBJECT(a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst), "caps", caps, NULL); + gst_object_unref(GST_OBJECT(caps)); + } break; case MM_WFD_SINK_AUDIO_CODEC_AAC: - if (audiobin[WFD_SINK_A_AAC_PARSE].gst) - element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_AAC_PARSE]); - if (audiobin[WFD_SINK_A_AAC_DEC].gst) - element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_AAC_DEC]); + if (a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_PARSE]); + if (a_decodebin[WFD_SINK_A_D_AAC_DEC].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_DEC]); break; case MM_WFD_SINK_AUDIO_CODEC_AC3: - if (audiobin[WFD_SINK_A_AC3_PARSE].gst) - element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_AC3_PARSE]); - if (audiobin[WFD_SINK_A_AC3_DEC].gst) - element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_AC3_DEC]); + if (a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_PARSE]); + if (a_decodebin[WFD_SINK_A_D_AC3_DEC].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_DEC]); break; default: - wfd_sink_error("audio type is not decied yet. cannot link audio decoder...\n"); + wfd_sink_error("audio codec is not decied yet. cannot link audio decodebin..."); return MM_ERROR_WFD_INTERNAL; break; } - if (!element_bucket) { - wfd_sink_debug("there is no additional elements to be linked... just link audiobin.\n"); - if (GST_PAD_LINK_OK != gst_pad_link_full(wfd_sink->prev_audio_dec_src_pad, wfd_sink->next_audio_dec_sink_pad, GST_PAD_LINK_CHECK_NOTHING)) { - wfd_sink_error("failed to link audiobin....\n"); + if (element_bucket == NULL) { + wfd_sink_error("there are no elements to be linked in the audio decodebin, destroy it"); + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to destroy audio decodebin"); goto fail_to_link; } goto done; } - /* adding elements to audiobin */ - if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(audiobin[WFD_SINK_A_BIN].gst), element_bucket, FALSE)) { - wfd_sink_error("failed to add elements to audiobin\n"); + /* adding elements to audio decodebin */ + if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_decodebin[WFD_SINK_A_D_BIN].gst), element_bucket, FALSE)) { + wfd_sink_error("failed to add elements to audio decodebin"); goto fail_to_link; } /* linking elements in the bucket by added order. */ if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { - wfd_sink_error("failed to link elements\n"); + wfd_sink_error("failed to link elements of the audio decodebin"); goto fail_to_link; } - /* get src pad */ - first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0); + /* get first element's sinkpad for creating ghostpad */ + first_element = (MMWFDSinkGstElement *)g_list_first(element_bucket)->data; if (!first_element) { - wfd_sink_error("failed to get first element to be linked....\n"); + wfd_sink_error("failed to get first element of the audio decodebin"); goto fail_to_link; } sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); if (!sinkpad) { - wfd_sink_error("failed to get sink pad from element(%s)\n", GST_ELEMENT_NAME(first_element->gst)); + wfd_sink_error("failed to get sink pad from element(%s)", + GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); goto fail_to_link; } - if (GST_PAD_LINK_OK != gst_pad_link_full(wfd_sink->prev_audio_dec_src_pad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) { - wfd_sink_error("failed to link audiobin....\n"); + ghostpad = gst_ghost_pad_new("sink", sinkpad); + if (!ghostpad) { + wfd_sink_error("failed to create ghostpad of audio decodebin"); goto fail_to_link; } + if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to audio decodebin"); + goto fail_to_link; + } gst_object_unref(GST_OBJECT(sinkpad)); sinkpad = NULL; - /* get sink pad */ - last_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, g_list_length(element_bucket) - 1); + /* get last element's src for creating ghostpad */ + last_element = (MMWFDSinkGstElement *)g_list_last(element_bucket)->data; if (!last_element) { - wfd_sink_error("failed to get last element to be linked....\n"); + wfd_sink_error("failed to get last element of the audio decodebin"); goto fail_to_link; } srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src"); if (!srcpad) { - wfd_sink_error("failed to get src pad from element(%s)\n", GST_ELEMENT_NAME(last_element->gst)); + wfd_sink_error("failed to get src pad from element(%s)", + GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst))); goto fail_to_link; } - if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, wfd_sink->next_audio_dec_sink_pad, GST_PAD_LINK_CHECK_NOTHING)) { - wfd_sink_error("failed to link audiobin....\n"); + ghostpad = gst_ghost_pad_new("src", srcpad); + if (!ghostpad) { + wfd_sink_error("failed to create ghostpad of audio decodebin"); goto fail_to_link; } + if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to audio decodebin"); + goto fail_to_link; + } gst_object_unref(GST_OBJECT(srcpad)); srcpad = NULL; g_list_free(element_bucket); done: - wfd_sink->audio_bin_is_linked = TRUE; + wfd_sink->audio_decodebin_is_linked = TRUE; wfd_sink_debug_fleave(); @@ -2085,25 +2293,10 @@ static int __mm_wfd_sink_prepare_audiosink(mm_wfd_sink_t *wfd_sink, GstElement * return MM_ERROR_NONE; } -static void -__mm_wfd_sink_queue_overrun(GstElement *element, gpointer u_data) -{ - debug_fenter(); - - return_if_fail(element); - - wfd_sink_warning("%s is overrun\n", - GST_STR_NULL(GST_ELEMENT_NAME(element))); - - debug_fleave(); - - return; -} - -static int __mm_wfd_sink_destroy_audiobin(mm_wfd_sink_t *wfd_sink) +static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - MMWFDSinkGstElement *audiobin = NULL; + MMWFDSinkGstElement *a_decodebin = NULL; GstObject *parent = NULL; int i; @@ -2113,305 +2306,388 @@ static int __mm_wfd_sink_destroy_audiobin(mm_wfd_sink_t *wfd_sink) MM_ERROR_WFD_NOT_INITIALIZED); if (wfd_sink->pipeline && - wfd_sink->pipeline->audiobin && - wfd_sink->pipeline->audiobin[WFD_SINK_A_BIN].gst) { - audiobin = wfd_sink->pipeline->audiobin; + wfd_sink->pipeline->a_decodebin&& + wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) { + a_decodebin = wfd_sink->pipeline->a_decodebin; } else { - wfd_sink_debug("audiobin is not created, nothing to destroy\n"); + wfd_sink_debug("audio decodebin is not created, nothing to destroy"); return MM_ERROR_NONE; } - - parent = gst_element_get_parent(audiobin[WFD_SINK_A_BIN].gst); + parent = gst_element_get_parent(a_decodebin[WFD_SINK_A_D_BIN].gst); if (!parent) { - wfd_sink_debug("audiobin has no parent.. need to relase by itself\n"); + wfd_sink_debug("audio decodebin has no parent.. need to relase by itself"); - if (GST_STATE(audiobin[WFD_SINK_A_BIN].gst) >= GST_STATE_READY) { - wfd_sink_debug("try to change state of audiobin to NULL\n"); - ret = gst_element_set_state(audiobin[WFD_SINK_A_BIN].gst, GST_STATE_NULL); + if (GST_STATE(a_decodebin[WFD_SINK_A_D_BIN].gst) >= GST_STATE_READY) { + wfd_sink_debug("try to change state of audio decodebin to NULL"); + ret = gst_element_set_state(a_decodebin[WFD_SINK_A_D_BIN].gst, GST_STATE_NULL); if (ret != GST_STATE_CHANGE_SUCCESS) { - wfd_sink_error("failed to change state of audiobin to NULL\n"); + wfd_sink_error("failed to change state of audio decodebin to NULL"); return MM_ERROR_WFD_INTERNAL; } } /* release element which are not added to bin */ - for (i = 1; i < WFD_SINK_A_NUM; i++) { /* NOTE : skip bin */ - if (audiobin[i].gst) { - parent = gst_element_get_parent(audiobin[i].gst); + for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */ + if (a_decodebin[i].gst) { + parent = gst_element_get_parent(a_decodebin[i].gst); if (!parent) { - wfd_sink_debug("unref %s(current ref %d)\n", - GST_STR_NULL(GST_ELEMENT_NAME(audiobin[i].gst)), - ((GObject *) audiobin[i].gst)->ref_count); - gst_object_unref(GST_OBJECT(audiobin[i].gst)); - audiobin[i].gst = NULL; + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)), + ((GObject *) a_decodebin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(a_decodebin[i].gst)); + a_decodebin[i].gst = NULL; } else { - wfd_sink_debug("unref %s(current ref %d)\n", - GST_STR_NULL(GST_ELEMENT_NAME(audiobin[i].gst)), - ((GObject *) audiobin[i].gst)->ref_count); + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)), + ((GObject *) a_decodebin[i].gst)->ref_count); gst_object_unref(GST_OBJECT(parent)); } } } - /* release audiobin with it's childs */ - if (audiobin[WFD_SINK_A_BIN].gst) - gst_object_unref(GST_OBJECT(audiobin[WFD_SINK_A_BIN].gst)); + /* release audio decodebin with it's childs */ + if (a_decodebin[WFD_SINK_A_D_BIN].gst) + gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst)); } else { - wfd_sink_debug("audiobin has parent(%s), unref it \n", + wfd_sink_debug("audio decodebin has parent(%s), unref it ", GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); gst_object_unref(GST_OBJECT(parent)); } + wfd_sink->audio_decodebin_is_linked = FALSE; + + MMWFDSINK_FREEIF(wfd_sink->pipeline->a_decodebin); + wfd_sink_debug_fleave(); return MM_ERROR_NONE; } -static int __mm_wfd_sink_create_audiobin(mm_wfd_sink_t *wfd_sink) +static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink) { - MMWFDSinkGstElement *audiobin = NULL; - gint audio_codec = MM_WFD_SINK_AUDIO_CODEC_NONE; - gboolean link_audio_dec = TRUE; + MMWFDSinkGstElement *a_decodebin = NULL; + gint audio_codec = WFD_AUDIO_UNKNOWN; GList *element_bucket = NULL; - GstPad *pad = NULL; - GstPad *ghostpad = NULL; - GstCaps *caps = NULL; + gboolean link = TRUE; + gint i=0; wfd_sink_debug_fenter(); wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin, + wfd_sink->pipeline, MM_ERROR_WFD_NOT_INITIALIZED); - /* alloc handles */ - audiobin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_NUM); - if (!audiobin) { - wfd_sink_error("failed to allocate memory for audiobin\n"); - return MM_ERROR_WFD_NO_FREE_SPACE; - } - - /* create audiobin */ - audiobin[WFD_SINK_A_BIN].id = WFD_SINK_A_BIN; - audiobin[WFD_SINK_A_BIN].gst = gst_bin_new("audiobin"); - if (!audiobin[WFD_SINK_A_BIN].gst) { - wfd_sink_error("failed to create audiobin\n"); - goto CREATE_ERROR; - } - - /* check audio decoder could be linked or not */ + /* check audio decodebin could be linked now */ switch (wfd_sink->stream_info.audio_stream_info.codec) { case MM_WFD_SINK_AUDIO_CODEC_AAC: audio_codec = WFD_AUDIO_AAC; + link = TRUE; break; case MM_WFD_SINK_AUDIO_CODEC_AC3: audio_codec = WFD_AUDIO_AC3; + link = TRUE; break; case MM_WFD_SINK_AUDIO_CODEC_LPCM: audio_codec = WFD_AUDIO_LPCM; + link = TRUE; break; case MM_WFD_SINK_AUDIO_CODEC_NONE: default: - wfd_sink_debug("audio decoder could NOT be linked now, just prepare.\n"); + wfd_sink_debug("audio decodebin could NOT be linked now, just create"); audio_codec = wfd_sink->ini.audio_codec; - link_audio_dec = FALSE; + link = FALSE; break; } - /* set need to link audio decoder flag*/ - wfd_sink->audio_bin_is_linked = link_audio_dec; - - /* queue - drm - parse - dec/capsfilter - audioconvert- volume - sink */ - /* create queue */ - MMWFDSINK_CREATE_ELEMENT(audiobin, WFD_SINK_A_QUEUE, "queue", "audio_queue", link_audio_dec); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_QUEUE].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_QUEUE].gst, "src"); - if (audiobin[WFD_SINK_A_QUEUE].gst) { - g_object_set(G_OBJECT(audiobin[WFD_SINK_A_QUEUE].gst), "max-size-bytes", 0, NULL); - g_object_set(G_OBJECT(audiobin[WFD_SINK_A_QUEUE].gst), "max-size-buffers", 0, NULL); - g_object_set(G_OBJECT(audiobin[WFD_SINK_A_QUEUE].gst), "max-size-time", (guint64)3000000000ULL, NULL); - g_signal_connect(audiobin[WFD_SINK_A_QUEUE].gst, "overrun", - G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink); - } - if (!link_audio_dec) { - if (!gst_bin_add(GST_BIN_CAST(audiobin[WFD_SINK_A_BIN].gst), audiobin[WFD_SINK_A_QUEUE].gst)) { - wfd_sink_error("failed to add %s to audiobin\n", - GST_STR_NULL(GST_ELEMENT_NAME(audiobin[WFD_SINK_A_QUEUE].gst))); - goto CREATE_ERROR; - } - - if (audiobin[WFD_SINK_A_HDCP].gst) { - if (!gst_bin_add(GST_BIN_CAST(audiobin[WFD_SINK_A_BIN].gst), audiobin[WFD_SINK_A_HDCP].gst)) { - wfd_sink_error("failed to add %s to audiobin\n", - GST_STR_NULL(GST_ELEMENT_NAME(audiobin[WFD_SINK_A_HDCP].gst))); - goto CREATE_ERROR; - } + /* alloc handles */ + a_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM); + if (!a_decodebin) { + wfd_sink_error("failed to allocate memory for audio decodebin"); + return MM_ERROR_WFD_NO_FREE_SPACE; + } - if (!gst_element_link(audiobin[WFD_SINK_A_QUEUE].gst, audiobin[WFD_SINK_A_HDCP].gst)) { - wfd_sink_error("failed to link [%s] to [%s] success\n", - GST_STR_NULL(GST_ELEMENT_NAME(audiobin[WFD_SINK_A_QUEUE].gst)), - GST_STR_NULL(GST_ELEMENT_NAME(audiobin[WFD_SINK_A_HDCP].gst))); - goto CREATE_ERROR; - } + memset(a_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM); - wfd_sink->prev_audio_dec_src_pad = gst_element_get_static_pad(audiobin[WFD_SINK_A_HDCP].gst, "src"); - } else { - wfd_sink->prev_audio_dec_src_pad = gst_element_get_static_pad(audiobin[WFD_SINK_A_QUEUE].gst, "src"); - } + /* create audio decodebin */ + a_decodebin[WFD_SINK_A_D_BIN].id = WFD_SINK_A_D_BIN; + a_decodebin[WFD_SINK_A_D_BIN].gst = gst_bin_new("audio_deocebin"); + if (!a_decodebin[WFD_SINK_A_D_BIN].gst) { + wfd_sink_error("failed to create audio decodebin"); + goto CREATE_ERROR; + } - if (!wfd_sink->prev_audio_dec_src_pad) { - wfd_sink_error("failed to get src pad from previous element of audio decoder\n"); - goto CREATE_ERROR; - } + /* create queue */ + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_QUEUE, "queue", "audio_queue", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst, "sink"); + if (a_decodebin[WFD_SINK_A_D_QUEUE].gst) + __mm_wfd_sink_prepare_queue( wfd_sink, a_decodebin[WFD_SINK_A_D_QUEUE].gst); - wfd_sink_debug("take src pad from previous element of audio decoder for linking\n"); - } + /* create hdcp */ + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_HDCP, wfd_sink->ini.name_of_audio_hdcp, "audio_hdcp", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst, "sink"); + /* create codec */ + audio_codec = wfd_sink->ini.audio_codec; if (audio_codec & WFD_AUDIO_LPCM) { /* create LPCM converter */ - MMWFDSINK_CREATE_ELEMENT(audiobin, WFD_SINK_A_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", link_audio_dec); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_LPCM_CONVERTER].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_LPCM_CONVERTER].gst, "src"); + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "src"); /* create LPCM filter */ - MMWFDSINK_CREATE_ELEMENT(audiobin, WFD_SINK_A_LPCM_FILTER, wfd_sink->ini.name_of_lpcm_filter, "audio_lpcm_filter", link_audio_dec); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_LPCM_FILTER].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_LPCM_FILTER].gst, "src"); - if (audiobin[WFD_SINK_A_LPCM_FILTER].gst) { - caps = gst_caps_new_simple("audio/x-raw", - "rate", G_TYPE_INT, 48000, - "channels", G_TYPE_INT, 2, - "format", G_TYPE_STRING, "S16BE", NULL); - - g_object_set(G_OBJECT(audiobin[WFD_SINK_A_LPCM_FILTER].gst), "caps", caps, NULL); - gst_object_unref(GST_OBJECT(caps)); - } + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_FILTER, wfd_sink->ini.name_of_lpcm_filter, "audio_lpcm_filter", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "src"); } if (audio_codec & WFD_AUDIO_AAC) { /* create AAC parse */ - MMWFDSINK_CREATE_ELEMENT(audiobin, WFD_SINK_A_AAC_PARSE, wfd_sink->ini.name_of_aac_parser, "audio_aac_parser", link_audio_dec); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_AAC_PARSE].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_AAC_PARSE].gst, "src"); + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_PARSE, wfd_sink->ini.name_of_aac_parser, "audio_aac_parser", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "src"); /* create AAC decoder */ - MMWFDSINK_CREATE_ELEMENT(audiobin, WFD_SINK_A_AAC_DEC, wfd_sink->ini.name_of_aac_decoder, "audio_aac_dec", link_audio_dec); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_AAC_DEC].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_AAC_DEC].gst, "src"); + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_DEC, wfd_sink->ini.name_of_aac_decoder, "audio_aac_dec", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "src"); } if (audio_codec & WFD_AUDIO_AC3) { /* create AC3 parser */ - MMWFDSINK_CREATE_ELEMENT(audiobin, WFD_SINK_A_AC3_PARSE, wfd_sink->ini.name_of_ac3_parser, "audio_ac3_parser", link_audio_dec); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_AC3_PARSE].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_AC3_PARSE].gst, "src"); + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_PARSE, wfd_sink->ini.name_of_ac3_parser, "audio_ac3_parser", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "src"); /* create AC3 decoder */ - MMWFDSINK_CREATE_ELEMENT(audiobin, WFD_SINK_A_AC3_DEC, wfd_sink->ini.name_of_ac3_decoder, "audio_ac3_dec", link_audio_dec); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_AC3_DEC].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_AC3_DEC].gst, "src"); + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_DEC, wfd_sink->ini.name_of_ac3_decoder, "audio_ac3_dec", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "src"); } - /* create resampler */ - MMWFDSINK_CREATE_ELEMENT(audiobin, WFD_SINK_A_RESAMPLER, wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_RESAMPLER].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_RESAMPLER].gst, "src"); - - /* create volume */ - MMWFDSINK_CREATE_ELEMENT(audiobin, WFD_SINK_A_VOLUME, wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_VOLUME].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_VOLUME].gst, "src"); + g_list_free(element_bucket); - /*TODO gstreamer-1.0 alsasink does not want process not S16LE format. */ - MMWFDSINK_CREATE_ELEMENT(audiobin, WFD_SINK_A_CAPSFILTER, "capsfilter", "audio_capsfilter", TRUE); - if (audiobin[WFD_SINK_A_CAPSFILTER].gst) { - caps = gst_caps_from_string("audio/x-raw, format=(string)S16LE"); - g_object_set(G_OBJECT(audiobin[WFD_SINK_A_CAPSFILTER].gst), "caps", caps, NULL); - gst_caps_unref(caps); - } + /* take it */ + wfd_sink->pipeline->a_decodebin= a_decodebin; - /* create sink */ - MMWFDSINK_CREATE_ELEMENT(audiobin, WFD_SINK_A_SINK, wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, audiobin[WFD_SINK_A_SINK].gst, "sink"); - if (audiobin[WFD_SINK_A_SINK].gst) { - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, audiobin[WFD_SINK_A_SINK].gst)) { - wfd_sink_error("failed to set audio sink property....\n"); - goto CREATE_ERROR; + /* link audio decodebin if audio codec is fixed */ + if (link) { + if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to link audio decodebin, destroy audio decodebin"); + __mm_wfd_sink_destroy_audio_decodebin(wfd_sink); + return MM_ERROR_WFD_INTERNAL; } } - if (!link_audio_dec) { - MMWFDSinkGstElement *first_element = NULL; - - first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0); - if (!first_element) { - wfd_sink_error("failed to get first element\n"); - goto CREATE_ERROR; - } - - wfd_sink->next_audio_dec_sink_pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); - if (!wfd_sink->next_audio_dec_sink_pad) { - wfd_sink_error("failed to get sink pad from next element of audio decoder\n"); - goto CREATE_ERROR; - } + wfd_sink_debug_fleave(); - wfd_sink_debug("take sink pad from next element of audio decoder for linking\n"); - } + return MM_ERROR_NONE; - /* adding created elements to audiobin */ - if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(audiobin[WFD_SINK_A_BIN].gst), element_bucket, FALSE)) { - wfd_sink_error("failed to add elements\n"); - goto CREATE_ERROR; - } +CREATE_ERROR: + wfd_sink_error("failed to create audio decodebin, release all"); - /* linking elements in the bucket by added order. */ - if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { - wfd_sink_error("failed to link elements\n"); - goto CREATE_ERROR; - } + g_list_free(element_bucket); - /* get queue's sinkpad for creating ghostpad */ - pad = gst_element_get_static_pad(audiobin[WFD_SINK_A_QUEUE].gst, "sink"); - if (!pad) { - wfd_sink_error("failed to get pad from queue of audiobin\n"); - goto CREATE_ERROR; - } + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */ + if (a_decodebin != NULL && a_decodebin[i].gst) { + GstObject *parent = NULL; + parent = gst_element_get_parent(a_decodebin[i].gst); - ghostpad = gst_ghost_pad_new("sink", pad); - if (!ghostpad) { - wfd_sink_error("failed to create ghostpad\n"); - goto CREATE_ERROR; + if (!parent) { + gst_object_unref(GST_OBJECT(a_decodebin[i].gst)); + a_decodebin[i].gst = NULL; + } else { + gst_object_unref(GST_OBJECT(parent)); + } + } } - if (FALSE == gst_element_add_pad(audiobin[WFD_SINK_A_BIN].gst, ghostpad)) { - wfd_sink_error("failed to add ghostpad to audiobin\n"); - goto CREATE_ERROR; - } + /* release audioo decodebin with it's childs */ + if (a_decodebin != NULL && a_decodebin[WFD_SINK_A_D_BIN].gst) + gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst)); - gst_object_unref(GST_OBJECT(pad)); + MMWFDSINK_FREEIF(a_decodebin); - g_list_free(element_bucket); + return MM_ERROR_WFD_INTERNAL; +} - /* take it */ - wfd_sink->pipeline->audiobin = audiobin; +static int __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + MMWFDSinkGstElement *a_sinkbin = NULL; + GstObject *parent = NULL; + int i; - wfd_sink_debug_fleave(); + wfd_sink_debug_fenter(); - return MM_ERROR_NONE; + wfd_sink_return_val_if_fail(wfd_sink, + MM_ERROR_WFD_NOT_INITIALIZED); -CREATE_ERROR: - wfd_sink_error("failed to create audiobin, releasing all\n"); + if (wfd_sink->pipeline && + wfd_sink->pipeline->a_sinkbin&& + wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) { + a_sinkbin = wfd_sink->pipeline->a_sinkbin; + } else { + wfd_sink_debug("audio sinkbin is not created, nothing to destroy"); + return MM_ERROR_NONE; + } - if (wfd_sink->next_audio_dec_sink_pad) - gst_object_unref(GST_OBJECT(wfd_sink->next_audio_dec_sink_pad)); - wfd_sink->next_audio_dec_sink_pad = NULL; - if (wfd_sink->prev_audio_dec_src_pad) - gst_object_unref(GST_OBJECT(wfd_sink->prev_audio_dec_src_pad)); - wfd_sink->prev_audio_dec_src_pad = NULL; + parent = gst_element_get_parent(a_sinkbin[WFD_SINK_A_S_BIN].gst); + if (!parent) { + wfd_sink_debug("audio decodebin has no parent.. need to relase by itself"); + + if (GST_STATE(a_sinkbin[WFD_SINK_A_S_BIN].gst) >= GST_STATE_READY) { + wfd_sink_debug("try to change state of audio decodebin to NULL"); + ret = gst_element_set_state(a_sinkbin[WFD_SINK_A_S_BIN].gst, GST_STATE_NULL); + if (ret != GST_STATE_CHANGE_SUCCESS) { + wfd_sink_error("failed to change state of audio decodebin to NULL"); + return MM_ERROR_WFD_INTERNAL; + } + } + + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */ + if (a_sinkbin[i].gst) { + parent = gst_element_get_parent(a_sinkbin[i].gst); + if (!parent) { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)), + ((GObject *) a_sinkbin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(a_sinkbin[i].gst)); + a_sinkbin[i].gst = NULL; + } else { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)), + ((GObject *) a_sinkbin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release audio decodebin with it's childs */ + if (a_sinkbin[WFD_SINK_A_S_BIN].gst) + gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst)); + + } else { + wfd_sink_debug("audio sinkbin has parent(%s), unref it ", + GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); + + gst_object_unref(GST_OBJECT(parent)); + } + + MMWFDSINK_FREEIF(wfd_sink->pipeline->a_sinkbin); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink) +{ + MMWFDSinkGstElement *a_sinkbin = NULL; + MMWFDSinkGstElement *first_element = NULL; + GList *element_bucket = NULL; + GstPad *ghostpad = NULL; + GstPad *pad = NULL; + gint i=0; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline, + MM_ERROR_WFD_NOT_INITIALIZED); + + /* alloc handles */ + a_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM); + if (!a_sinkbin) { + wfd_sink_error("failed to allocate memory for audio sinkbin"); + return MM_ERROR_WFD_NO_FREE_SPACE; + } + + memset(a_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM); + + /* create audio sinkbin */ + a_sinkbin[WFD_SINK_A_S_BIN].id = WFD_SINK_A_S_BIN; + a_sinkbin[WFD_SINK_A_S_BIN].gst = gst_bin_new("audio_sinkbin"); + if (!a_sinkbin[WFD_SINK_A_S_BIN].gst) { + wfd_sink_error("failed to create audio sinkbin"); + goto CREATE_ERROR; + } + + /* create resampler */ + MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_RESAMPLER, wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "src"); + + /* create volume */ + MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_VOLUME, wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "src"); + + /* create sink */ + MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_SINK, wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_SINK].gst, "sink"); + if (a_sinkbin[WFD_SINK_A_S_SINK].gst) { + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, a_sinkbin[WFD_SINK_A_S_SINK].gst)) { + wfd_sink_error("failed to set audio sink property...."); + goto CREATE_ERROR; + } + } + + /* adding created elements to audio sinkbin */ + if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_sinkbin[WFD_SINK_A_S_BIN].gst), element_bucket, FALSE)) { + wfd_sink_error("failed to add elements to audio sinkbin"); + goto CREATE_ERROR; + } + + /* linking elements in the bucket by added order. */ + if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { + wfd_sink_error("failed to link elements fo the audio sinkbin"); + goto CREATE_ERROR; + } + + /* get first element's of the audio sinkbin */ + first_element = (MMWFDSinkGstElement *)g_list_first(element_bucket)->data; + if (!first_element) { + wfd_sink_error("failed to get first element of the audio sinkbin"); + goto CREATE_ERROR; + } + + /* get first element's sinkpad for creating ghostpad */ + pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); + if (!pad) { + wfd_sink_error("failed to get sink pad from element(%s)", + GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); + goto CREATE_ERROR; + } + + ghostpad = gst_ghost_pad_new("sink", pad); + if (!ghostpad) { + wfd_sink_error("failed to create ghostpad of audio sinkbin"); + goto CREATE_ERROR; + } + + if (FALSE == gst_element_add_pad(a_sinkbin[WFD_SINK_A_S_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to audio sinkbin"); + goto CREATE_ERROR; + } + gst_object_unref(GST_OBJECT(pad)); + + g_list_free(element_bucket); + + /* take it */ + wfd_sink->pipeline->a_sinkbin = a_sinkbin; + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + +CREATE_ERROR: + wfd_sink_error("failed to create audio sinkbin, releasing all"); if (pad) gst_object_unref(GST_OBJECT(pad)); @@ -2426,48 +2702,187 @@ CREATE_ERROR: element_bucket = NULL; /* release element which are not added to bin */ - __mm_wfd_sink_destroy_audiobin(wfd_sink); + for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */ + if (a_sinkbin != NULL && a_sinkbin[i].gst) { + GstObject *parent = NULL; + parent = gst_element_get_parent(a_sinkbin[i].gst); + + if (!parent) { + gst_object_unref(GST_OBJECT(a_sinkbin[i].gst)); + a_sinkbin[i].gst = NULL; + } else { + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release audio sinkbin with it's childs */ + if (a_sinkbin != NULL && a_sinkbin[WFD_SINK_A_S_BIN].gst) + gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst)); - MMWFDSINK_FREEIF(audiobin); + MMWFDSINK_FREEIF(a_sinkbin); return MM_ERROR_WFD_INTERNAL; } -int __mm_wfd_sink_link_videobin(mm_wfd_sink_t *wfd_sink) +int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink) { - MMWFDSinkGstElement *videobin = NULL; + MMWFDSinkGstElement *v_decodebin = NULL; + MMWFDSinkGstElement *first_element = NULL; + MMWFDSinkGstElement *last_element = NULL; + GList *element_bucket = NULL; + GstPad *sinkpad = NULL; + GstPad *srcpad = NULL; + GstPad *ghostpad = NULL; wfd_sink_debug_fenter(); wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->pipeline && - wfd_sink->pipeline->videobin && - wfd_sink->pipeline->videobin[WFD_SINK_V_BIN].gst, + wfd_sink->pipeline->v_decodebin && + wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst, MM_ERROR_WFD_NOT_INITIALIZED); - if (wfd_sink->video_bin_is_linked) { - wfd_sink_debug("videobin is already linked... nothing to do\n"); + if (wfd_sink->video_decodebin_is_linked) { + wfd_sink_debug("video decodebin is already linked... nothing to do"); return MM_ERROR_NONE; } - /* take videobin */ - videobin = wfd_sink->pipeline->videobin; + /* take video decodebin */ + v_decodebin = wfd_sink->pipeline->v_decodebin; + + /* check video queue */ + if (v_decodebin[WFD_SINK_V_D_QUEUE].gst) + element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_QUEUE]); + + /* check video hdcp */ + if (v_decodebin[WFD_SINK_V_D_HDCP].gst) + element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_HDCP]); + + /* check video codec */ + switch (wfd_sink->stream_info.video_stream_info.codec) { + case MM_WFD_SINK_VIDEO_CODEC_H264: + if (v_decodebin[WFD_SINK_V_D_PARSE].gst) + element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_PARSE]); + if (v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst) { + GstCaps *caps = NULL; + + element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_CAPSSETTER]); + caps = gst_caps_new_simple("video/x-h264", + "width", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.width, + "height", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.height, + "framerate", GST_TYPE_FRACTION, wfd_sink->stream_info.video_stream_info.frame_rate, 1, NULL); + g_object_set(G_OBJECT(v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst), "caps", caps, NULL); + gst_object_unref(GST_OBJECT(caps)); + } + if (v_decodebin[WFD_SINK_V_D_DEC].gst) + element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_DEC]); + break; - if (videobin[WFD_SINK_V_CAPSSETTER].gst) { - GstCaps *caps = NULL; - caps = gst_caps_new_simple("video/x-h264", - "width", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.width, - "height", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.height, - "framerate", GST_TYPE_FRACTION, wfd_sink->stream_info.video_stream_info.frame_rate, 1, NULL); - g_object_set(G_OBJECT(videobin[WFD_SINK_V_CAPSSETTER].gst), "caps", caps, NULL); - gst_object_unref(GST_OBJECT(caps)); + default: + wfd_sink_error("video codec is not decied yet. cannot link video decpdebin..."); + return MM_ERROR_WFD_INTERNAL; + break; } - wfd_sink->video_bin_is_linked = TRUE; + if (element_bucket == NULL) { + wfd_sink_error("there are no elements to be linked in the video decodebin, destroy it"); + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to destroy video decodebin"); + goto fail_to_link; + } + goto done; + } + + /* adding elements to video decodebin */ + if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_decodebin[WFD_SINK_V_D_BIN].gst), element_bucket, FALSE)) { + wfd_sink_error("failed to add elements to video decodebin"); + goto fail_to_link; + } + + /* linking elements in the bucket by added order. */ + if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { + wfd_sink_error("failed to link elements of the video decodebin"); + goto fail_to_link; + } + + /* get first element's sinkpad for creating ghostpad */ + first_element = (MMWFDSinkGstElement *)g_list_first(element_bucket)->data; + if (!first_element) { + wfd_sink_error("failed to get first element of the video decodebin"); + goto fail_to_link; + } + + sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); + if (!sinkpad) { + wfd_sink_error("failed to get sink pad from element(%s)", + GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); + goto fail_to_link; + } + + ghostpad = gst_ghost_pad_new("sink", sinkpad); + if (!ghostpad) { + wfd_sink_error("failed to create ghostpad of video decodebin"); + goto fail_to_link; + } + + if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to video decodebin"); + goto fail_to_link; + } + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; + + + /* get last element's src for creating ghostpad */ + last_element = (MMWFDSinkGstElement *)g_list_last(element_bucket)->data; + if (!last_element) { + wfd_sink_error("failed to get last element of the video decodebin"); + goto fail_to_link; + } + + srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src"); + if (!srcpad) { + wfd_sink_error("failed to get src pad from element(%s)", + GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst))); + goto fail_to_link; + } + + ghostpad = gst_ghost_pad_new("src", srcpad); + if (!ghostpad) { + wfd_sink_error("failed to create ghostpad of video decodebin"); + goto fail_to_link; + } + + if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to video decodebin"); + goto fail_to_link; + } + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + + g_list_free(element_bucket); + +done: + wfd_sink->video_decodebin_is_linked = TRUE; wfd_sink_debug_fleave(); return MM_ERROR_NONE; + + /* ERRORS*/ +fail_to_link: + if (srcpad) + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + + if (sinkpad) + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; + + g_list_free(element_bucket); + + return MM_ERROR_WFD_INTERNAL; } static int __mm_wfd_sink_prepare_videodec(mm_wfd_sink_t *wfd_sink, GstElement *video_dec) @@ -2560,10 +2975,10 @@ static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement * return MM_ERROR_NONE; } -static int __mm_wfd_sink_destroy_videobin(mm_wfd_sink_t *wfd_sink) +static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - MMWFDSinkGstElement *videobin = NULL; + MMWFDSinkGstElement *v_decodebin = NULL; GstObject *parent = NULL; int i; @@ -2572,187 +2987,362 @@ static int __mm_wfd_sink_destroy_videobin(mm_wfd_sink_t *wfd_sink) wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); if (wfd_sink->pipeline && - wfd_sink->pipeline->videobin && - wfd_sink->pipeline->videobin[WFD_SINK_V_BIN].gst) { - videobin = wfd_sink->pipeline->videobin; + wfd_sink->pipeline->v_decodebin && + wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) { + v_decodebin = wfd_sink->pipeline->v_decodebin; } else { - wfd_sink_debug("videobin is not created, nothing to destroy\n"); + wfd_sink_debug("video decodebin is not created, nothing to destroy"); return MM_ERROR_NONE; } - parent = gst_element_get_parent(videobin[WFD_SINK_V_BIN].gst); + parent = gst_element_get_parent(v_decodebin[WFD_SINK_V_D_BIN].gst); if (!parent) { - wfd_sink_debug("videobin has no parent.. need to relase by itself\n"); + wfd_sink_debug("video decodebin has no parent.. need to relase by itself"); - if (GST_STATE(videobin[WFD_SINK_V_BIN].gst) >= GST_STATE_READY) { - wfd_sink_debug("try to change state of videobin to NULL\n"); - ret = gst_element_set_state(videobin[WFD_SINK_V_BIN].gst, GST_STATE_NULL); + if (GST_STATE(v_decodebin[WFD_SINK_V_D_BIN].gst) >= GST_STATE_READY) { + wfd_sink_debug("try to change state of video decodebin to NULL"); + ret = gst_element_set_state(v_decodebin[WFD_SINK_V_D_BIN].gst, GST_STATE_NULL); if (ret != GST_STATE_CHANGE_SUCCESS) { - wfd_sink_error("failed to change state of videobin to NULL\n"); + wfd_sink_error("failed to change state of video decodebin to NULL"); return MM_ERROR_WFD_INTERNAL; } } /* release element which are not added to bin */ - for (i = 1; i < WFD_SINK_V_NUM; i++) { /* NOTE : skip bin */ - if (videobin[i].gst) { - parent = gst_element_get_parent(videobin[i].gst); + for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */ + if (v_decodebin[i].gst) { + parent = gst_element_get_parent(v_decodebin[i].gst); if (!parent) { - wfd_sink_debug("unref %s(current ref %d)\n", - GST_STR_NULL(GST_ELEMENT_NAME(videobin[i].gst)), - ((GObject *) videobin[i].gst)->ref_count); - gst_object_unref(GST_OBJECT(videobin[i].gst)); - videobin[i].gst = NULL; + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)), + ((GObject *) v_decodebin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(v_decodebin[i].gst)); + v_decodebin[i].gst = NULL; } else { - wfd_sink_debug("unref %s(current ref %d)\n", - GST_STR_NULL(GST_ELEMENT_NAME(videobin[i].gst)), - ((GObject *) videobin[i].gst)->ref_count); + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)), + ((GObject *) v_decodebin[i].gst)->ref_count); gst_object_unref(GST_OBJECT(parent)); } } } - /* release audiobin with it's childs */ - if (videobin[WFD_SINK_V_BIN].gst) { - gst_object_unref(GST_OBJECT(videobin[WFD_SINK_V_BIN].gst)); + /* release video decodebin with it's childs */ + if (v_decodebin[WFD_SINK_V_D_BIN].gst) { + gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst)); + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[WFD_SINK_V_D_BIN].gst)), + ((GObject *)v_decodebin[WFD_SINK_V_D_BIN].gst)->ref_count); } } else { - wfd_sink_debug("videobin has parent(%s), unref it \n", + wfd_sink_debug("video decodebin has parent(%s), unref it", GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); gst_object_unref(GST_OBJECT(parent)); } + wfd_sink->video_decodebin_is_linked = FALSE; + + MMWFDSINK_FREEIF(wfd_sink->pipeline->v_decodebin); + wfd_sink_debug_fleave(); return MM_ERROR_NONE; } - -static int __mm_wfd_sink_create_videobin(mm_wfd_sink_t *wfd_sink) +static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink) { - MMWFDSinkGstElement *first_element = NULL; - MMWFDSinkGstElement *videobin = NULL; + MMWFDSinkGstElement *v_decodebin = NULL; + guint video_codec = WFD_VIDEO_UNKNOWN; GList *element_bucket = NULL; - GstPad *pad = NULL; - GstPad *ghostpad = NULL; + gboolean link = TRUE; + gint i=0; wfd_sink_debug_fenter(); wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin, + wfd_sink->pipeline, MM_ERROR_WFD_NOT_INITIALIZED); + if (wfd_sink->pipeline->v_decodebin) { + wfd_sink_debug("video decodebin is already created... nothing to do"); + return MM_ERROR_NONE; + } + + /* check audio decodebin could be linked now */ + switch (wfd_sink->stream_info.video_stream_info.codec) { + case MM_WFD_SINK_VIDEO_CODEC_H264: + video_codec = WFD_VIDEO_H264; + link = TRUE; + break; + case MM_WFD_SINK_VIDEO_CODEC_NONE: + default: + wfd_sink_debug("video decodebin could NOT be linked now, just create"); + video_codec = wfd_sink->ini.video_codec; + link = FALSE; + break; + } + /* alloc handles */ - videobin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_NUM); - if (!videobin) { - wfd_sink_error("failed to allocate memory for videobin\n"); + v_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM); + if (!v_decodebin) { + wfd_sink_error("failed to allocate memory for video decodebin"); return MM_ERROR_WFD_NO_FREE_SPACE; } - /* create videobin */ - videobin[WFD_SINK_V_BIN].id = WFD_SINK_V_BIN; - videobin[WFD_SINK_V_BIN].gst = gst_bin_new("videobin"); - if (!videobin[WFD_SINK_V_BIN].gst) { - wfd_sink_error("failed to create videobin\n"); + memset(v_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM); + + /* create video decodebin */ + v_decodebin[WFD_SINK_V_D_BIN].id = WFD_SINK_V_D_BIN; + v_decodebin[WFD_SINK_V_D_BIN].gst = gst_bin_new("video_decodebin"); + if (!v_decodebin[WFD_SINK_V_D_BIN].gst) { + wfd_sink_error("failed to create video decodebin"); goto CREATE_ERROR; } - /* queue - drm - parse - dec - sink */ /* create queue */ - MMWFDSINK_CREATE_ELEMENT(videobin, WFD_SINK_V_QUEUE, "queue", "video_queue", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_QUEUE].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_QUEUE].gst, "src"); - if (videobin[WFD_SINK_V_QUEUE].gst) { - g_object_set(G_OBJECT(videobin[WFD_SINK_V_QUEUE].gst), "max-size-bytes", 0, NULL); - g_object_set(G_OBJECT(videobin[WFD_SINK_V_QUEUE].gst), "max-size-buffers", 0, NULL); - g_object_set(G_OBJECT(videobin[WFD_SINK_V_QUEUE].gst), "max-size-time", (guint64)3000000000ULL, NULL); - g_signal_connect(videobin[WFD_SINK_V_QUEUE].gst, "overrun", - G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink); - } - - /* create parser */ - MMWFDSINK_CREATE_ELEMENT(videobin, WFD_SINK_V_PARSE, wfd_sink->ini.name_of_video_parser, "video_parser", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_PARSE].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_PARSE].gst, "src"); - - /* create capssetter */ - MMWFDSINK_CREATE_ELEMENT(videobin, WFD_SINK_V_CAPSSETTER, wfd_sink->ini.name_of_video_capssetter, "video_capssetter", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_CAPSSETTER].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_CAPSSETTER].gst, "src"); - - /* create dec */ - MMWFDSINK_CREATE_ELEMENT(videobin, WFD_SINK_V_DEC, wfd_sink->ini.name_of_video_decoder, "video_dec", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_DEC].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_DEC].gst, "src"); - if (videobin[WFD_SINK_V_DEC].gst) { - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, videobin[WFD_SINK_V_DEC].gst)) { - wfd_sink_error("failed to set video sink property....\n"); - goto CREATE_ERROR; + MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_QUEUE, "queue", "video_queue", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst, "sink"); + if (v_decodebin[WFD_SINK_V_D_QUEUE].gst) + __mm_wfd_sink_prepare_queue( wfd_sink, v_decodebin[WFD_SINK_V_D_QUEUE].gst); + + /* create hdcp */ + MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_HDCP, wfd_sink->ini.name_of_video_hdcp, "video_hdcp", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "src"); + + if (video_codec & WFD_VIDEO_H264) { + /* create parser */ + MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_PARSE, wfd_sink->ini.name_of_video_parser, "video_parser", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst, "src"); + + /* create capssetter */ + MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_CAPSSETTER, wfd_sink->ini.name_of_video_capssetter, "video_capssetter", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst, "src"); + + /* create dec */ + MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_DEC, wfd_sink->ini.name_of_video_decoder, "video_dec", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst, "src"); + if (v_decodebin[WFD_SINK_V_D_DEC].gst) { + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_DEC].gst)) { + wfd_sink_error("failed to set video decoder property..."); + goto CREATE_ERROR; + } } } + g_list_free(element_bucket); + + /* take it */ + wfd_sink->pipeline->v_decodebin = v_decodebin; + + /* link video decodebin if video codec is fixed */ + if (link) { + if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to link video decodebin, destroy video decodebin"); + __mm_wfd_sink_destroy_video_decodebin(wfd_sink); + return MM_ERROR_WFD_INTERNAL; + } + } + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + + /* ERRORS */ +CREATE_ERROR: + wfd_sink_error("failed to create video decodebin, releasing all"); + + g_list_free(element_bucket); + + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */ + if (v_decodebin != NULL && v_decodebin[i].gst) { + GstObject *parent = NULL; + parent = gst_element_get_parent(v_decodebin[i].gst); + + if (!parent) { + gst_object_unref(GST_OBJECT(v_decodebin[i].gst)); + v_decodebin[i].gst = NULL; + } else { + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release video decodebin with it's childs */ + if (v_decodebin != NULL && v_decodebin[WFD_SINK_V_D_BIN].gst) + gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst)); + + MMWFDSINK_FREEIF(v_decodebin); + + return MM_ERROR_WFD_INTERNAL; +} + +static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + MMWFDSinkGstElement *v_sinkbin = NULL; + GstObject *parent = NULL; + int i; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + if (wfd_sink->pipeline && + wfd_sink->pipeline->v_sinkbin && + wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) { + v_sinkbin = wfd_sink->pipeline->v_sinkbin; + } else { + wfd_sink_debug("video sinkbin is not created, nothing to destroy"); + return MM_ERROR_NONE; + } + + + parent = gst_element_get_parent(v_sinkbin[WFD_SINK_V_S_BIN].gst); + if (!parent) { + wfd_sink_debug("video sinkbin has no parent.. need to relase by itself"); + + if (GST_STATE(v_sinkbin[WFD_SINK_V_S_BIN].gst) >= GST_STATE_READY) { + wfd_sink_debug("try to change state of video sinkbin to NULL"); + ret = gst_element_set_state(v_sinkbin[WFD_SINK_V_S_BIN].gst, GST_STATE_NULL); + if (ret != GST_STATE_CHANGE_SUCCESS) { + wfd_sink_error("failed to change state of video sinkbin to NULL"); + return MM_ERROR_WFD_INTERNAL; + } + } + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */ + if (v_sinkbin[i].gst) { + parent = gst_element_get_parent(v_sinkbin[i].gst); + if (!parent) { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)), + ((GObject *) v_sinkbin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(v_sinkbin[i].gst)); + v_sinkbin[i].gst = NULL; + } else { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)), + ((GObject *) v_sinkbin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(parent)); + } + } + } + /* release video sinkbin with it's childs */ + if (v_sinkbin[WFD_SINK_V_S_BIN].gst) { + gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst)); + } + } else { + wfd_sink_debug("video sinkbin has parent(%s), unref it ", + GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); + + gst_object_unref(GST_OBJECT(parent)); + } + + MMWFDSINK_FREEIF(wfd_sink->pipeline->v_sinkbin); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink) +{ + MMWFDSinkGstElement *first_element = NULL; + MMWFDSinkGstElement *v_sinkbin = NULL; + GList *element_bucket = NULL; + GstPad *pad = NULL; + GstPad *ghostpad = NULL; + gint i=0; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline, + MM_ERROR_WFD_NOT_INITIALIZED); + + /* alloc handles */ + v_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM); + if (!v_sinkbin) { + wfd_sink_error("failed to allocate memory for video sinkbin"); + return MM_ERROR_WFD_NO_FREE_SPACE; + } + + memset(v_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM); + + /* create video sinkbin */ + v_sinkbin[WFD_SINK_V_S_BIN].id = WFD_SINK_V_S_BIN; + v_sinkbin[WFD_SINK_V_S_BIN].gst = gst_bin_new("video_sinkbin"); + if (!v_sinkbin[WFD_SINK_V_S_BIN].gst) { + wfd_sink_error("failed to create video sinkbin"); + goto CREATE_ERROR; + } + /* create convert */ - MMWFDSINK_CREATE_ELEMENT(videobin, WFD_SINK_V_CONVERT, wfd_sink->ini.name_of_video_converter, "video_convert", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_CONVERT].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_CONVERT].gst, "src"); + MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_CONVERT, wfd_sink->ini.name_of_video_converter, "video_convert", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "src"); /* create filter */ - MMWFDSINK_CREATE_ELEMENT(videobin, WFD_SINK_V_CAPSFILTER, wfd_sink->ini.name_of_video_filter, "video_filter", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_CAPSFILTER].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_CAPSFILTER].gst, "src"); - if (videobin[WFD_SINK_V_CAPSFILTER].gst) { + MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_FILTER, wfd_sink->ini.name_of_video_filter, "video_filter", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "src"); + if (v_sinkbin[WFD_SINK_V_S_FILTER].gst) { GstCaps *caps = NULL; caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "SN12", NULL); - g_object_set(G_OBJECT(videobin[WFD_SINK_V_CAPSFILTER].gst), "caps", caps, NULL); + g_object_set(G_OBJECT(v_sinkbin[WFD_SINK_V_S_FILTER].gst), "caps", caps, NULL); gst_object_unref(GST_OBJECT(caps)); } - /* create sink */ - MMWFDSINK_CREATE_ELEMENT(videobin, WFD_SINK_V_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, videobin[WFD_SINK_V_SINK].gst, "sink"); - if (videobin[WFD_SINK_V_SINK].gst) { - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, videobin[WFD_SINK_V_SINK].gst)) { - wfd_sink_error("failed to set video sink property....\n"); + MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_SINK].gst, "sink"); + if (v_sinkbin[WFD_SINK_V_S_SINK].gst) { + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, v_sinkbin[WFD_SINK_V_S_SINK].gst)) { + wfd_sink_error("failed to set video sink property...."); goto CREATE_ERROR; } } - /* adding created elements to videobin */ - if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(videobin[WFD_SINK_V_BIN].gst), element_bucket, FALSE)) { - wfd_sink_error("failed to add elements\n"); + /* adding created elements to video sinkbin */ + if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_sinkbin[WFD_SINK_V_S_BIN].gst), element_bucket, FALSE)) { + wfd_sink_error("failed to add elements to video sinkbin"); goto CREATE_ERROR; } /* linking elements in the bucket by added order. */ if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { - wfd_sink_error("failed to link elements\n"); + wfd_sink_error("failed to link elements of the video sinkbin"); goto CREATE_ERROR; } /* get first element's sinkpad for creating ghostpad */ first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0); if (!first_element) { - wfd_sink_error("failed to get first element of videobin\n"); + wfd_sink_error("failed to get first element of the video sinkbin"); goto CREATE_ERROR; } pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); if (!pad) { - wfd_sink_error("failed to get pad from first element(%s) of videobin\n", GST_ELEMENT_NAME(first_element->gst)); + wfd_sink_error("failed to get pad from first element(%s) of the video sinkbin", + GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); goto CREATE_ERROR; } ghostpad = gst_ghost_pad_new("sink", pad); if (!ghostpad) { - wfd_sink_error("failed to create ghostpad\n"); + wfd_sink_error("failed to create ghostpad of the video sinkbin"); goto CREATE_ERROR; } - if (FALSE == gst_element_add_pad(videobin[WFD_SINK_V_BIN].gst, ghostpad)) { - wfd_sink_error("failed to add ghostpad to videobin\n"); + if (FALSE == gst_element_add_pad(v_sinkbin[WFD_SINK_V_S_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to video sinkbin"); goto CREATE_ERROR; } @@ -2762,15 +3352,7 @@ static int __mm_wfd_sink_create_videobin(mm_wfd_sink_t *wfd_sink) /* take it */ - wfd_sink->pipeline->videobin = videobin; - - if (wfd_sink->ini.video_sink_async) { - GstBus *bus = NULL; - bus = gst_element_get_bus(videobin[WFD_SINK_V_BIN].gst); - if (bus) - gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL); - gst_object_unref(bus); - } + wfd_sink->pipeline->v_sinkbin = v_sinkbin; wfd_sink_debug_fleave(); @@ -2778,7 +3360,7 @@ static int __mm_wfd_sink_create_videobin(mm_wfd_sink_t *wfd_sink) /* ERRORS */ CREATE_ERROR: - wfd_sink_error("failed to create videobin, releasing all\n"); + wfd_sink_error("failed to create video sinkbin, releasing all"); if (pad) gst_object_unref(GST_OBJECT(pad)); @@ -2790,9 +3372,26 @@ CREATE_ERROR: g_list_free(element_bucket); - __mm_wfd_sink_destroy_videobin(wfd_sink); + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */ + if (v_sinkbin != NULL && v_sinkbin[i].gst) { + GstObject *parent = NULL; + parent = gst_element_get_parent(v_sinkbin[i].gst); + + if (!parent) { + gst_object_unref(GST_OBJECT(v_sinkbin[i].gst)); + v_sinkbin[i].gst = NULL; + } else { + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release video sinkbin with it's childs */ + if (v_sinkbin != NULL && v_sinkbin[WFD_SINK_V_S_BIN].gst) + gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst)); - MMWFDSINK_FREEIF(videobin); + MMWFDSINK_FREEIF(v_sinkbin); return MM_ERROR_WFD_INTERNAL; } @@ -2818,38 +3417,42 @@ static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink) MMWFDSinkGstElement *mainbin = wfd_sink->pipeline->mainbin; if (mainbin) { - MMWFDSinkGstElement *audiobin = wfd_sink->pipeline->audiobin; - MMWFDSinkGstElement *videobin = wfd_sink->pipeline->videobin; - ret = gst_element_set_state(mainbin[WFD_SINK_M_PIPE].gst, GST_STATE_NULL); if (ret != GST_STATE_CHANGE_SUCCESS) { - wfd_sink_error("failed to change state of mainbin to NULL\n"); + wfd_sink_error("failed to change state of mainbin to NULL"); + return MM_ERROR_WFD_INTERNAL; + } + + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to destroy video decodebin"); + return MM_ERROR_WFD_INTERNAL; + } + + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to destroy audio decodebin"); return MM_ERROR_WFD_INTERNAL; } - if (MM_ERROR_NONE != __mm_wfd_sink_destroy_videobin(wfd_sink)) { - wfd_sink_error("failed to destroy videobin\n"); + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_sinkbin(wfd_sink)) { + wfd_sink_error("failed to destroy video sinkbin"); return MM_ERROR_WFD_INTERNAL; } - if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audiobin(wfd_sink)) { - wfd_sink_error("failed to destroy audiobin\n"); + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink)) { + wfd_sink_error("failed to destroy audio sinkbin"); return MM_ERROR_WFD_INTERNAL; } gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst)); - MMWFDSINK_FREEIF(audiobin); - MMWFDSINK_FREEIF(videobin); MMWFDSINK_FREEIF(mainbin); } MMWFDSINK_FREEIF(wfd_sink->pipeline); } - wfd_sink->added_av_pad_num = 0; - wfd_sink->audio_bin_is_linked = FALSE; - wfd_sink->video_bin_is_linked = FALSE; + wfd_sink->audio_decodebin_is_linked = FALSE; + wfd_sink->video_decodebin_is_linked = FALSE; wfd_sink->need_to_reset_basetime = FALSE; wfd_sink_debug_fleave(); @@ -2887,7 +3490,7 @@ __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink) factory = gst_element_get_factory(item) ; if (factory) { - wfd_sink_error("%s:%s : From:%s To:%s refcount : %d\n", + wfd_sink_error("%s:%s : From:%s To:%s refcount : %d", GST_STR_NULL(GST_OBJECT_NAME(factory)), GST_STR_NULL(GST_ELEMENT_NAME(item)), gst_element_state_get_name(state), @@ -2918,7 +3521,7 @@ __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink) factory = gst_element_get_factory(item) ; if (factory) { - wfd_sink_error("%s:%s : From:%s To:%s refcount : %d\n", + wfd_sink_error("%s:%s : From:%s To:%s refcount : %d", GST_OBJECT_NAME(factory), GST_ELEMENT_NAME(item), gst_element_state_get_name(state),