Change the structure of file src 25/264425/26
authorbackto.kim <backto.kim@samsung.com>
Fri, 17 Sep 2021 08:35:03 +0000 (17:35 +0900)
committerbackto.kim <backto.kim@samsung.com>
Fri, 1 Oct 2021 03:00:17 +0000 (12:00 +0900)
A separate pipeline for filesrc is added, and the existing src bin receives input with appsrc.
This makes functions such as file looping convenient by separately managing pipelines.

[Version] 0.2.112
[Issue Type] Improvement

Change-Id: I69e1edea62515eb57987624e12bf863fa653b3fc

include/webrtc_private.h
packaging/capi-media-webrtc.spec
src/webrtc_private.c
src/webrtc_source.c

index 16bf224bc28b1abd11116fd2ef39d3975e9df4a4..cfce82159b2a7d1b8affa609098a70d612502897 100644 (file)
@@ -472,6 +472,10 @@ typedef struct _webrtc_gst_slot_s {
        gulong camerasrc_probe_id;
        bool video_muted;
 
+       GstElement *filesrc_pipeline;
+       GstBus *filesrc_bus;
+       guint filesrc_bus_watcher;
+
        webrtc_display_s *display;
 } webrtc_gst_slot_s;
 
@@ -650,6 +654,8 @@ int _stop_websocket(webrtc_websocket_s *ws);
 int _check_privilege(const char *privilege);
 int _check_feature(const char *feature);
 
+int _gst_filesrc_pipeline_set_state(webrtc_s *webrtc, GstState state);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index 26e03423c0c16c449827bf9d1658c975da5295de..1e44ae412d638dc3d7d4bfb84331a974321f17fd 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.2.111
+Version:    0.2.112
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 2b63884d032e8ee3d17529128525e0f23752a927..bd06ae86696fbdcf875d80976ddb8a826b5e3112 100644 (file)
@@ -1304,6 +1304,7 @@ void _gst_destroy_pipeline(webrtc_s *webrtc)
 int _gst_pipeline_set_state(webrtc_s *webrtc, GstState state)
 {
        GstStateChangeReturn ret;
+       int filesrc_ret = WEBRTC_ERROR_NONE;
 
        RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
        RET_VAL_IF(webrtc->gst.pipeline == NULL, WEBRTC_ERROR_INVALID_OPERATION, "pipeline is NULL");
@@ -1314,6 +1315,9 @@ int _gst_pipeline_set_state(webrtc_s *webrtc, GstState state)
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
 
+       filesrc_ret = _gst_filesrc_pipeline_set_state(webrtc, state);
+       RET_VAL_IF(filesrc_ret != WEBRTC_ERROR_NONE, filesrc_ret, "failed to change filesrc pipeline state to [%s]", gst_element_state_get_name(state));
+
        return WEBRTC_ERROR_NONE;
 }
 
@@ -1748,4 +1752,4 @@ int _apply_stream_info(GstElement *element, const char *stream_type, int stream_
        gst_structure_free(structure);
 
        return WEBRTC_ERROR_NONE;
-}
\ No newline at end of file
+}
index b9a4efacf2764ae2784761bf72d4772d29a661f0..d78ec380a2194db751ba9da40a24bd2ca8ee3a3e 100644 (file)
 #define DEFAULT_NAME_VIDEO_PAYLOAD    "videoPayload"
 #define DEFAULT_NAME_VIDEOCROP        "videoCrop"
 #define DEFAULT_NAME_SCREENSRC        "waylandSrc"
-
+#define DEFAULT_NAME_AUDIO_FAKESINK   "audioFakeSink"
+#define DEFAULT_NAME_VIDEO_FAKESINK   "videoFakeSink"
+#define DEFAULT_NAME_AUDIO_APPSRC     "audioAppsrc"
+#define DEFAULT_NAME_VIDEO_APPSRC     "videoAppsrc"
 
 #define APPEND_ELEMENT(x_list, x_element) \
 do { \
@@ -1643,14 +1646,14 @@ exit:
        return ret;
 }
 
-static int __build_rest_of_filesrc_elements(webrtc_gst_slot_s *source, media_type_e media_type)
+static int __build_filesrc_bin(webrtc_gst_slot_s *source, media_type_e media_type)
 {
        int ret = WEBRTC_ERROR_NONE;
        gboolean is_audio;
        GstPad *src_pad = NULL;
+       GstElement *appsrc = NULL;
        GstElement *queue = NULL;
        GstElement *capsfilter = NULL;
-       unsigned int payload_id;
 
        RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
        RET_VAL_IF(source->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL");
@@ -1662,51 +1665,58 @@ static int __build_rest_of_filesrc_elements(webrtc_gst_slot_s *source, media_typ
        ret = _add_no_target_ghostpad_to_slot(source, true, &src_pad);
        RET_VAL_IF(ret != WEBRTC_ERROR_NONE, ret, "failed to _add_no_target_ghostpad_to_slot()");
 
-       if (!(queue = _create_element("queue", is_audio ? DEFAULT_NAME_AUDIO_QUEUE : DEFAULT_NAME_VIDEO_QUEUE)))
+       if (!(appsrc = _create_element("appsrc", is_audio ? DEFAULT_NAME_AUDIO_APPSRC : DEFAULT_NAME_VIDEO_APPSRC)))
+               return WEBRTC_ERROR_INVALID_OPERATION;
+
+       g_object_set(G_OBJECT(appsrc),
+                       "is-live", TRUE,
+                       "format", GST_FORMAT_TIME,
+                       NULL);
+
+       if (!(queue = _create_element("queue", is_audio ? DEFAULT_NAME_AUDIO_QUEUE : DEFAULT_NAME_VIDEO_QUEUE))) {
+               SAFE_GST_OBJECT_UNREF(appsrc);
                return WEBRTC_ERROR_INVALID_OPERATION;
+       }
 
        if (!(capsfilter = _create_element("capsfilter", is_audio ? DEFAULT_NAME_AUDIO_CAPSFILTER : DEFAULT_NAME_VIDEO_CAPSFILTER))) {
+               SAFE_GST_OBJECT_UNREF(appsrc);
                SAFE_GST_OBJECT_UNREF(queue);
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
 
-       gst_bin_add_many(source->bin, queue, capsfilter, NULL);
+       gst_bin_add_many(source->bin, appsrc, queue, capsfilter, NULL);
+
+       if (!gst_element_link_many(appsrc, queue, capsfilter, NULL)) {
+               LOG_ERROR("failed to gst_element_link_many()");
+               goto error;
+       }
+
+       if (!gst_element_sync_state_with_parent(appsrc)) {
+               LOG_ERROR("failed to gst_element_sync_state_with_parent() for [%s]", GST_ELEMENT_NAME(appsrc));
+               goto error;
+       }
 
        if (!gst_element_sync_state_with_parent(queue)) {
                LOG_ERROR("failed to gst_element_sync_state_with_parent() for [%s]", GST_ELEMENT_NAME(queue));
-               gst_bin_remove_many(source->bin, queue, capsfilter, NULL);
-               return WEBRTC_ERROR_INVALID_OPERATION;
+               goto error;
        }
 
        if (!gst_element_sync_state_with_parent(capsfilter)) {
                LOG_ERROR("failed to gst_element_sync_state_with_parent() for [%s]", GST_ELEMENT_NAME(capsfilter));
-               gst_bin_remove_many(source->bin, queue, capsfilter, NULL);
-               return WEBRTC_ERROR_INVALID_OPERATION;
-       }
-
-       if (!gst_element_link_many(queue, capsfilter, NULL)) {
-               LOG_ERROR("failed to gst_element_link_many()");
-               gst_bin_remove_many(source->bin, queue, capsfilter, NULL);
-               return WEBRTC_ERROR_INVALID_OPERATION;
+               goto error;
        }
 
        ret = _set_ghost_pad_target(src_pad, capsfilter, true);
-       if (ret != WEBRTC_ERROR_NONE) {
-               gst_bin_remove_many(source->bin, queue, capsfilter, NULL);
-               return ret;
-       }
+       if (ret != WEBRTC_ERROR_NONE)
+               goto error;
 
        __add_probe_to_pad_for_pause(source, is_audio ? AV_IDX_AUDIO : AV_IDX_VIDEO, src_pad, __payloaded_data_probe_cb);
 
-       payload_id = __get_available_payload_id(source->webrtc);
-       if (payload_id == 0) {
-               gst_bin_remove_many(source->bin, queue, capsfilter, NULL);
-               return WEBRTC_ERROR_INVALID_OPERATION;
-       }
-
-       source->av[is_audio ? AV_IDX_AUDIO : AV_IDX_VIDEO].payload_id = payload_id;
-
        return WEBRTC_ERROR_NONE;
+
+error:
+       gst_bin_remove_many(source->bin, appsrc, queue, capsfilter, NULL);
+       return WEBRTC_ERROR_INVALID_OPERATION;
 }
 
 static void __remove_rest_of_filesrc_element(webrtc_gst_slot_s *source, bool is_audio)
@@ -1723,14 +1733,130 @@ static void __remove_rest_of_filesrc_element(webrtc_gst_slot_s *source, bool is_
        gst_bin_remove_many(source->bin, queue, capsfilter, NULL);
 }
 
+static void __filesrc_pipeline_audio_stream_handoff_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
+{
+       webrtc_gst_slot_s *source = data;
+       GstFlowReturn gst_ret = GST_FLOW_OK;
+
+       g_signal_emit_by_name(gst_bin_get_by_name(source->bin, DEFAULT_NAME_AUDIO_APPSRC), "push-buffer", buffer, &gst_ret, NULL);
+       if (gst_ret != GST_FLOW_OK)
+               LOG_ERROR("failed to 'push-buffer', gst_ret[0x%x]", gst_ret);
+}
+
+static void __filesrc_pipeline_video_stream_handoff_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
+{
+       webrtc_gst_slot_s *source = data;
+       GstFlowReturn gst_ret = GST_FLOW_OK;
+
+       g_signal_emit_by_name(gst_bin_get_by_name(source->bin, DEFAULT_NAME_VIDEO_APPSRC), "push-buffer", buffer, &gst_ret, NULL);
+       if (gst_ret != GST_FLOW_OK)
+               LOG_ERROR("failed to 'push-buffer', gst_ret[0x%x]", gst_ret);
+}
+
+static GstPadProbeReturn __fakesink_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
+{
+       webrtc_gst_slot_s *source = u_data;
+       GstCaps *new_cap = NULL;
+       GstElement *appsrc = NULL;
+       gchar *media = NULL;
+
+       gst_structure_get(gst_caps_get_structure(gst_pad_get_current_caps(pad), 0), "media", G_TYPE_STRING, &media, NULL);
+
+       if (g_strrstr(media, "audio"))
+               appsrc = gst_bin_get_by_name(source->bin, DEFAULT_NAME_AUDIO_APPSRC);
+       else
+               appsrc = gst_bin_get_by_name(source->bin, DEFAULT_NAME_VIDEO_APPSRC);
+
+       RET_VAL_IF(appsrc == NULL, GST_PAD_PROBE_OK, "There is no appsrc for [%s]", media);
+
+       new_cap = gst_caps_copy(gst_pad_get_current_caps(pad));
+       g_object_set(G_OBJECT(appsrc), "caps", new_cap, NULL);
+
+       LOG_INFO("setting caps for [%s appsrc] successfully", media);
+       PRINT_CAPS(new_cap, "appsrc");
+
+       return GST_PAD_PROBE_REMOVE;
+}
+
+static int __create_rest_of_elements_for_filesrc_pipeline(webrtc_gst_slot_s *source, GstElement *payloader, bool is_audio)
+{
+       GstBin *bin = NULL;
+       GstElement *capsfilter = NULL;
+       GstElement *fakesink = NULL;
+       GstCaps *sink_caps = NULL;
+       unsigned int payload_id;
+       GstPad *sink_pad = NULL;
+
+       RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+       RET_VAL_IF(payloader == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "payloader is NULL");
+       RET_VAL_IF(source->filesrc_pipeline == NULL, WEBRTC_ERROR_INVALID_OPERATION, "filesrc_pipeline is NULL");
+
+       bin = GST_BIN(source->filesrc_pipeline);
+
+       if (!(capsfilter = _create_element(DEFAULT_ELEMENT_CAPSFILTER, is_audio ? DEFAULT_NAME_AUDIO_CAPSFILTER : DEFAULT_NAME_VIDEO_CAPSFILTER)))
+               return WEBRTC_ERROR_INVALID_OPERATION;
+
+       payload_id = __get_available_payload_id(source->webrtc);
+       if (payload_id == 0) {
+               SAFE_GST_OBJECT_UNREF(capsfilter);
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
+       source->av[is_audio ? AV_IDX_AUDIO : AV_IDX_VIDEO].payload_id = payload_id;
+
+       if ((sink_caps = __make_rtp_caps(is_audio ? "audio" : "video", payload_id))) {
+               g_object_set(G_OBJECT(capsfilter), "caps", sink_caps, NULL);
+               gst_caps_unref(sink_caps);
+       }
+
+       if (!(fakesink = _create_element("fakesink", is_audio ? DEFAULT_NAME_AUDIO_FAKESINK : DEFAULT_NAME_VIDEO_FAKESINK))) {
+               SAFE_GST_OBJECT_UNREF(capsfilter);
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
+       sink_pad = gst_element_get_static_pad(fakesink, "sink");
+       gst_pad_add_probe(sink_pad, GST_PAD_PROBE_TYPE_BUFFER, __fakesink_probe_cb, source, NULL);
+       gst_object_unref(sink_pad);
+
+       g_object_set(G_OBJECT(fakesink), "sync", true, NULL);
+       g_object_set(fakesink, "signal-handoffs", TRUE, NULL);
+       g_signal_connect(fakesink, "handoff", is_audio ? G_CALLBACK(__filesrc_pipeline_audio_stream_handoff_cb) : G_CALLBACK(__filesrc_pipeline_video_stream_handoff_cb), (gpointer)source);
+
+       gst_bin_add_many(GST_BIN(source->filesrc_pipeline), capsfilter, fakesink, NULL);
+
+       if (!gst_element_link_many(payloader, capsfilter, fakesink, NULL)) {
+               LOG_ERROR("failed to gst_element_link_many()");
+               gst_bin_remove_many(bin, capsfilter, fakesink, NULL);
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
+       if (!gst_element_sync_state_with_parent(capsfilter)) {
+               LOG_ERROR("failed to gst_element_sync_state_with_parent() for [%s]", GST_ELEMENT_NAME(capsfilter));
+               gst_bin_remove_many(bin, capsfilter, fakesink, NULL);
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
+       if (!gst_element_sync_state_with_parent(fakesink)) {
+               LOG_ERROR("failed to gst_element_sync_state_with_parent() for [%s]", GST_ELEMENT_NAME(fakesink));
+               gst_bin_remove_many(bin, capsfilter, fakesink, NULL);
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
+       return WEBRTC_ERROR_NONE;
+}
+
 static GstElement * __link_decodebin_with_payload(GstPad *pad, webrtc_gst_slot_s *source, bool is_audio, bool create)
 {
        element_info_s elem_info;
+       GstBin *bin = NULL;
        GstElement *payload = NULL;
        GstPad *payload_sink_pad = NULL;
 
        RET_VAL_IF(pad == NULL, NULL, "pad is NULL");
        RET_VAL_IF(source == NULL, NULL, "source is NULL");
+       RET_VAL_IF(source->filesrc_pipeline == NULL, NULL, "filesrc_pipeline is NULL");
+
+       bin = GST_BIN(source->filesrc_pipeline);
 
        if (create) {
                CREATE_ELEMENT_FROM_REGISTRY(elem_info, GST_KLASS_NAME_PAYLOADER_RTP,
@@ -1742,86 +1868,53 @@ static GstElement * __link_decodebin_with_payload(GstPad *pad, webrtc_gst_slot_s
 
                gst_element_set_name(payload, is_audio ? DEFAULT_NAME_AUDIO_PAYLOAD : DEFAULT_NAME_VIDEO_PAYLOAD);
 
-               gst_bin_add(source->bin, payload);
+               gst_bin_add(bin, payload);
 
                if (!gst_element_sync_state_with_parent(payload)) {
                        LOG_ERROR("failed to gst_element_sync_state_with_parent() for [%s]", GST_ELEMENT_NAME(payload));
-                       gst_bin_remove(source->bin, payload);
+                       gst_bin_remove(bin, payload);
                        return NULL;
                }
        } else {
-               payload = gst_bin_get_by_name(source->bin, is_audio ? DEFAULT_NAME_AUDIO_PAYLOAD : DEFAULT_NAME_VIDEO_PAYLOAD);
+               payload = gst_bin_get_by_name(bin, is_audio ? DEFAULT_NAME_AUDIO_PAYLOAD : DEFAULT_NAME_VIDEO_PAYLOAD);
                RET_VAL_IF(payload == NULL, NULL, "There is no payload to link");
        }
 
        payload_sink_pad = gst_element_get_static_pad(payload, "sink");
        if (!payload_sink_pad) {
                LOG_ERROR("payload_sink_pad is NULL");
-               gst_bin_remove(source->bin, payload);
+               gst_bin_remove(bin, payload);
                return NULL;
        }
 
        if (gst_pad_link(pad, payload_sink_pad) != GST_PAD_LINK_OK) {
                LOG_ERROR("failed to gst_pad_link()");
-               gst_bin_remove(source->bin, payload);
+               gst_bin_remove(bin, payload);
                g_object_unref(payload_sink_pad);
                return NULL;
        }
 
        g_object_unref(payload_sink_pad);
 
-       LOG_INFO("decidebin is linked to [%s]", GST_ELEMENT_NAME(payload));
+       LOG_INFO("decodebin is linked to [%s]", GST_ELEMENT_NAME(payload));
 
        return payload;
 }
 
-static int __link_payload_with_rest_of_filesrc_elements(webrtc_gst_slot_s *source, const gchar *media_type, GstElement *payload)
-{
-       gboolean is_audio;
-       GstElement *queue = NULL;
-       GstElement *capsfilter = NULL;
-       unsigned int payload_id = 0;
-       GstCaps *sink_caps = NULL;
-
-       RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
-       RET_VAL_IF(media_type == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "media_type is NULL");
-       RET_VAL_IF(payload == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "payload is NULL");
-
-       is_audio = (g_strrstr(media_type, "audio")) ? TRUE : FALSE;
-
-       queue = gst_bin_get_by_name(source->bin, is_audio ? DEFAULT_NAME_AUDIO_QUEUE : DEFAULT_NAME_VIDEO_QUEUE);
-       RET_VAL_IF(queue == NULL, WEBRTC_ERROR_INVALID_OPERATION, "queue is NULL");
-
-       capsfilter = gst_bin_get_by_name(source->bin, is_audio ? DEFAULT_NAME_AUDIO_CAPSFILTER : DEFAULT_NAME_VIDEO_CAPSFILTER);
-       RET_VAL_IF(capsfilter == NULL, WEBRTC_ERROR_INVALID_OPERATION, "capsfilter is NULL");
-
-       payload_id = source->av[is_audio ? AV_IDX_AUDIO : AV_IDX_VIDEO].payload_id;
-
-       if (!gst_element_link(payload, queue)) {
-               LOG_ERROR("failed to gst_element_link() [%s] - [%s]", GST_ELEMENT_NAME(payload), GST_ELEMENT_NAME(queue));
-               return WEBRTC_ERROR_INVALID_OPERATION;
-       }
-
-       if ((sink_caps = __make_rtp_caps(media_type, payload_id))) {
-               g_object_set(G_OBJECT(capsfilter), "caps", sink_caps, NULL);
-               gst_caps_unref(sink_caps);
-       }
-
-       LOG_INFO("[%s] is linked to [%s]", GST_ELEMENT_NAME(payload), GST_ELEMENT_NAME(queue));
-
-       return WEBRTC_ERROR_NONE;
-}
-
-static void __filesrc_decodebin_pad_added_cb(GstElement *element, GstPad *pad, gpointer data)
+static void __filesrc_pipeline_decodebin_pad_added_cb(GstElement *element, GstPad *pad, gpointer data)
 {
        int ret = WEBRTC_ERROR_NONE;
        webrtc_gst_slot_s *source = data;
+       GstBin *bin = NULL;
        const gchar *media_type = NULL;
        GstElement *payload = NULL;
        gboolean is_audio;
        int av_idx;
 
        RET_IF(source == NULL, "source is NULL");
+       RET_IF(source->filesrc_pipeline == NULL, "filesrc_pipeline is NULL");
+
+       bin = GST_BIN(source->filesrc_pipeline);
 
        media_type = gst_structure_get_name(gst_caps_get_structure(gst_pad_get_current_caps(pad), 0));
        RET_IF(media_type == NULL, "media_type is NULL");
@@ -1845,25 +1938,24 @@ static void __filesrc_decodebin_pad_added_cb(GstElement *element, GstPad *pad, g
        payload = __link_decodebin_with_payload(pad, source, is_audio, true);
        RET_IF(payload == NULL, "failed to __link_decodebin_with_payload()");
 
-       ret = __build_rest_of_filesrc_elements(source, is_audio ? MEDIA_TYPE_AUDIO : MEDIA_TYPE_VIDEO);
+       ret = __create_rest_of_elements_for_filesrc_pipeline(source, payload, is_audio);
        if (ret != WEBRTC_ERROR_NONE) {
-               LOG_ERROR("failed to __build_rest_of_filesrc_elements()");
-               gst_bin_remove(source->bin, payload);
+               LOG_ERROR("failed to __create_rest_of_elements_for_filesrc_pipeline()");
+               gst_bin_remove(bin, payload);
                return;
        }
 
-       ret = __link_payload_with_rest_of_filesrc_elements(source, media_type, payload);
+       ret = __build_filesrc_bin(source, is_audio ? MEDIA_TYPE_AUDIO : MEDIA_TYPE_VIDEO);
        if (ret != WEBRTC_ERROR_NONE) {
-               LOG_ERROR("failed to __link_payload_with_rest_of_filesrc_elements()");
-               gst_bin_remove(source->bin, payload);
-               __remove_rest_of_filesrc_element(source, is_audio);
+               LOG_ERROR("failed to __build_filesrc_bin()");
+               gst_bin_remove(bin, payload);
                return;
        }
 
        ret = __link_source_with_webrtcbin(source, source->webrtc->gst.webrtcbin);
        if (ret != WEBRTC_ERROR_NONE) {
                LOG_ERROR("failed to __link_source_with_webrtcbin()");
-               gst_bin_remove(source->bin, payload);
+               gst_bin_remove(bin, payload);
                __remove_rest_of_filesrc_element(source, is_audio);
                g_hash_table_remove(source->webrtc->gst.source_slots, GST_ELEMENT_NAME(source->bin));
                return;
@@ -1874,7 +1966,7 @@ static void __filesrc_decodebin_pad_added_cb(GstElement *element, GstPad *pad, g
        __add_probe_to_pad_for_render(source, av_idx, pad, __source_data_probe_cb);
 }
 
-static GstAutoplugSelectResult __filesrc_decodebin_autoplug_select_cb(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory* factory, gpointer udata)
+static GstAutoplugSelectResult __filesrc_pipeline_decodebin_autoplug_select_cb(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory* factory, gpointer udata)
 {
        const gchar *klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
 
@@ -1886,7 +1978,7 @@ static GstAutoplugSelectResult __filesrc_decodebin_autoplug_select_cb(GstElement
        return GST_AUTOPLUG_SELECT_TRY;
 }
 
-static void __filesrc_decodebin_pad_removed_cb(GstElement *element, GstPad *pad, gpointer data)
+static void __filesrc_pipeline_decodebin_pad_removed_cb(GstElement *element, GstPad *pad, gpointer data)
 {
        webrtc_gst_slot_s *source = data;
        int idx = 0;
@@ -1909,7 +2001,91 @@ static void __filesrc_decodebin_pad_removed_cb(GstElement *element, GstPad *pad,
        }
 }
 
-static int __build_filesrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
+static gboolean __filesrc_pipeline_bus_watch_cb(GstBus *bus, GstMessage *message, gpointer user_data)
+{
+       webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)user_data;
+       GError *err = NULL;
+       GstState gst_state_old = GST_STATE_VOID_PENDING;
+       GstState gst_state_new = GST_STATE_VOID_PENDING;
+       GstState gst_state_pending = GST_STATE_VOID_PENDING;
+
+       RET_VAL_IF(source == NULL, FALSE, "source is NULL");
+       RET_VAL_IF(source->filesrc_pipeline == NULL, FALSE, "pipeline is NULL");
+
+       if (message == NULL) {
+               LOG_DEBUG("message is null");
+               return TRUE;
+       }
+
+       switch (GST_MESSAGE_TYPE(message)) {
+       case GST_MESSAGE_ERROR:
+               gst_message_parse_error(message, &err, NULL);
+
+               LOG_ERROR("Error[from %s]: message[%s], code[%d]",
+                       GST_OBJECT_NAME(GST_OBJECT_CAST(GST_ELEMENT(GST_MESSAGE_SRC(message)))), err->message, err->code);
+
+               g_error_free(err);
+               break;
+
+       case GST_MESSAGE_STATE_CHANGED:
+               if (GST_MESSAGE_SRC(message) != GST_OBJECT(source->filesrc_pipeline))
+                       return TRUE;
+
+               gst_message_parse_state_changed(message, &gst_state_old, &gst_state_new, &gst_state_pending);
+
+               LOG_INFO("GST_MESSAGE_STATE_CHANGED: Old[GST_STATE_%s] New[GST_STATE_%s] Pending[GST_STATE_%s]",
+                               gst_element_state_get_name(gst_state_old), gst_element_state_get_name(gst_state_new),
+                               gst_element_state_get_name(gst_state_pending));
+               break;
+
+       case GST_MESSAGE_ASYNC_DONE:
+               if (GST_MESSAGE_SRC(message) != GST_OBJECT(source->filesrc_pipeline))
+                       return TRUE;
+
+               LOG_INFO("GST_MESSAGE_ASYNC_DONE");
+               break;
+
+       case GST_MESSAGE_EOS:
+               LOG_INFO("GST_MESSAGE_EOS end-of-stream");
+
+#if 0  //ToDo
+               gst_element_seek(source->filesrc_pipeline,
+                       1.0,
+                       GST_FORMAT_TIME,
+                       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
+                       GST_SEEK_TYPE_SET, 0,
+                       GST_SEEK_TYPE_NONE, 0);
+#endif
+               break;
+
+       default:
+               break;
+       }
+
+       return TRUE;
+}
+
+static void __destroy_filesrc_pipeline(webrtc_gst_slot_s *source)
+{
+       RET_IF(source == NULL, "source is NULL");
+
+       if (source->filesrc_bus_watcher > 0) {
+               gst_bus_remove_watch(source->filesrc_bus);
+               source->filesrc_bus_watcher = 0;
+       }
+
+       if (source->filesrc_bus) {
+               gst_object_unref(source->filesrc_bus);
+               source->filesrc_bus = NULL;
+       }
+
+       if (source->filesrc_pipeline) {
+               gst_object_unref(source->filesrc_pipeline);
+               source->filesrc_pipeline = NULL;
+       }
+}
+
+static int __build_filesrc_pipeline(webrtc_s *webrtc, webrtc_gst_slot_s *source)
 {
        GstElement *filesrc = NULL;
        GstElement *decodebin = NULL;
@@ -1918,27 +2094,45 @@ static int __build_filesrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
        RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
        RET_VAL_IF(source->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL");
 
+       source->filesrc_pipeline = gst_pipeline_new("filesrc-pipeline");
+       RET_VAL_IF(source->filesrc_pipeline == NULL, WEBRTC_ERROR_INVALID_OPERATION, "pipeline is NULL");
+
+       if (!(source->filesrc_bus = gst_pipeline_get_bus(GST_PIPELINE(source->filesrc_pipeline)))) {
+               LOG_ERROR("failed to gst_pipeline_get_bus()");
+               goto error;
+       }
+
+       if ((source->filesrc_bus_watcher = gst_bus_add_watch(source->filesrc_bus, (GstBusFunc)__filesrc_pipeline_bus_watch_cb, source)) == 0) {
+               LOG_ERROR("failed to gst_bus_add_watch()");
+               goto error;
+       }
+
        if (!(filesrc = _create_element("filesrc", DEFAULT_NAME_FILE_SRC)))
-               return WEBRTC_ERROR_INVALID_OPERATION;
+               goto error;
 
        if (!(decodebin = _create_element("decodebin", NULL))) {
                SAFE_GST_OBJECT_UNREF(filesrc);
-               return WEBRTC_ERROR_INVALID_OPERATION;
+               goto error;
        }
 
-       gst_bin_add_many(source->bin, filesrc, decodebin, NULL);
+       gst_bin_add_many(GST_BIN(source->filesrc_pipeline), filesrc, decodebin, NULL);
 
        if (!gst_element_link(filesrc, decodebin)) {
+               gst_bin_remove_many(GST_BIN(source->filesrc_pipeline), filesrc, decodebin, NULL);
                LOG_ERROR("failed to gst_element_link()");
-               gst_bin_remove_many(source->bin, filesrc, decodebin, NULL);
-               return WEBRTC_ERROR_INVALID_OPERATION;
+               goto error;
        }
 
-       g_signal_connect(decodebin, "autoplug-select", G_CALLBACK(__filesrc_decodebin_autoplug_select_cb), NULL);
-       g_signal_connect(decodebin, "pad-added", G_CALLBACK(__filesrc_decodebin_pad_added_cb), (gpointer)source);
-       g_signal_connect(decodebin, "pad-removed", G_CALLBACK(__filesrc_decodebin_pad_removed_cb), (gpointer)source);
+       g_signal_connect(decodebin, "autoplug-select", G_CALLBACK(__filesrc_pipeline_decodebin_autoplug_select_cb), NULL);
+       g_signal_connect(decodebin, "pad-added", G_CALLBACK(__filesrc_pipeline_decodebin_pad_added_cb), (gpointer)source);
+       g_signal_connect(decodebin, "pad-removed", G_CALLBACK(__filesrc_pipeline_decodebin_pad_removed_cb), (gpointer)source);
 
        return WEBRTC_ERROR_NONE;
+
+error:
+       __destroy_filesrc_pipeline(source);
+       return WEBRTC_ERROR_INVALID_OPERATION;
+
 }
 
 static void _appsrc_need_data_cb(GstElement *appsrc, guint size, gpointer data)
@@ -2135,7 +2329,7 @@ static int __build_source_bin(webrtc_s *webrtc, webrtc_gst_slot_s *source)
                return __build_screensrc(webrtc, source);
 
        case WEBRTC_MEDIA_SOURCE_TYPE_FILE:
-               return __build_filesrc(webrtc, source);
+               return __build_filesrc_pipeline(webrtc, source);
 
        case WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET:
                return __build_mediapacketsrc(webrtc, source);
@@ -2238,6 +2432,9 @@ void _source_slot_destroy_cb(gpointer data)
        if (source->sound_stream_info.type)
                free(source->sound_stream_info.type);
 
+       if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_FILE)
+               __destroy_filesrc_pipeline(source);
+
        g_free(source);
 }
 
@@ -2778,28 +2975,42 @@ bool _check_if_format_is_set_to_packet_sources(webrtc_s *webrtc)
 
 static void __remove_filesrc_element(webrtc_gst_slot_s *source)
 {
+       GstBin *bin = NULL;
        GstElement *payload = NULL;
-       GstElement *queue = NULL;
        GstElement *capsfilter = NULL;
+       GstElement *fakesink = NULL;
 
-       payload = gst_bin_get_by_name(source->bin, DEFAULT_NAME_AUDIO_PAYLOAD);
+       RET_IF(source == NULL, "source is NULL");
+       RET_IF(source->filesrc_pipeline == NULL, "filesrc_pipeline is NULL");
+
+       bin = GST_BIN(source->filesrc_pipeline);
+
+       payload = gst_bin_get_by_name(bin, DEFAULT_NAME_AUDIO_PAYLOAD);
        if (payload) {
-               queue = gst_bin_get_by_name(source->bin, DEFAULT_NAME_AUDIO_QUEUE);
-               capsfilter = gst_bin_get_by_name(source->bin, DEFAULT_NAME_AUDIO_CAPSFILTER);
-               gst_bin_remove_many(source->bin, payload, queue, capsfilter, NULL);
+               capsfilter = gst_bin_get_by_name(bin, DEFAULT_NAME_AUDIO_CAPSFILTER);
+               fakesink = gst_bin_get_by_name(bin, DEFAULT_NAME_AUDIO_FAKESINK);
+               gst_bin_remove_many(bin, payload, capsfilter, fakesink, NULL);
+
+               if (source->av[AV_IDX_AUDIO].payload_id > 0)
+                       __return_payload_id(source->webrtc, source->av[AV_IDX_AUDIO].payload_id);
 
                __remove_probe_from_pad_for_pause(source, AV_IDX_AUDIO);
        }
 
-       payload = gst_bin_get_by_name(source->bin, DEFAULT_NAME_VIDEO_PAYLOAD);
+       payload = gst_bin_get_by_name(bin, DEFAULT_NAME_VIDEO_PAYLOAD);
        if (payload) {
-               queue = gst_bin_get_by_name(source->bin, DEFAULT_NAME_VIDEO_QUEUE);
-               capsfilter = gst_bin_get_by_name(source->bin, DEFAULT_NAME_VIDEO_CAPSFILTER);
-               gst_bin_remove_many(source->bin, payload, queue, capsfilter, NULL);
+               capsfilter = gst_bin_get_by_name(bin, DEFAULT_NAME_VIDEO_CAPSFILTER);
+               fakesink = gst_bin_get_by_name(bin, DEFAULT_NAME_VIDEO_FAKESINK);
+               gst_bin_remove_many(bin, payload, capsfilter, fakesink, NULL);
+
+               if (source->av[AV_IDX_VIDEO].payload_id > 0)
+                       __return_payload_id(source->webrtc, source->av[AV_IDX_VIDEO].payload_id);
 
                __remove_probe_from_pad_for_pause(source, AV_IDX_VIDEO);
        }
 
+       /* FIXME: filesrc_bin should be updated as well */
+
        source->media_types = 0;
 }
 
@@ -2825,7 +3036,7 @@ int _set_media_path(webrtc_s *webrtc, unsigned int source_id, const char *path)
                }
        }
 
-       filesrc = gst_bin_get_by_name(source->bin, DEFAULT_NAME_FILE_SRC);
+       filesrc = gst_bin_get_by_name(GST_BIN(source->filesrc_pipeline), DEFAULT_NAME_FILE_SRC);
        RET_VAL_IF(filesrc == NULL, WEBRTC_ERROR_INVALID_OPERATION, "filesrc is NULL");
 
        g_object_get(G_OBJECT(filesrc), "location", &location, NULL);
@@ -2843,12 +3054,12 @@ int _set_media_path(webrtc_s *webrtc, unsigned int source_id, const char *path)
 
 static gboolean __check_path_is_not_set_cb(gpointer key, gpointer value, gpointer user_data)
 {
-       webrtc_gst_slot_s *source = value;
+       webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)value;
        gchar *location = NULL;
 
        if (source->type == GPOINTER_TO_INT(user_data)) {
                LOG_INFO("found file source[%p, id:%u]", source, source->id);
-               g_object_get(G_OBJECT(gst_bin_get_by_name(source->bin, DEFAULT_NAME_FILE_SRC)), "location", &location, NULL);
+               g_object_get(G_OBJECT(gst_bin_get_by_name(GST_BIN(source->filesrc_pipeline), DEFAULT_NAME_FILE_SRC)), "location", &location, NULL);
 
                if (!location)
                        return TRUE;
@@ -3933,3 +4144,32 @@ int _unset_screen_source_crop(webrtc_s *webrtc, unsigned int source_id)
 
        return WEBRTC_ERROR_NONE;
 }
+
+static void __set_filesrc_pipline_state_foreach_cb(gpointer key, gpointer value, gpointer user_data)
+{
+       webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)value;
+       GstStateChangeReturn ret;
+       GstState state = GPOINTER_TO_UINT(user_data);
+
+       if (source->type != WEBRTC_MEDIA_SOURCE_TYPE_FILE)
+               return;
+
+       LOG_INFO("found file source[%p, id:%u]", source, source->id);
+
+       ret = gst_element_set_state(source->filesrc_pipeline, state);
+       if (ret == GST_STATE_CHANGE_FAILURE) {
+               LOG_ERROR("failed to gst_element_set_state(), state[%s]", gst_element_state_get_name(state));
+               return;
+       }
+
+       LOG_INFO("change pipeline state to [%s]", gst_element_state_get_name(state));
+}
+
+int _gst_filesrc_pipeline_set_state(webrtc_s *webrtc, GstState state)
+{
+       RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+
+       g_hash_table_foreach(webrtc->gst.source_slots, __set_filesrc_pipline_state_foreach_cb, GINT_TO_POINTER(state));
+
+       return WEBRTC_ERROR_NONE;
+}