+ // FIXME: it cause block during preparing
+ if ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player))) {
+ gint stype = 0;
+
+ mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
+ /* don't make video because of not required */
+ if ((stype == MM_DISPLAY_SURFACE_NULL) &&
+ (!player->set_mode.video_export)) {
+ LOGD("no need video decoding, skip video stream");
+ return RET_SKIP;
+ }
+ }
+
+ if (caps_structure) {
+ gint width = 0;
+
+ gst_structure_get_int(caps_structure, "width", &width);
+ if (width != 0) {
+ if (player->v_stream_caps) {
+ gst_caps_unref(player->v_stream_caps);
+ player->v_stream_caps = NULL;
+ }
+
+ player->v_stream_caps = gst_caps_copy(caps);
+ MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
+ }
+ }
+ break;
+ }
+ case GST_STREAM_TYPE_TEXT:
+ break;
+ default:
+ LOGW("Skip not supported stream type");
+ return RET_SKIP;
+ }
+
+ _mmplayer_track_update_stream(player, type, stream);
+
+ ret = _mmplayer_get_track_index(player, type, stream, &stream_index);
+
+ if ((player->track[type].active_track_index == INVALID_TRACK_INDEX) &&
+ (ret == MM_ERROR_NONE)) {
+ player->track[type].active_track_index = stream_index;
+ LOGD("select this stream, active track idx : %d", player->track[type].active_track_index);
+ if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
+ _mmplayer_set_audio_attrs(player, caps);
+ return RET_SELECT;
+ }
+
+ if (player->track[type].active_track_index == stream_index) {
+ LOGD("already activate track idx : %d", player->track[type].active_track_index);
+ return RET_SELECT;
+ }
+
+ LOGD("Skip stream");
+ return RET_SKIP;
+}
+
+static gboolean
+__mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
+ GstStream * stream, gpointer data)
+{
+ mmplayer_t *player = (mmplayer_t *)data;
+ GstStreamType stype = gst_stream_get_stream_type(stream);
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
+
+ LOGD("stream type %s", gst_stream_type_get_name(stype));
+
+ /* public does not support audio hw decoder at the moment */
+
+ if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
+ LOGW("video decoder resource is already acquired, skip it.");
+ return TRUE;
+ }
+
+ if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
+ LOGE("failed to acquire video decoder resource");
+ return FALSE;
+ }
+ player->interrupted_by_resource = FALSE;
+ MMPLAYER_FLEAVE();
+ return TRUE;
+}
+
+static GstElement *
+__mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
+{
+ GstIterator *iter = NULL;
+ GValue item = {0, };
+ GstElement *ch_element = NULL;
+ GstElementFactory *ch_factory = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
+
+ iter = gst_bin_iterate_recurse(bin);
+ MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
+
+ while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
+ ch_element = g_value_get_object(&item);
+ ch_factory = gst_element_get_factory(ch_element);
+ LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
+ if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
+ LOGD("Find %s element", element_name);
+ break;
+ }
+ ch_element = NULL;
+ g_value_reset(&item);
+ }
+ gst_iterator_free(iter);
+
+ MMPLAYER_FLEAVE();
+ return ch_element;
+}
+
+static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
+{
+ mmplayer_t *player = (mmplayer_t *)data;
+
+ g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
+
+ _mmplayer_add_signal_connection(player, G_OBJECT(bin),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
+ G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
+
+ _mmplayer_add_signal_connection(player, G_OBJECT(bin),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
+ G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
+}
+
+static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
+{
+ mmplayer_t *player = (mmplayer_t *)data;
+ int video_codec_type = 0;
+ int audio_codec_type = 0;
+
+ g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
+
+ mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
+ mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
+
+ LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
+
+ if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
+ g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
+ if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
+ g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
+
+ _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
+ "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
+}
+
+static void
+__mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
+{
+ gchar *factory_name = NULL;
+ mmplayer_t *player = (mmplayer_t *)data;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
+
+ factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
+
+ LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
+
+ if (g_strrstr(factory_name, "urisourcebin")) {
+ GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
+ if (dbin3) {
+ GstElement *mq = __mmplayer_gst_find_child_element(child, "multiqueue");
+ if (mq)
+ g_object_set(G_OBJECT(mq), "use-interleave", FALSE, NULL);
+
+ __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
+ } else {
+ LOGW("failed to find decodebin3");
+ }
+ } else if (g_strrstr(factory_name, "parsebin")) {
+ g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
+ __mmplayer_parsebin_setup(GST_BIN(element), data);
+ } else {
+ _mmplayer_gst_element_added(child, element, data);
+ }
+}
+
+static void
+__mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
+{
+ MMPLAYER_FENTER();
+
+ MMPLAYER_RETURN_IF_FAIL(player);
+ MMPLAYER_RETURN_IF_FAIL(removed_element);
+
+ LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
+
+ for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
+ GList *node = player->signals[type];
+ while (node) {
+ GList *next_node = node->next;
+ mmplayer_signal_item_t *item = node->data;
+ if (item && item->obj == G_OBJECT(removed_element)) {
+ player->signals[type] = g_list_delete_link(player->signals[type], node);
+ MMPLAYER_FREEIF(item);
+ }
+ node = next_node;
+ }
+ }
+
+ MMPLAYER_FLEAVE();
+}
+
+void
+__mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
+{
+ mmplayer_t *player = (mmplayer_t *)data;
+
+ MMPLAYER_FENTER();
+
+ MMPLAYER_RETURN_IF_FAIL(player);
+
+ LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
+
+ __mmplayer_delete_signal_connection(player, element);
+
+ MMPLAYER_FLEAVE();
+}
+
+static GstElement *
+__mmplayer_gst_make_uridecodebin(mmplayer_t *player)
+{
+ GstElement *uridecodebin3 = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
+
+ uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
+ if (!uridecodebin3) {
+ LOGE("failed to create uridecodebin3");
+ return NULL;
+ }
+
+ /* get attribute */
+ SECURE_LOGD("uri : %s", player->profile.uri);
+
+ /* setting property to streaming source */
+ g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
+ "message-forward", TRUE,
+ "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
+ "use-buffering", TRUE, NULL);
+
+ _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
+
+ _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
+
+ _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
+
+ _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
+
+ _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
+
+ _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
+
+ _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
+
+ _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
+
+ if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
+ LOGW("[DASH] this is still experimental feature");
+
+ MMPLAYER_FLEAVE();
+ return uridecodebin3;
+}
+
+static GstElement *
+__mmplayer_gst_make_http_src(mmplayer_t *player)
+{
+#define MAX_RETRY_COUNT 10
+ GstElement *element = NULL;
+ MMHandleType attrs = 0;
+ gchar *user_agent, *cookies, **cookie_list;
+ gint http_timeout = DEFAULT_HTTP_TIMEOUT;
+
+ user_agent = cookies = NULL;
+ cookie_list = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
+
+ /* get profile attribute */
+ attrs = MMPLAYER_GET_ATTRS(player);
+ if (!attrs) {
+ LOGE("failed to get content attribute");
+ return NULL;
+ }
+
+ LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
+
+ element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
+ if (!element) {
+ LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
+ return NULL;
+ }
+
+ /* get attribute */
+ mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
+ mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
+
+ if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
+ http_timeout = player->ini.http_timeout;
+
+ /* get attribute */
+ SECURE_LOGD("location : %s", player->profile.uri);
+ SECURE_LOGD("cookies : %s", cookies);
+ SECURE_LOGD("user_agent : %s", user_agent);
+ LOGD("timeout : %d", http_timeout);
+
+ /* setting property to streaming source */
+ g_object_set(G_OBJECT(element), "location", player->profile.uri,
+ "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
+ "retries", MAX_RETRY_COUNT, NULL);
+
+ /* parsing cookies */
+ if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
+ g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
+ g_strfreev(cookie_list);
+ }
+
+ if (user_agent)
+ g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
+
+ if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
+ LOGW("[DASH] this is still experimental feature");
+
+ MMPLAYER_FLEAVE();
+ return element;
+}
+
+static GstElement *
+__mmplayer_gst_make_file_src(mmplayer_t *player)
+{
+ GstElement *element = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
+
+ LOGD("using filesrc for 'file://' handler");
+ if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
+ LOGE("failed to get storage info");
+ return NULL;
+ }
+
+ element = gst_element_factory_make("filesrc", "source");
+ if (!element) {
+ LOGE("failed to create filesrc");
+ return NULL;
+ }
+
+ g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
+
+ MMPLAYER_FLEAVE();
+ return element;
+}
+
+static gboolean
+__mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
+{
+ mmplayer_t *player = (mmplayer_t *)data;
+
+ g_return_val_if_fail(player, FALSE);
+ g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
+ gst_message_ref(msg);
+
+ g_mutex_lock(&player->bus_msg_q_lock);
+ g_queue_push_tail(player->bus_msg_q, msg);
+ g_mutex_unlock(&player->bus_msg_q_lock);
+
+ MMPLAYER_BUS_MSG_THREAD_LOCK(player);
+ MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
+ MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
+ return TRUE;
+}
+
+static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
+{
+ mmplayer_t *player = (mmplayer_t *)(data);
+ GstMessage *msg = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player &&
+ player->pipeline &&
+ player->pipeline->mainbin &&
+ player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
+ NULL);
+
+ MMPLAYER_BUS_MSG_THREAD_LOCK(player);
+
+ LOGD("[handle: %p] gst bus msg thread will be started.", player);
+ while (!player->bus_msg_thread_exit) {
+ g_mutex_lock(&player->bus_msg_q_lock);
+ msg = g_queue_pop_head(player->bus_msg_q);
+ g_mutex_unlock(&player->bus_msg_q_lock);
+ if (msg == NULL) {
+ MMPLAYER_BUS_MSG_THREAD_WAIT(player);
+ continue;
+ }
+ MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
+ /* handle the gst msg */
+ __mmplayer_gst_bus_msg_callback(msg, player);
+ MMPLAYER_BUS_MSG_THREAD_LOCK(player);
+ gst_message_unref(msg);
+ }
+
+ MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
+ MMPLAYER_FLEAVE();