#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 { \
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");
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)
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,
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");
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;
__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);
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;
}
}
-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;
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)
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);
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);
}
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;
}
}
}
- 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);
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;
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;
+}