#include <dlog.h>
#include <mm_error.h>
#include <mm_attrs_private.h>
+#include <gst/app/gstappsrc.h>
#include "mm_player_gst.h"
#include "mm_player_priv.h"
return;
}
-
-#if 0
-#endif
-
-int
-__mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
-{
- GstState element_state = GST_STATE_VOID_PENDING;
- GstState element_pending_state = GST_STATE_VOID_PENDING;
- GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
-
- MMPLAYER_FENTER();
-
- MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
- MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
-
- LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
-
- /* set state */
- ret = gst_element_set_state(element, state);
-
- if (ret == GST_STATE_CHANGE_FAILURE) {
- LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
-
- /* dump state of all element */
- __mmplayer_dump_pipeline_state(player);
-
- return MM_ERROR_PLAYER_INTERNAL;
- }
-
- /* return here so state transition to be done in async mode */
- if (async) {
- LOGD("async state transition. not waiting for state complete.\n");
- return MM_ERROR_NONE;
- }
-
- /* wait for state transition */
- ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
-
- if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
- LOGE("failed to change [%s] element state to [%s] within %d sec\n",
- GST_ELEMENT_NAME(element),
- gst_element_state_get_name(state), timeout);
-
- LOGE(" [%s] state : %s pending : %s \n",
- GST_ELEMENT_NAME(element),
- gst_element_state_get_name(element_state),
- gst_element_state_get_name(element_pending_state));
-
- /* dump state of all element */
- __mmplayer_dump_pipeline_state(player);
-
- return MM_ERROR_PLAYER_INTERNAL;
- }
-
- LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
-
- MMPLAYER_FLEAVE();
-
- return MM_ERROR_NONE;
-}
-
-void
+static void
__mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
{
mm_player_t* player = (mm_player_t*)(data);
break;
}
- /* should not call 'gst_message_unref(msg)' */
- return;
-}
+ /* should not call 'gst_message_unref(msg)' */
+ return;
+}
+
+static GstBusSyncReply
+__mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
+{
+ mm_player_t *player = (mm_player_t *)data;
+ GstBusSyncReply reply = GST_BUS_DROP;
+
+ if (!(player->pipeline && player->pipeline->mainbin)) {
+ LOGE("player pipeline handle is null");
+ return GST_BUS_PASS;
+ }
+
+ if (!__mmplayer_gst_check_useful_message(player, message)) {
+ gst_message_unref(message);
+ return GST_BUS_DROP;
+ }
+
+ switch (GST_MESSAGE_TYPE(message)) {
+ case GST_MESSAGE_STATE_CHANGED:
+ /* post directly for fast launch */
+ if (player->sync_handler) {
+ __mmplayer_gst_bus_msg_callback(message, player);
+ reply = GST_BUS_DROP;
+ } else
+ reply = GST_BUS_PASS;
+ break;
+ case GST_MESSAGE_TAG:
+ __mmplayer_gst_extract_tag_from_msg(player, message);
+
+ #if 0 // debug
+ {
+ GstTagList *tags = NULL;
+
+ gst_message_parse_tag(message, &tags);
+ if (tags) {
+ LOGE("TAGS received from element \"%s\".\n",
+ GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
+
+ gst_tag_list_foreach(tags, print_tag, NULL);
+ gst_tag_list_free(tags);
+ tags = NULL;
+ }
+ break;
+ }
+ #endif
+ break;
+
+ case GST_MESSAGE_DURATION_CHANGED:
+ __mmplayer_gst_handle_duration(player, message);
+ break;
+ case GST_MESSAGE_ASYNC_DONE:
+ /* NOTE:Don't call gst_callback directly
+ * because previous frame can be showed even though this message is received for seek.
+ */
+ default:
+ reply = GST_BUS_PASS;
+ break;
+ }
+
+ if (reply == GST_BUS_DROP)
+ gst_message_unref(message);
+
+ return reply;
+}
+
+static void
+__mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
+{
+ GstElement *appsrc = element;
+ MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
+ GstBuffer *buffer = NULL;
+ GstFlowReturn ret = GST_FLOW_OK;
+ gint len = size;
+
+ MMPLAYER_RETURN_IF_FAIL(element);
+ MMPLAYER_RETURN_IF_FAIL(buf);
+
+ buffer = gst_buffer_new();
+
+ if (buf->offset < 0 || buf->len < 0) {
+ LOGE("invalid buf info %d %d", buf->offset, buf->len);
+ return;
+ }
+
+ if (buf->offset >= buf->len) {
+ LOGD("call eos appsrc");
+ g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
+ return;
+ }
+
+ if (buf->len - buf->offset < size)
+ len = buf->len - buf->offset;
+
+ gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
+ GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
+ GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
+
+ //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
+ g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
+
+ buf->offset += len;
+}
+
+static gboolean
+__mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
+{
+ MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
+
+ MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
+
+ buf->offset = (int)size;
+
+ return TRUE;
+}
+
+void
+__mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
+{
+ mm_player_t *player = (mm_player_t*)user_data;
+ MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
+ guint64 current_level_bytes = 0;
+
+ MMPLAYER_RETURN_IF_FAIL(player);
+
+ if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
+ type = MM_PLAYER_STREAM_TYPE_AUDIO;
+ else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
+ type = MM_PLAYER_STREAM_TYPE_VIDEO;
+ else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
+ type = MM_PLAYER_STREAM_TYPE_TEXT;
+ else {
+ LOGE("can not enter here");
+ return;
+ }
+
+ g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
+
+ LOGI("type: %d, level: %llu", type, current_level_bytes);
+
+ MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
+ if (player->media_stream_buffer_status_cb[type])
+ player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
+ MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
+}
+
+void
+__mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
+{
+ mm_player_t *player = (mm_player_t*)user_data;
+ MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
+ guint64 current_level_bytes = 0;
+
+ MMPLAYER_RETURN_IF_FAIL(player);
+
+ if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
+ type = MM_PLAYER_STREAM_TYPE_AUDIO;
+ else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
+ type = MM_PLAYER_STREAM_TYPE_VIDEO;
+ else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
+ type = MM_PLAYER_STREAM_TYPE_TEXT;
+ else {
+ LOGE("can not enter here");
+ return;
+ }
+
+ LOGI("type: %d, buffer is full", type);
+
+ g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
+
+ MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
+
+ if (player->media_stream_buffer_status_cb[type])
+ player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
+
+ MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
+}
+
+gboolean
+__mmplayer_gst_appsrc_seek_data(GstElement * element, guint64 position, gpointer user_data)
+{
+ mm_player_t *player = (mm_player_t*)user_data;
+ MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
+
+ MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
+
+ if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
+ type = MM_PLAYER_STREAM_TYPE_AUDIO;
+ else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
+ type = MM_PLAYER_STREAM_TYPE_VIDEO;
+ else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
+ type = MM_PLAYER_STREAM_TYPE_TEXT;
+ else {
+ LOGE("can not enter here");
+ return TRUE;
+ }
+
+ LOGD("type: %d, pos: %llu", type, position);
+ MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
+
+ if (player->media_stream_seek_data_cb[type])
+ player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
+ MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
+
+ return TRUE;
+}
+
+static gboolean
+__mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad* srcpad)
+{
+#define MAX_LEN_NAME 20
+
+ gboolean ret = FALSE;
+ GstPad *sinkpad = NULL;
+ gchar *prefix = NULL;
+ gchar dec_name[MAX_LEN_NAME] = {0};
+ enum MainElementID elem_id = MMPLAYER_M_NUM;
+
+ MMPlayerGstElement *mainbin = NULL;
+ GstElement *decodebin = NULL;
+ GstCaps *dec_caps = NULL;
+
+ MMPLAYER_FENTER();
+
+ MMPLAYER_RETURN_VAL_IF_FAIL(player &&
+ player->pipeline &&
+ player->pipeline->mainbin, FALSE);
+ MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
+
+ mainbin = player->pipeline->mainbin;
+ switch (type) {
+ case MM_PLAYER_STREAM_TYPE_AUDIO:
+ prefix = "audio";
+ elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
+ break;
+ case MM_PLAYER_STREAM_TYPE_VIDEO:
+ prefix = "video";
+ elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
+ break;
+ default:
+ LOGE("invalid type %d", type);
+ return FALSE;
+ }
+
+ if (mainbin[elem_id].gst) {
+ LOGE("elem(%d) is already created", elem_id);
+ return FALSE;
+ }
+
+ snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
+
+ /* create decodebin */
+ decodebin = gst_element_factory_make("decodebin", dec_name);
+ if (!decodebin) {
+ LOGE("failed to create %s", dec_name);
+ return FALSE;
+ }
+
+ mainbin[elem_id].id = elem_id;
+ mainbin[elem_id].gst = decodebin;
+
+ /* raw pad handling signal */
+ __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
+ G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
+
+ /* This signal is emitted whenever decodebin finds a new stream. It is emitted
+ before looking for any elements that can handle that stream.*/
+ __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
+ G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
+
+ /* This signal is emitted when a element is added to the bin.*/
+ __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
+ G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
+
+ if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
+ LOGE("failed to add new decodebin");
+ return FALSE;
+ }
+
+ dec_caps = gst_pad_query_caps(srcpad, NULL);
+ if (dec_caps) {
+ //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
+ g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
+ gst_caps_unref(dec_caps);
+ }
+
+ sinkpad = gst_element_get_static_pad(decodebin, "sink");
+
+ if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
+ LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
+ goto ERROR;
+ }
+ gst_object_unref(GST_OBJECT(sinkpad));
+
+ gst_element_sync_state_with_parent(decodebin);
+ MMPLAYER_FLEAVE();
+ return TRUE;
+
+ERROR:
+ if (sinkpad)
+ gst_object_unref(GST_OBJECT(sinkpad));
+
+ if (mainbin[elem_id].gst) {
+ gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
+ gst_object_unref(mainbin[elem_id].gst);
+ mainbin[elem_id].gst = NULL;
+ }
+
+ MMPLAYER_FLEAVE();
+ return ret;
+}
+
+static gboolean
+__mmplayer_gst_create_es_path(mm_player_t* player, MMPlayerStreamType type, GstCaps* caps)
+{
+#define MAX_LEN_NAME 20
+ MMPlayerGstElement *mainbin = NULL;
+ gchar *prefix = NULL;
+ enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
+
+ gchar src_name[MAX_LEN_NAME] = {0}, queue_name[MAX_LEN_NAME] = {0};
+ GstElement *src = NULL, *queue = NULL;
+ GstPad *srcpad = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
+ player->pipeline->mainbin, FALSE);
+
+ mainbin = player->pipeline->mainbin;
+
+ LOGD("type(%d) path is creating", type);
+ switch (type) {
+ case MM_PLAYER_STREAM_TYPE_AUDIO:
+ prefix = "audio";
+ if (mainbin[MMPLAYER_M_SRC].gst)
+ src_id = MMPLAYER_M_2ND_SRC;
+ else
+ src_id = MMPLAYER_M_SRC;
+ queue_id = MMPLAYER_M_A_BUFFER;
+ break;
+ case MM_PLAYER_STREAM_TYPE_VIDEO:
+ prefix = "video";
+ src_id = MMPLAYER_M_SRC;
+ queue_id = MMPLAYER_M_V_BUFFER;
+ break;
+ case MM_PLAYER_STREAM_TYPE_TEXT:
+ prefix = "subtitle";
+ src_id = MMPLAYER_M_SUBSRC;
+ queue_id = MMPLAYER_M_S_BUFFER;
+ break;
+ default:
+ LOGE("invalid type %d", type);
+ return FALSE;
+ }
+
+ snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
+ snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
+
+ /* create source */
+ src = gst_element_factory_make("appsrc", src_name);
+ if (!src) {
+ LOGF("failed to create %s", src_name);
+ goto ERROR;
+ }
+
+ mainbin[src_id].id = src_id;
+ mainbin[src_id].gst = src;
+
+ g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
+ "caps", caps, NULL);
+
+ /* size of many video frames are larger than default blocksize as 4096 */
+ if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
+ g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
+
+ if (player->media_stream_buffer_max_size[type] > 0)
+ g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
+
+ if (player->media_stream_buffer_min_percent[type] > 0)
+ g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
+
+ /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
+ gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
+
+ __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
+ G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
+ G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
+ G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
+
+ /* create queue */
+ queue = gst_element_factory_make("queue2", queue_name);
+ if (!queue) {
+ LOGE("failed to create %s", queue_name);
+ goto ERROR;
+ }
+ g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
+
+ mainbin[queue_id].id = queue_id;
+ mainbin[queue_id].gst = queue;
+
+ if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
+ LOGE("failed to add src");
+ goto ERROR;
+ }
+
+ if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
+ LOGE("failed to add queue");
+ goto ERROR;
+ }
+
+ if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
+ LOGE("failed to link src and queue");
+ goto ERROR;
+ }
+
+ /* create decoder */
+ srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
+ if (!srcpad) {
+ LOGE("failed to get srcpad of queue");
+ goto ERROR;
+ }
+
+ if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
+ __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
+ } else {
+ if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
+ LOGE("failed to create decoder");
+ gst_object_unref(GST_OBJECT(srcpad));
+ goto ERROR;
+ }
+ }
+ gst_object_unref(GST_OBJECT(srcpad));
+ return TRUE;
+
+ERROR:
+ if (mainbin[src_id].gst) {
+ gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
+ gst_object_unref(mainbin[src_id].gst);
+ mainbin[src_id].gst = NULL;
+ }
+
+ if (mainbin[queue_id].gst) {
+ gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
+ gst_object_unref(mainbin[queue_id].gst);
+ mainbin[queue_id].gst = NULL;
+ }
+
+ return FALSE;
+}
+
+static void
+__mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
+{
+ GstPad *sinkpad = NULL;
+ GstCaps* caps = NULL;
+ GstElement* new_element = NULL;
+ GstStructure* str = NULL;
+ const gchar* name = NULL;
+
+ mm_player_t* player = (mm_player_t*) data;
+
+ MMPLAYER_FENTER();
+
+ MMPLAYER_RETURN_IF_FAIL(element && pad);
+ MMPLAYER_RETURN_IF_FAIL(player &&
+ player->pipeline &&
+ player->pipeline->mainbin);
+
+
+ /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
+ * num_dynamic_pad will decreased after creating a sinkbin.
+ */
+ player->num_dynamic_pad++;
+ LOGD("stream count inc : %d\n", player->num_dynamic_pad);
+
+ caps = gst_pad_query_caps(pad, NULL);
+
+ MMPLAYER_CHECK_NULL(caps);
+
+ /* clear previous result*/
+ player->have_dynamic_pad = FALSE;
+
+ str = gst_caps_get_structure(caps, 0);
+
+ if (!str) {
+ LOGE("cannot get structure from caps.\n");
+ goto ERROR;
+ }
+
+ name = gst_structure_get_name(str);
+ if (!name) {
+ LOGE("cannot get mimetype from structure.\n");
+ goto ERROR;
+ }
+
+ if (strstr(name, "video")) {
+ gint stype = 0;
+ mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
+
+ if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
+ if (player->v_stream_caps) {
+ gst_caps_unref(player->v_stream_caps);
+ player->v_stream_caps = NULL;
+ }
+
+ new_element = gst_element_factory_make("fakesink", NULL);
+ player->num_dynamic_pad--;
+ goto NEW_ELEMENT;
+ }
+ }
+
+ /* clear previous result*/
+ player->have_dynamic_pad = FALSE;
+
+ if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
+ LOGE("failed to autoplug for caps");
+ goto ERROR;
+ }
+
+ /* check if there's dynamic pad*/
+ if (player->have_dynamic_pad) {
+ LOGE("using pad caps assums there's no dynamic pad !\n");
+ goto ERROR;
+ }
+
+ gst_caps_unref(caps);
+ caps = NULL;
+
+NEW_ELEMENT:
+
+ /* excute new_element if created*/
+ if (new_element) {
+ LOGD("adding new element to pipeline\n");
+
+ /* set state to READY before add to bin */
+ MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
+
+ /* add new element to the pipeline */
+ if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
+ LOGE("failed to add autoplug element to bin\n");
+ goto ERROR;
+ }
+
+ /* get pad from element */
+ sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
+ if (!sinkpad) {
+ LOGE("failed to get sinkpad from autoplug element\n");
+ goto ERROR;
+ }
+
+ /* link it */
+ if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
+ LOGE("failed to link autoplug element\n");
+ goto ERROR;
+ }
+
+ gst_object_unref(sinkpad);
+ sinkpad = NULL;
+
+ /* run. setting PLAYING here since streamming source is live source */
+ MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
+ }
+
+ if (caps)
+ gst_caps_unref(caps);
+
+ MMPLAYER_FLEAVE();
+
+ return;
+
+STATE_CHANGE_FAILED:
+ERROR:
+ /* FIXIT : take care if new_element has already added to pipeline */
+ if (new_element)
+ gst_object_unref(GST_OBJECT(new_element));
+
+ if (sinkpad)
+ gst_object_unref(GST_OBJECT(sinkpad));
+
+ if (caps)
+ gst_caps_unref(caps);
+
+ /* FIXIT : how to inform this error to MSL ????? */
+ /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
+ * then post an error to application
+ */
+}
+
+static void
+__mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
+{
+ mm_player_t* player = (mm_player_t*) data;
+
+ MMPLAYER_FENTER();
+
+ /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
+ * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
+ * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
+ * So we can say this. if num_dynamic_pad is zero, it must be one of followings
+
+ * [1] audio and video will be dumped with filesink.
+ * [2] autoplugging is done by just using pad caps.
+ * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
+ * and the video will be dumped via filesink.
+ */
+ if (player->num_dynamic_pad == 0) {
+ LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
+
+ if (!__mmplayer_gst_remove_fakesink(player,
+ &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
+ /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
+ * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
+ * source element are not same. To overcome this situation, this function will called
+ * several places and several times. Therefore, this is not an error case.
+ */
+ return;
+ }
+
+ /* create dot before error-return. for debugging */
+ MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
+
+ player->no_more_pad = TRUE;
+
+ MMPLAYER_FLEAVE();
+}
+
+static GstElement*
+__mmplayer_gst_create_rtsp_src(mm_player_t* player)
+{
+ GstElement* element = NULL;
+ gchar *user_agent = NULL;
+ MMHandleType attrs = 0;
+
+ 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;
+ }
+
+ element = gst_element_factory_make("rtspsrc", "rtsp source");
+ if (!element) {
+ LOGE("failed to create rtspsrc element");
+ return NULL;
+ }
+
+ /* get attribute */
+ mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
+
+ SECURE_LOGD("user_agent : %s", user_agent);
+
+ /* setting property to streaming source */
+ g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
+ if (user_agent)
+ g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
+
+ __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
+ G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
+ G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
+
+ MMPLAYER_FLEAVE();
+ return element;
+}
+
+static GstElement*
+__mmplayer_gst_create_http_src(mm_player_t* player)
+{
+ 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 streamming 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), NULL);
+
+ /* parsing cookies */
+ if ((cookie_list = util_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_create_file_src(mm_player_t* player)
+{
+ GstElement* element = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
+
+ LOGD("using filesrc for 'file://' handler");
+ if (!util_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)
+{
+ mm_player_t *player = (mm_player_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)
+{
+ mm_player_t *player = (mm_player_t*)(data);
+ GstMessage *msg = NULL;
+ GstBus *bus = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player &&
+ player->pipeline &&
+ player->pipeline->mainbin &&
+ player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
+ NULL);
+
+ bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
+ if (!bus) {
+ LOGE("cannot get BUS from the pipeline");
+ return 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);
+ gst_object_unref(GST_OBJECT(bus));
+
+ MMPLAYER_FLEAVE();
+ return NULL;
+}
+
+#if 0
+#endif
+
+int
+__mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
+{
+ GstState element_state = GST_STATE_VOID_PENDING;
+ GstState element_pending_state = GST_STATE_VOID_PENDING;
+ GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
+
+ MMPLAYER_FENTER();
+
+ MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
+ MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
+
+ LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
+
+ /* set state */
+ ret = gst_element_set_state(element, state);
+
+ if (ret == GST_STATE_CHANGE_FAILURE) {
+ LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
-GstBusSyncReply
-__mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
-{
- mm_player_t *player = (mm_player_t *)data;
- GstBusSyncReply reply = GST_BUS_DROP;
+ /* dump state of all element */
+ __mmplayer_dump_pipeline_state(player);
- if (!(player->pipeline && player->pipeline->mainbin)) {
- LOGE("player pipeline handle is null");
- return GST_BUS_PASS;
+ return MM_ERROR_PLAYER_INTERNAL;
}
- if (!__mmplayer_gst_check_useful_message(player, message)) {
- gst_message_unref(message);
- return GST_BUS_DROP;
+ /* return here so state transition to be done in async mode */
+ if (async) {
+ LOGD("async state transition. not waiting for state complete.\n");
+ return MM_ERROR_NONE;
}
- switch (GST_MESSAGE_TYPE(message)) {
- case GST_MESSAGE_STATE_CHANGED:
- /* post directly for fast launch */
- if (player->sync_handler) {
- __mmplayer_gst_bus_msg_callback(message, player);
- reply = GST_BUS_DROP;
- } else
- reply = GST_BUS_PASS;
- break;
- case GST_MESSAGE_TAG:
- __mmplayer_gst_extract_tag_from_msg(player, message);
+ /* wait for state transition */
+ ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
- #if 0 // debug
- {
- GstTagList *tags = NULL;
+ if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
+ LOGE("failed to change [%s] element state to [%s] within %d sec\n",
+ GST_ELEMENT_NAME(element),
+ gst_element_state_get_name(state), timeout);
- gst_message_parse_tag(message, &tags);
- if (tags) {
- LOGE("TAGS received from element \"%s\".\n",
- GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
+ LOGE(" [%s] state : %s pending : %s \n",
+ GST_ELEMENT_NAME(element),
+ gst_element_state_get_name(element_state),
+ gst_element_state_get_name(element_pending_state));
- gst_tag_list_foreach(tags, print_tag, NULL);
- gst_tag_list_free(tags);
- tags = NULL;
- }
- break;
- }
- #endif
- break;
+ /* dump state of all element */
+ __mmplayer_dump_pipeline_state(player);
- case GST_MESSAGE_DURATION_CHANGED:
- __mmplayer_gst_handle_duration(player, message);
- break;
- case GST_MESSAGE_ASYNC_DONE:
- /* NOTE:Don't call gst_callback directly
- * because previous frame can be showed even though this message is received for seek.
- */
- default:
- reply = GST_BUS_PASS;
- break;
+ return MM_ERROR_PLAYER_INTERNAL;
}
- if (reply == GST_BUS_DROP)
- gst_message_unref(message);
+ LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
- return reply;
+ MMPLAYER_FLEAVE();
+
+ return MM_ERROR_NONE;
}
int __mmplayer_gst_start(mm_player_t* player)
return MM_ERROR_NONE;
}
+int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
+{
+ MMHandleType attrs = 0;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
+ player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
+
+ /* get profile attribute */
+ attrs = MMPLAYER_GET_ATTRS(player);
+ if (!attrs) {
+ LOGE("failed to get content attribute");
+ return MM_ERROR_PLAYER_INTERNAL;
+ }
+
+ SECURE_LOGD("uri : %s", player->profile.uri);
+
+ mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
+ if (mmf_attrs_commit(attrs)) /* return -1 if error */
+ LOGE("failed to commit");
+
+ if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
+ return MM_ERROR_PLAYER_INTERNAL;
+
+ if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
+ return MM_ERROR_PLAYER_INTERNAL;
+
+ if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
+ return MM_ERROR_PLAYER_INTERNAL;
+
+ MMPLAYER_FLEAVE();
+ return MM_ERROR_NONE;
+}
+
+int __mmplayer_gst_build_pd_pipeline(mm_player_t* player)
+{
+ MMPlayerGstElement *mainbin = NULL;
+ GstElement *pd_src = NULL;
+ GstElement *pd_queue = NULL;
+ GstElement *pd_decodebin = NULL;
+ GList* element_bucket = NULL;
+ MMHandleType attrs = 0;
+ gchar *path = NULL;
+ gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
+ player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
+
+ /* get profile attribute */
+ attrs = MMPLAYER_GET_ATTRS(player);
+ if (!attrs) {
+ LOGE("failed to get content attribute");
+ return MM_ERROR_PLAYER_INTERNAL;
+ }
+
+ LOGD("http playback with progressive download : %d", player->pd_mode);
+
+ if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
+ mm_attrs_get_string_by_name(attrs, "pd_location", &path);
+ MMPLAYER_FREEIF(player->pd_file_save_path);
+
+ SECURE_LOGD("PD Location : %s", path);
+ if (!path) {
+ LOGE("filed to find pd location");
+ return MM_ERROR_PLAYER_INTERNAL;
+ }
+
+ if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
+ LOGE("failed to get storage info");
+ return MM_ERROR_PLAYER_INTERNAL;
+ }
+ player->pd_file_save_path = g_strdup(path);
+ }
+
+ pd_src = gst_element_factory_make("pdpushsrc", "PD pushsrc");
+ if (!pd_src) {
+ LOGE("failed to create PD push source");
+ return MM_ERROR_PLAYER_INTERNAL;
+ }
+
+ if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
+ g_object_set(G_OBJECT(pd_src), "location", player->pd_file_save_path, NULL);
+ else
+ g_object_set(G_OBJECT(pd_src), "location", player->profile.uri, NULL);
+
+ mainbin = player->pipeline->mainbin;
+
+ /* take source element */
+ mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
+ mainbin[MMPLAYER_M_SRC].gst = pd_src;
+ element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
+
+ /* setting queue */
+ LOGD("Picked queue2 element(pre buffer : %d ms)", pre_buffering_time);
+ pd_queue = gst_element_factory_make("queue2", "queue2");
+ if (!pd_queue) {
+ LOGE("failed to create pd buffer element");
+ goto ERROR;
+ }
+
+ /* take queue2 */
+ mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
+ mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = pd_queue;
+ element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
+
+ pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
+
+ player->streamer->is_pd_mode = TRUE;
+
+ __mm_player_streaming_set_queue2(player->streamer, pd_queue, TRUE,
+ player->ini.http_max_size_bytes, pre_buffering_time, 1.0,
+ player->ini.http_buffering_limit, MUXED_BUFFER_TYPE_MEM_QUEUE, NULL, 0);
+
+ pd_decodebin = __mmplayer_create_decodebin(player);
+ if (!pd_decodebin) {
+ LOGE("failed to create decodebin");
+ goto ERROR;
+ }
+
+ /* default size of mq in decodebin is 2M
+ * but it can cause blocking issue during seeking depends on content. */
+ g_object_set(G_OBJECT(pd_decodebin), "max-size-bytes", (5*1024*1024), NULL);
+
+ mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
+ mainbin[MMPLAYER_M_AUTOPLUG].gst = pd_decodebin;
+
+ element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
+
+ /* add elements to pipeline */
+ if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
+ LOGE("failed to add elements to pipeline");
+ goto ERROR;
+ }
+
+ /* linking elements in the bucket by added order. */
+ if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
+ LOGE("failed to link some elements");
+ goto ERROR;
+ }
+
+ g_list_free(element_bucket);
+
+ MMPLAYER_FLEAVE();
+ return MM_ERROR_NONE;
+
+ERROR:
+ MMPLAYER_FREEIF(player->pd_file_save_path);
+ g_list_free(element_bucket);
+
+ if (mainbin[MMPLAYER_M_SRC].gst)
+ gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
+
+ if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
+ gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst));
+
+ if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
+ gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
+
+ mainbin[MMPLAYER_M_SRC].gst = NULL;
+ mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
+ mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
+
+ return MM_ERROR_PLAYER_INTERNAL;
+}
+
+int __mmplayer_gst_build_pipeline(mm_player_t* player)
+{
+ MMPlayerGstElement *mainbin = NULL;
+ GstElement* src_elem = NULL;
+ GstElement *autoplug_elem = NULL;
+ GList* element_bucket = NULL;
+ MMHandleType attrs = 0;
+ enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
+ player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
+
+ /* get profile attribute */
+ attrs = MMPLAYER_GET_ATTRS(player);
+ if (!attrs) {
+ LOGE("failed to get content attribute");
+ return MM_ERROR_PLAYER_INTERNAL;
+ }
+
+ LOGD("uri type %d", player->profile.uri_type);
+
+ /* create source element */
+ switch (player->profile.uri_type) {
+ case MM_PLAYER_URI_TYPE_URL_RTSP:
+ src_elem = __mmplayer_gst_create_rtsp_src(player);
+ break;
+ case MM_PLAYER_URI_TYPE_URL_HTTP:
+ src_elem = __mmplayer_gst_create_http_src(player);
+ break;
+ case MM_PLAYER_URI_TYPE_FILE:
+ src_elem = __mmplayer_gst_create_file_src(player);
+ break;
+ case MM_PLAYER_URI_TYPE_SS:
+ {
+ gint http_timeout = DEFAULT_HTTP_TIMEOUT;
+ src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
+ if (!src_elem) {
+ LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
+ break;
+ }
+
+ if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
+ LOGD("get timeout from ini");
+ http_timeout = player->ini.http_timeout;
+ }
+
+ /* setting property to streaming source */
+ g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
+ }
+ break;
+ case MM_PLAYER_URI_TYPE_MEM:
+ {
+ guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
+
+ src_elem = gst_element_factory_make("appsrc", "mem-source");
+ if (!src_elem) {
+ LOGE("failed to create appsrc element");
+ break;
+ }
+
+ g_object_set(src_elem, "stream-type", stream_type,
+ "size", player->profile.input_mem.len, "blocksize", (guint64)20480, NULL);
+
+ __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
+ G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
+ __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
+ G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
+ }
+ break;
+ default:
+ LOGE("not support uri type");
+ break;
+ }
+
+ if (!src_elem) {
+ LOGE("failed to create source element");
+ return MM_ERROR_PLAYER_INTERNAL;
+ }
+
+ mainbin = player->pipeline->mainbin;
+
+ /* take source element */
+ LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
+
+ mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
+ mainbin[MMPLAYER_M_SRC].gst = src_elem;
+ element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
+
+ /* create next element for auto-plugging */
+ if (MMPLAYER_IS_HTTP_STREAMING(player)) {
+ autoplug_elem_id = MMPLAYER_M_TYPEFIND;
+ autoplug_elem = gst_element_factory_make("typefind", "typefinder");
+ if (!autoplug_elem) {
+ LOGE("failed to create typefind element");
+ goto ERROR;
+ }
+
+ __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
+ G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
+ } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
+ autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
+ autoplug_elem = __mmplayer_create_decodebin(player);
+ if (!autoplug_elem) {
+ LOGE("failed to create decodebin");
+ goto ERROR;
+ }
+
+ /* default size of mq in decodebin is 2M
+ * but it can cause blocking issue during seeking depends on content. */
+ g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
+ }
+
+ if (autoplug_elem) {
+ LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
+ mainbin[autoplug_elem_id].id = autoplug_elem_id;
+ mainbin[autoplug_elem_id].gst = autoplug_elem;
+
+ element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
+ }
+
+ /* add elements to pipeline */
+ if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
+ LOGE("failed to add elements to pipeline");
+ goto ERROR;
+ }
+
+ /* linking elements in the bucket by added order. */
+ if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
+ LOGE("failed to link some elements");
+ goto ERROR;
+ }
+
+ /* FIXME: need to check whether this is required or not. */
+ if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
+ /* create fakesink element for keeping the pipeline state PAUSED. if needed */
+ mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
+ mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
+
+ if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
+ LOGE("failed to create fakesink");
+ goto ERROR;
+ }
+ GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
+
+ /* take ownership of fakesink. we are reusing it */
+ gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
+
+ if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
+ LOGE("failed to add fakesink to bin");
+ gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
+ goto ERROR;
+ }
+ }
+
+ g_list_free(element_bucket);
+
+ MMPLAYER_FLEAVE();
+ return MM_ERROR_NONE;
+
+ERROR:
+ g_list_free(element_bucket);
+
+ if (mainbin[MMPLAYER_M_SRC].gst)
+ gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
+
+ if (mainbin[autoplug_elem_id].gst)
+ gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
+
+ if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
+ gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
+
+ mainbin[MMPLAYER_M_SRC].gst = NULL;
+ mainbin[autoplug_elem_id].gst = NULL;
+ mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
+
+ return MM_ERROR_PLAYER_INTERNAL;
+}
+
+int __mmplayer_gst_add_bus_watch(mm_player_t* player)
+{
+ GstBus *bus = NULL;
+ MMPlayerGstElement *mainbin = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
+ player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
+
+ mainbin = player->pipeline->mainbin;
+
+ /* connect bus callback */
+ bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
+ if (!bus) {
+ LOGE("cannot get bus from pipeline");
+ return MM_ERROR_PLAYER_INTERNAL;
+ }
+
+ player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
+ player->context.thread_default = g_main_context_get_thread_default();
+ if (player->context.thread_default == NULL) {
+ player->context.thread_default = g_main_context_default();
+ LOGD("thread-default context is the global default context");
+ }
+ LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
+
+ /* set sync handler to get tag synchronously */
+ gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
+ gst_object_unref(GST_OBJECT(bus));
+
+ /* create gst bus_msb_cb thread */
+ g_mutex_init(&player->bus_msg_thread_mutex);
+ g_cond_init(&player->bus_msg_thread_cond);
+ player->bus_msg_thread_exit = FALSE;
+ player->bus_msg_thread =
+ g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
+ if (!player->bus_msg_thread) {
+ LOGE("failed to create gst BUS msg thread");
+ g_mutex_clear(&player->bus_msg_thread_mutex);
+ g_cond_clear(&player->bus_msg_thread_cond);
+ return MM_ERROR_PLAYER_INTERNAL;
+ }
+
+ MMPLAYER_FLEAVE();
+ return MM_ERROR_NONE;
+}
+
+GstElement* __mmplayer_gst_build_source(mm_player_t* player)
+{
+ GstElement* element = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
+ player->pipeline->mainbin, NULL);
+
+ /* setup source for gapless play */
+ switch (player->profile.uri_type) {
+ /* file source */
+ case MM_PLAYER_URI_TYPE_FILE:
+ element = __mmplayer_gst_create_file_src(player);
+ break;
+ case MM_PLAYER_URI_TYPE_URL_HTTP:
+ element = __mmplayer_gst_create_http_src(player);
+ break;
+ default:
+ LOGE("not support uri type %d", player->profile.uri_type);
+ break;
+ }
+
+ if (!element) {
+ LOGE("failed to create source element");
+ return NULL;
+ }
+
+ MMPLAYER_FLEAVE();
+ return element;
+}
========================================================================================== */
#include <glib.h>
#include <gst/gst.h>
-#include <gst/app/gstappsrc.h>
#include <gst/video/videooverlay.h>
#include <gst/audio/gstaudiobasesink.h>
#include <unistd.h>
static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
-static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
-static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
-static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
-static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
-static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
-static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
-static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
static gboolean __mmplayer_is_midi_type(gchar* str_caps);
static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
-static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
-static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
static void __mmplayer_release_misc(mm_player_t* player);
static void __mmplayer_release_misc_post(mm_player_t* player);
static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
-static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
static void __mmplayer_release_dump_list(GList *dump_list);
-static int __gst_realize(mm_player_t* player);
-static int __gst_unrealize(mm_player_t* player);
-static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
-static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
+static int __mmplayer_gst_realize(mm_player_t* player);
+static int __mmplayer_gst_unrealize(mm_player_t* player);
+static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
+static int __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
/* util */
static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
-static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
-static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
-static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
-static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
-static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
-static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
-static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
-static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
MMPLAYER_FLEAVE();
}
-gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
-{
- mm_player_t *player = (mm_player_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)
-{
- mm_player_t *player = (mm_player_t*)(data);
- GstMessage *msg = NULL;
- GstBus *bus = NULL;
-
- MMPLAYER_FENTER();
- MMPLAYER_RETURN_VAL_IF_FAIL(player &&
- player->pipeline &&
- player->pipeline->mainbin &&
- player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
- NULL);
-
- bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
- if (!bus) {
- LOGE("cannot get BUS from the pipeline");
- return 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);
- gst_object_unref(GST_OBJECT(bus));
-
- MMPLAYER_FLEAVE();
- return NULL;
-}
-
-static void
-__mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
-{
- mm_player_t* player = (mm_player_t*) data;
-
- MMPLAYER_FENTER();
-
- /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
- * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
- * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
- * So we can say this. if num_dynamic_pad is zero, it must be one of followings
-
- * [1] audio and video will be dumped with filesink.
- * [2] autoplugging is done by just using pad caps.
- * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
- * and the video will be dumped via filesink.
- */
- if (player->num_dynamic_pad == 0) {
- LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
-
- if (!__mmplayer_gst_remove_fakesink(player,
- &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
- /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
- * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
- * source element are not same. To overcome this situation, this function will called
- * several places and several times. Therefore, this is not an error case.
- */
- return;
- }
-
- /* create dot before error-return. for debugging */
- MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
-
- player->no_more_pad = TRUE;
-
- MMPLAYER_FLEAVE();
-}
-
-static gboolean
+gboolean
__mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
{
GstElement* parent = NULL;
return FALSE;
}
-
-static void
-__mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
-{
- GstPad *sinkpad = NULL;
- GstCaps* caps = NULL;
- GstElement* new_element = NULL;
- GstStructure* str = NULL;
- const gchar* name = NULL;
-
- mm_player_t* player = (mm_player_t*) data;
-
- MMPLAYER_FENTER();
-
- MMPLAYER_RETURN_IF_FAIL(element && pad);
- MMPLAYER_RETURN_IF_FAIL(player &&
- player->pipeline &&
- player->pipeline->mainbin);
-
-
- /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
- * num_dynamic_pad will decreased after creating a sinkbin.
- */
- player->num_dynamic_pad++;
- LOGD("stream count inc : %d\n", player->num_dynamic_pad);
-
- caps = gst_pad_query_caps(pad, NULL);
-
- MMPLAYER_CHECK_NULL(caps);
-
- /* clear previous result*/
- player->have_dynamic_pad = FALSE;
-
- str = gst_caps_get_structure(caps, 0);
-
- if (!str) {
- LOGE("cannot get structure from caps.\n");
- goto ERROR;
- }
-
- name = gst_structure_get_name(str);
- if (!name) {
- LOGE("cannot get mimetype from structure.\n");
- goto ERROR;
- }
-
- if (strstr(name, "video")) {
- gint stype = 0;
- mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
-
- if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
- if (player->v_stream_caps) {
- gst_caps_unref(player->v_stream_caps);
- player->v_stream_caps = NULL;
- }
-
- new_element = gst_element_factory_make("fakesink", NULL);
- player->num_dynamic_pad--;
- goto NEW_ELEMENT;
- }
- }
-
- /* clear previous result*/
- player->have_dynamic_pad = FALSE;
-
- if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
- LOGE("failed to autoplug for caps");
- goto ERROR;
- }
-
- /* check if there's dynamic pad*/
- if (player->have_dynamic_pad) {
- LOGE("using pad caps assums there's no dynamic pad !\n");
- goto ERROR;
- }
-
- gst_caps_unref(caps);
- caps = NULL;
-
-NEW_ELEMENT:
-
- /* excute new_element if created*/
- if (new_element) {
- LOGD("adding new element to pipeline\n");
-
- /* set state to READY before add to bin */
- MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
-
- /* add new element to the pipeline */
- if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
- LOGE("failed to add autoplug element to bin\n");
- goto ERROR;
- }
-
- /* get pad from element */
- sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
- if (!sinkpad) {
- LOGE("failed to get sinkpad from autoplug element\n");
- goto ERROR;
- }
-
- /* link it */
- if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
- LOGE("failed to link autoplug element\n");
- goto ERROR;
- }
-
- gst_object_unref(sinkpad);
- sinkpad = NULL;
-
- /* run. setting PLAYING here since streamming source is live source */
- MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
- }
-
- if (caps)
- gst_caps_unref(caps);
-
- MMPLAYER_FLEAVE();
-
- return;
-
-STATE_CHANGE_FAILED:
-ERROR:
- /* FIXIT : take care if new_element has already added to pipeline */
- if (new_element)
- gst_object_unref(GST_OBJECT(new_element));
-
- if (sinkpad)
- gst_object_unref(GST_OBJECT(sinkpad));
-
- if (caps)
- gst_caps_unref(caps);
-
- /* FIXIT : how to inform this error to MSL ????? */
- /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
- * then post an error to application
- */
-}
-
static GstPadProbeReturn
__mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
{
return ret;
}
-static void
+void
__mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
{
mm_player_t* player = NULL;
}
if (stype == MM_DISPLAY_SURFACE_REMOTE) {
- MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
- "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(sinkpad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
+ "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
}
if (player->set_mode.media_packet_video_stream) {
g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
- MMPLAYER_SIGNAL_CONNECT(player,
+ __mmplayer_add_signal_connection(player,
G_OBJECT(fakesink),
MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
"handoff",
G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
(gpointer)player);
- MMPLAYER_SIGNAL_CONNECT(player,
+ __mmplayer_add_signal_connection(player,
G_OBJECT(fakesink),
MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
"preroll-handoff",
g_object_set(selector, "active-pad", sinkpad, NULL);
}
- _mmplayer_track_update_info(player, stream_type, sinkpad);
+ __mmplayer_track_update_info(player, stream_type, sinkpad);
DONE:
g_object_set(deinterleave, "keep-positions", TRUE, NULL);
- MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
- G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(deinterleave), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
+ G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), (gpointer)player);
- MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
- G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(deinterleave), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
+ G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), (gpointer)player);
player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
return MM_ERROR_NONE;
}
-static int
+int
__mmplayer_gst_element_link_bucket(GList* element_bucket)
{
GList* bucket = element_bucket;
element = (MMPlayerGstElement*)bucket->data;
if (element && element->gst) {
- /* If next element is audio appsrc then make a separate audio pipeline */
- if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
- !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
- prv_element = element;
- continue;
- }
-
if (prv_element && prv_element->gst) {
if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
LOGD("linking [%s] to [%s] success\n",
return successful_link_count;
}
-static int
+int
__mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
{
GList* bucket = element_bucket;
gst_element_set_state(sink, GST_STATE_PAUSED);
gst_element_set_state(queue, GST_STATE_PAUSED);
- MMPLAYER_SIGNAL_CONNECT(player,
+ __mmplayer_add_signal_connection(player,
G_OBJECT(sink),
MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
"handoff",
g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
/* raw pad handling signal */
- MMPLAYER_SIGNAL_CONNECT(player,
- (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
- MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
- G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
} else {
int dst_samplerate = 0;
int dst_channels = 0;
if (audiobin[MMPLAYER_A_SINK].gst) {
GstPad *sink_pad = NULL;
sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
- MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
- "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
+ "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
gst_object_unref(GST_OBJECT(sink_pad));
}
if (enable)
g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
- MMPLAYER_SIGNAL_CONNECT(player,
+ __mmplayer_add_signal_connection(player,
G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
"handoff",
G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
(gpointer)player);
- MMPLAYER_SIGNAL_CONNECT(player,
+ __mmplayer_add_signal_connection(player,
G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
"preroll-handoff",
g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
"sync", TRUE, "signal-handoffs", TRUE, NULL);
- MMPLAYER_SIGNAL_CONNECT(player,
+ __mmplayer_add_signal_connection(player,
G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
"handoff",
G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
(gpointer)player);
- MMPLAYER_SIGNAL_CONNECT(player,
+ __mmplayer_add_signal_connection(player,
G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
"preroll-handoff",
GstPad *sink_pad = NULL;
sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
if (sink_pad) {
- MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
- "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
+ "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
gst_object_unref(GST_OBJECT(sink_pad));
} else
LOGW("failed to get sink pad from videosink\n");
NULL);
MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
- MMPLAYER_SIGNAL_CONNECT(player,
+ __mmplayer_add_signal_connection(player,
G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
"handoff",
return GST_PAD_PROBE_OK;
}
-static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
+static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
{
MMPLAYER_FENTER();
switch (format) {
case MM_PLAYER_POS_FORMAT_TIME:
- {
- /* check current postion */
- player->adjust_subtitle_pos = position;
-
- LOGD("save adjust_subtitle_pos in player") ;
- }
- break;
-
- default:
- {
- LOGW("invalid format.\n");
- MMPLAYER_FLEAVE();
- return MM_ERROR_INVALID_ARGUMENT;
- }
- }
-
- MMPLAYER_FLEAVE();
-
- return MM_ERROR_NONE;
-}
-
-static void
-__gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
-{
- GstElement *appsrc = element;
- MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
- GstBuffer *buffer = NULL;
- GstFlowReturn ret = GST_FLOW_OK;
- gint len = size;
-
- MMPLAYER_RETURN_IF_FAIL(element);
- MMPLAYER_RETURN_IF_FAIL(buf);
-
- buffer = gst_buffer_new();
-
- if (buf->offset >= buf->len) {
- LOGD("call eos appsrc\n");
- g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
- return;
- }
-
- if (buf->len - buf->offset < size)
- len = buf->len - buf->offset;
-
- gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
- GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
- GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
-
- //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
- g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
-
- buf->offset += len;
-}
-
-static gboolean
-__gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
-{
- MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
-
- MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
-
- buf->offset = (int)size;
-
- return TRUE;
-}
-
-static gboolean
-__mmplayer_gst_create_decoder(mm_player_t *player,
- MMPlayerTrackType track,
- GstPad* srcpad,
- enum MainElementID elemId,
- const gchar* name)
-{
- gboolean ret = TRUE;
- GstPad *sinkpad = NULL;
-
- MMPLAYER_FENTER();
-
- MMPLAYER_RETURN_VAL_IF_FAIL(player &&
- player->pipeline &&
- player->pipeline->mainbin, FALSE);
- MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
- MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
- MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
-
- GstElement *decodebin = NULL;
- GstCaps *dec_caps = NULL;
-
- /* create decodebin */
- decodebin = gst_element_factory_make("decodebin", name);
-
- if (!decodebin) {
- LOGE("error : fail to create decodebin for %d decoder\n", track);
- ret = FALSE;
- goto ERROR;
- }
-
- /* raw pad handling signal */
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
- G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
-
- /* This signal is emitted whenever decodebin finds a new stream. It is emitted
- before looking for any elements that can handle that stream.*/
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
- G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
-
- /* This signal is emitted when a element is added to the bin.*/
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
- G_CALLBACK(__mmplayer_gst_element_added), player);
-
- if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
- LOGE("failed to add new decodebin\n");
- ret = FALSE;
- goto ERROR;
- }
-
- dec_caps = gst_pad_query_caps(srcpad, NULL);
- if (dec_caps) {
- //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
- g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
- gst_caps_unref(dec_caps);
- }
-
- player->pipeline->mainbin[elemId].id = elemId;
- player->pipeline->mainbin[elemId].gst = decodebin;
-
- sinkpad = gst_element_get_static_pad(decodebin, "sink");
-
- if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
- LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
- gst_object_unref(GST_OBJECT(decodebin));
- }
-
- if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
- LOGE("failed to sync second level decodebin state with parent\n");
-
- LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
-
-ERROR:
- if (sinkpad) {
- gst_object_unref(GST_OBJECT(sinkpad));
- sinkpad = NULL;
- }
- MMPLAYER_FLEAVE();
-
- return ret;
-}
-
-/**
- * This function is to create audio or video pipeline for playing.
- *
- * @param player [in] handle of player
- *
- * @return This function returns zero on success.
- * @remark
- * @see
- */
-static int
-__mmplayer_gst_create_pipeline(mm_player_t* player)
-{
- GstBus *bus = NULL;
- MMPlayerGstElement *mainbin = NULL;
- MMHandleType attrs = 0;
- GstElement* element = NULL;
- GstElement* elem_src_audio = NULL;
- GstElement* elem_src_subtitle = NULL;
- GstElement* es_video_queue = NULL;
- GstElement* es_audio_queue = NULL;
- GstElement* es_subtitle_queue = NULL;
- GList* element_bucket = NULL;
- gboolean need_state_holder = TRUE;
- gint i = 0;
-#ifdef SW_CODEC_ONLY
- int surface_type = 0;
-#endif
- MMPLAYER_FENTER();
-
- MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
-
- /* get profile attribute */
- attrs = MMPLAYER_GET_ATTRS(player);
- if (!attrs) {
- LOGE("cannot get content attribute\n");
- goto INIT_ERROR;
- }
-
- /* create pipeline handles */
- if (player->pipeline) {
- LOGW("pipeline should be released before create new one\n");
- goto INIT_ERROR;
- }
-
- player->video360_metadata.is_spherical = -1;
- player->is_openal_plugin_used = FALSE;
-
- player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
- if (player->pipeline == NULL)
- goto INIT_ERROR;
-
- memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
-
- /* create mainbin */
- mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
- if (mainbin == NULL)
- goto INIT_ERROR;
-
- memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
-
- /* create pipeline */
- mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
- mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
- if (!mainbin[MMPLAYER_M_PIPE].gst) {
- LOGE("failed to create pipeline\n");
- goto INIT_ERROR;
- }
- player->demux_pad_index = 0;
- player->subtitle_language_list = NULL;
-
- player->is_subtitle_force_drop = FALSE;
- player->last_multiwin_status = FALSE;
-
- _mmplayer_track_initialize(player);
- __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
-
- /* create source element */
- switch (player->profile.uri_type) {
- /* rtsp streamming */
- case MM_PLAYER_URI_TYPE_URL_RTSP:
- {
- gchar *user_agent;
-
- element = gst_element_factory_make("rtspsrc", "rtsp source");
-
- if (!element) {
- LOGE("failed to create streaming source element\n");
- break;
- }
-
- /* make it zero */
- user_agent = NULL;
-
- /* get attribute */
- mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
-
- SECURE_LOGD("user_agent : %s\n", user_agent);
-
- /* setting property to streaming source */
- g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
- if (user_agent)
- g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
-
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
- G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
- G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
- }
- break;
-
- /* http streaming*/
- case MM_PLAYER_URI_TYPE_URL_HTTP:
- {
- gchar *user_agent, *cookies, **cookie_list;
- gint http_timeout = DEFAULT_HTTP_TIMEOUT;
- user_agent = cookies = NULL;
- cookie_list = NULL;
- gint mode = MM_PLAYER_PD_MODE_NONE;
-
- mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
-
- player->pd_mode = mode;
-
- LOGD("http playback, PD mode : %d\n", player->pd_mode);
-
- if (!MMPLAYER_IS_HTTP_PD(player)) {
- element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
- if (!element) {
- LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
- break;
- }
- LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
-
- /* 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) {
- LOGD("get timeout from ini\n");
- http_timeout = player->ini.http_timeout;
- }
-
- /* get attribute */
- SECURE_LOGD("location : %s\n", player->profile.uri);
- SECURE_LOGD("cookies : %s\n", cookies);
- SECURE_LOGD("user_agent : %s\n", user_agent);
- LOGD("timeout : %d\n", http_timeout);
-
- /* setting property to streaming source */
- g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
- g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
- g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
-
- /* parsing cookies */
- if ((cookie_list = util_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("it's dash. and it's still experimental feature.");
- } else {
- // progressive download
- gchar* location = NULL;
-
- if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
- gchar *path = NULL;
-
- mm_attrs_get_string_by_name(attrs, "pd_location", &path);
-
- MMPLAYER_FREEIF(player->pd_file_save_path);
-
- LOGD("PD Location : %s\n", path);
-
- if (path) {
- if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
- LOGE("failed to get storage info");
- break;
- }
- player->pd_file_save_path = g_strdup(path);
- } else {
- LOGE("can't find pd location so, it should be set \n");
- break;
- }
- }
-
- element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
- if (!element) {
- LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
- break;
- }
-
- if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
- g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
- else
- g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
- g_object_get(element, "location", &location, NULL);
- LOGD("PD_LOCATION [%s].\n", location);
- if (location)
- g_free(location);
- }
- }
- break;
-
- /* file source */
- case MM_PLAYER_URI_TYPE_FILE:
- {
- LOGD("using filesrc for 'file://' handler.\n");
- if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
- LOGE("failed to get storage info");
- break;
- }
-
- element = gst_element_factory_make("filesrc", "source");
- if (!element) {
- LOGE("failed to create filesrc\n");
- break;
- }
-
- g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
- }
- break;
-
- case MM_PLAYER_URI_TYPE_SS:
- {
- gint http_timeout = DEFAULT_HTTP_TIMEOUT;
- element = gst_element_factory_make("souphttpsrc", "http streaming source");
- if (!element) {
- LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
- break;
- }
-
- if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
- LOGD("get timeout from ini\n");
- http_timeout = player->ini.http_timeout;
- }
-
- /* setting property to streaming source */
- g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
- g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
- }
- break;
- case MM_PLAYER_URI_TYPE_MS_BUFF:
- {
- LOGD("MS buff src is selected\n");
-
- if (player->v_stream_caps) {
- element = gst_element_factory_make("appsrc", "video_appsrc");
- if (!element) {
- LOGF("failed to create video app source element[appsrc].\n");
- break;
- }
-
- if (player->a_stream_caps) {
- elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
- if (!elem_src_audio) {
- LOGF("failed to create audio app source element[appsrc].\n");
- break;
- }
- }
- } else if (player->a_stream_caps) {
- /* no video, only audio pipeline*/
- element = gst_element_factory_make("appsrc", "audio_appsrc");
- if (!element) {
- LOGF("failed to create audio app source element[appsrc].\n");
- break;
- }
- }
-
- if (player->s_stream_caps) {
- elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
- if (!elem_src_subtitle) {
- LOGF("failed to create subtitle app source element[appsrc].\n");
- break;
- }
- }
-
- LOGD("setting app sources properties.\n");
- LOGD("location : %s\n", player->profile.uri);
-
- if (player->v_stream_caps && element) {
- g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
- "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
- "caps", player->v_stream_caps, NULL);
-
- if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
- g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
- if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
- g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
-
- /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
- gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
- MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
- G_CALLBACK(__gst_seek_video_data), player);
-
- if (player->a_stream_caps && elem_src_audio) {
- g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
- "caps", player->a_stream_caps, NULL);
-
- if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
- g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
- if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
- g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
-
- /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
- gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
- MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
- G_CALLBACK(__gst_seek_audio_data), player);
- }
- } else if (player->a_stream_caps && element) {
- g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
- "caps", player->a_stream_caps, NULL);
-
- if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
- g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
- if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
- g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
-
- /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
- gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
- MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
- G_CALLBACK(__gst_seek_audio_data), player);
- }
-
- if (player->s_stream_caps && elem_src_subtitle) {
- g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
- "caps", player->s_stream_caps, NULL);
-
- if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
- g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
- if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
- g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
-
- gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
-
- MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
- G_CALLBACK(__gst_seek_subtitle_data), player);
- }
-
- if (player->v_stream_caps && element) {
- MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
- G_CALLBACK(__gst_appsrc_feed_video_data), player);
- MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
- G_CALLBACK(__gst_appsrc_enough_video_data), player);
-
- if (player->a_stream_caps && elem_src_audio) {
- MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
- G_CALLBACK(__gst_appsrc_feed_audio_data), player);
- MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
- G_CALLBACK(__gst_appsrc_enough_audio_data), player);
- }
- } else if (player->a_stream_caps && element) {
- MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
- G_CALLBACK(__gst_appsrc_feed_audio_data), player);
- MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
- G_CALLBACK(__gst_appsrc_enough_audio_data), player);
- }
-
- if (player->s_stream_caps && elem_src_subtitle)
- MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
- G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
-
- need_state_holder = FALSE;
-
- mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
- if (mmf_attrs_commit(attrs)) /* return -1 if error */
- LOGE("failed to commit\n");
- }
- break;
- /* appsrc */
- case MM_PLAYER_URI_TYPE_MEM:
- {
- guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
-
- LOGD("mem src is selected\n");
-
- element = gst_element_factory_make("appsrc", "mem-source");
- if (!element) {
- LOGE("failed to create appsrc element\n");
- break;
- }
-
- g_object_set(element, "stream-type", stream_type, NULL);
- g_object_set(element, "size", player->profile.input_mem.len, NULL);
- g_object_set(element, "blocksize", (guint64)20480, NULL);
-
- MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
- G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
- MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
- G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
- }
- break;
- case MM_PLAYER_URI_TYPE_URL:
- break;
-
- case MM_PLAYER_URI_TYPE_TEMP:
- break;
-
- case MM_PLAYER_URI_TYPE_NONE:
- default:
- break;
- }
-
- /* check source element is OK */
- if (!element) {
- LOGE("no source element was created.\n");
- goto INIT_ERROR;
- }
-
- /* take source element */
- mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
- mainbin[MMPLAYER_M_SRC].gst = element;
- element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
-
- if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
- player->streamer = __mm_player_streaming_create();
- __mm_player_streaming_initialize(player->streamer);
- }
-
- if (MMPLAYER_IS_HTTP_PD(player)) {
- gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
-
- LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
- element = gst_element_factory_make("queue2", "queue2");
- if (!element) {
- LOGE("failed to create http streaming buffer element\n");
- goto INIT_ERROR;
- }
-
- /* take it */
- mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
- mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
- element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
-
- pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
-
- player->streamer->is_pd_mode = TRUE;
-
- __mm_player_streaming_set_queue2(player->streamer,
- element,
- TRUE,
- player->ini.http_max_size_bytes, // + PLAYER_PD_EXT_MAX_SIZE_BYTE,
- pre_buffering_time,
- 1.0,
- player->ini.http_buffering_limit,
- MUXED_BUFFER_TYPE_MEM_QUEUE,
- NULL,
- 0);
- }
- if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
- if (player->v_stream_caps) {
- es_video_queue = gst_element_factory_make("queue2", "video_queue");
- if (!es_video_queue) {
- LOGE("create es_video_queue for es player failed\n");
- goto INIT_ERROR;
- }
- g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
- mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
- mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
- element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
-
- /* Adding audio appsrc to bucket */
- if (player->a_stream_caps && elem_src_audio) {
- mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
- mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
- element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
-
- es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
- if (!es_audio_queue) {
- LOGE("create es_audio_queue for es player failed\n");
- goto INIT_ERROR;
- }
- g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
+ {
+ /* check current postion */
+ player->adjust_subtitle_pos = position;
- mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
- mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
- element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
- }
- } else if (player->a_stream_caps) {
- /* Only audio stream, no video */
- es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
- if (!es_audio_queue) {
- LOGE("create es_audio_queue for es player failed\n");
- goto INIT_ERROR;
- }
- mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
- mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
- element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
+ LOGD("save adjust_subtitle_pos in player") ;
}
+ break;
- if (player->s_stream_caps && elem_src_subtitle) {
- mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
- mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
- element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
-
- es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
- if (!es_subtitle_queue) {
- LOGE("create es_subtitle_queue for es player failed\n");
- goto INIT_ERROR;
- }
- mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
- mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
- element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
+ default:
+ {
+ LOGW("invalid format.\n");
+ MMPLAYER_FLEAVE();
+ return MM_ERROR_INVALID_ARGUMENT;
}
}
- /* create autoplugging element if src element is not a rtsp src */
- if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
- (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
- element = NULL;
- enum MainElementID elemId = MMPLAYER_M_NUM;
-
- if (((MMPLAYER_IS_HTTP_PD(player)) ||
- (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
- elemId = MMPLAYER_M_AUTOPLUG;
- element = __mmplayer_create_decodebin(player);
- if (element) {
- /* default size of mq in decodebin is 2M
- * but it can cause blocking issue during seeking depends on content. */
- g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
- }
- need_state_holder = FALSE;
- } else {
- elemId = MMPLAYER_M_TYPEFIND;
- element = gst_element_factory_make("typefind", "typefinder");
- MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
- G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
- }
+ MMPLAYER_FLEAVE();
- /* check autoplug element is OK */
- if (!element) {
- LOGE("can not create element(%d)\n", elemId);
- goto INIT_ERROR;
- }
+ return MM_ERROR_NONE;
+}
- mainbin[elemId].id = elemId;
- mainbin[elemId].gst = element;
+/**
+ * This function is to create audio or video pipeline for playing.
+ *
+ * @param player [in] handle of player
+ *
+ * @return This function returns zero on success.
+ * @remark
+ * @see
+ */
+static int
+__mmplayer_gst_create_pipeline(mm_player_t* player)
+{
+ int ret = MM_ERROR_NONE;
+ MMPlayerGstElement *mainbin = NULL;
+ MMHandleType attrs = 0;
+ gint mode = MM_PLAYER_PD_MODE_NONE;
- element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
- }
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
- /* add elements to pipeline */
- if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
- LOGE("Failed to add elements to pipeline\n");
+ /* get profile attribute */
+ attrs = MMPLAYER_GET_ATTRS(player);
+ if (!attrs) {
+ LOGE("failed to get content attribute");
goto INIT_ERROR;
}
-
- /* linking elements in the bucket by added order. */
- if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
- LOGE("Failed to link some elements\n");
+ /* create pipeline handles */
+ if (player->pipeline) {
+ LOGE("pipeline should be released before create new one");
goto INIT_ERROR;
}
+ player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
+ if (player->pipeline == NULL)
+ goto INIT_ERROR;
- /* create fakesink element for keeping the pipeline state PAUSED. if needed */
- if (need_state_holder) {
- /* create */
- mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
- mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
-
- if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
- LOGE("fakesink element could not be created\n");
- goto INIT_ERROR;
- }
- GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
-
- /* take ownership of fakesink. we are reusing it */
- gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
+ /* create mainbin */
+ mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
+ if (mainbin == NULL)
+ goto INIT_ERROR;
- /* add */
- if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
- mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
- LOGE("failed to add fakesink to bin\n");
- goto INIT_ERROR;
- }
+ /* create pipeline */
+ mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
+ mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
+ if (!mainbin[MMPLAYER_M_PIPE].gst) {
+ LOGE("failed to create pipeline");
+ goto INIT_ERROR;
}
- /* now we have completed mainbin. take it */
player->pipeline->mainbin = mainbin;
- if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
- GstPad *srcpad = NULL;
-
- if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
- srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
- if (srcpad) {
- __mmplayer_gst_create_decoder(player,
- MM_PLAYER_TRACK_TYPE_VIDEO,
- srcpad,
- MMPLAYER_M_AUTOPLUG_V_DEC,
- "video_decodebin");
-
- gst_object_unref(GST_OBJECT(srcpad));
- srcpad = NULL;
- }
- }
-
- if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
- srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
- if (srcpad) {
- __mmplayer_gst_create_decoder(player,
- MM_PLAYER_TRACK_TYPE_AUDIO,
- srcpad,
- MMPLAYER_M_AUTOPLUG_A_DEC,
- "audio_decodebin");
-
- gst_object_unref(GST_OBJECT(srcpad));
- srcpad = NULL;
- } // else error
- } // else error
-
- if (mainbin[MMPLAYER_M_S_BUFFER].gst)
- __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
- }
+ /* check pd mode */
+ mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
+ player->pd_mode = mode;
- /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
- if (__mmplayer_check_subtitle(player)) {
- if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
- LOGE("fail to create text pipeline");
+ /* create the source and decoder elements */
+ if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
+ ret = __mmplayer_gst_build_es_pipeline(player);
+ } else if (MMPLAYER_IS_HTTP_STREAMING(player) && MMPLAYER_IS_HTTP_PD(player)) {
+ ret = __mmplayer_gst_build_pd_pipeline(player);
+ } else {
+ ret = __mmplayer_gst_build_pipeline(player);
}
- /* connect bus callback */
- bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
- if (!bus) {
- LOGE("cannot get bus from pipeline.\n");
+ if (ret != MM_ERROR_NONE) {
+ LOGE("failed to create some elements");
goto INIT_ERROR;
}
- player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
-
- player->context.thread_default = g_main_context_get_thread_default();
-
- if (player->context.thread_default == NULL) {
- player->context.thread_default = g_main_context_default();
- LOGD("thread-default context is the global default context");
+ /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
+ if (__mmplayer_check_subtitle(player)) {
+ if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
+ LOGE("failed to create text pipeline");
}
- LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
-
- /* set sync handler to get tag synchronously */
- gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
-
- /* finished */
- gst_object_unref(GST_OBJECT(bus));
- g_list_free(element_bucket);
- /* create gst bus_msb_cb thread */
- g_mutex_init(&player->bus_msg_thread_mutex);
- g_cond_init(&player->bus_msg_thread_cond);
- player->bus_msg_thread_exit = FALSE;
- player->bus_msg_thread =
- g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
- if (!player->bus_msg_thread) {
- LOGE("failed to create gst BUS msg thread");
- g_mutex_clear(&player->bus_msg_thread_mutex);
- g_cond_clear(&player->bus_msg_thread_cond);
+ /* add bus watch */
+ ret = __mmplayer_gst_add_bus_watch(player);
+ if (ret != MM_ERROR_NONE) {
+ LOGE("failed to add bus watch");
goto INIT_ERROR;
}
MMPLAYER_FLEAVE();
-
return MM_ERROR_NONE;
INIT_ERROR:
__mmplayer_gst_destroy_pipeline(player);
- g_list_free(element_bucket);
-
- if (mainbin) {
- /* release element which are not added to bin */
- for (i = 1; i < MMPLAYER_M_NUM; i++) {
- /* NOTE : skip pipeline */
- if (mainbin[i].gst) {
- GstObject* parent = NULL;
- parent = gst_element_get_parent(mainbin[i].gst);
-
- if (!parent) {
- gst_object_unref(GST_OBJECT(mainbin[i].gst));
- mainbin[i].gst = NULL;
- } else
- gst_object_unref(GST_OBJECT(parent));
- }
- }
-
- /* release pipeline with it's childs */
- if (mainbin[MMPLAYER_M_PIPE].gst)
- gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
-
- MMPLAYER_FREEIF(mainbin);
- }
-
- MMPLAYER_FREEIF(player->pipeline);
return MM_ERROR_PLAYER_INTERNAL;
}
gst_caps_unref(player->s_stream_caps);
player->s_stream_caps = NULL;
}
- _mmplayer_track_destroy(player);
+ __mmplayer_track_destroy(player);
if (player->sink_elements)
g_list_free(player->sink_elements);
return ret;
}
-static int __gst_realize(mm_player_t* player)
+static int __mmplayer_gst_realize(mm_player_t* player)
{
gint timeout = 0;
int ret = MM_ERROR_NONE;
return ret;
}
-static int __gst_unrealize(mm_player_t* player)
+static int __mmplayer_gst_unrealize(mm_player_t* player)
{
int ret = MM_ERROR_NONE;
}
static int
-__gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
+__mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
{
MMPLAYER_FENTER();
player->textsink_linked = 0;
player->is_external_subtitle_present = FALSE;
player->is_external_subtitle_added_now = FALSE;
- /* set the subtitle ON default */
- player->is_subtitle_off = FALSE;
+ player->is_subtitle_off = FALSE; /* set the subtitle ON default */
+ player->video360_metadata.is_spherical = -1;
+ player->is_openal_plugin_used = FALSE;
+ player->demux_pad_index = 0;
+ player->subtitle_language_list = NULL;
+ player->is_subtitle_force_drop = FALSE;
+ player->last_multiwin_status = FALSE;
+
+ __mmplayer_track_initialize(player);
+ __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
+
+ if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
+ player->streamer = __mm_player_streaming_create();
+ __mm_player_streaming_initialize(player->streamer);
+ }
/* realize pipeline */
- ret = __gst_realize(player);
+ ret = __mmplayer_gst_realize(player);
if (ret != MM_ERROR_NONE)
LOGE("fail to realize the player.\n");
else
__mmplayer_unrealize_streaming_ext(player);
/* unrealize pipeline */
- ret = __gst_unrealize(player);
+ ret = __mmplayer_gst_unrealize(player);
/* set asm stop if success */
if (MM_ERROR_NONE == ret) {
MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
- return __gst_set_message_callback(player, callback, user_param);
+ return __mmplayer_gst_set_message_callback(player, callback, user_param);
}
int
MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
- ret = __gst_adjust_subtitle_position(player, format, position);
+ ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
MMPLAYER_FLEAVE();
MMPLAYER_FLEAVE();
}
-static void
+void
__mmplayer_typefind_have_type(GstElement *tf, guint probability,
GstCaps *caps, gpointer data)
{
return;
}
-static GstElement *
+GstElement *
__mmplayer_create_decodebin(mm_player_t* player)
{
GstElement *decodebin = NULL;
}
/* raw pad handling signal */
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
- G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
+ G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
/* no-more-pad pad handling signal */
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
- G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
+ G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
- G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
+ G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
/* This signal is emitted when a pad for which there is no further possible
decoding is added to the decodebin.*/
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
- G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
+ G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
/* This signal is emitted whenever decodebin finds a new stream. It is emitted
before looking for any elements that can handle that stream.*/
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
- G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
+ G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
/* This signal is emitted whenever decodebin finds a new stream. It is emitted
before looking for any elements that can handle that stream.*/
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
- G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
+ G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
/* This signal is emitted once decodebin has finished decoding all the data.*/
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
- G_CALLBACK(__mmplayer_gst_decode_drained), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
+ G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
/* This signal is emitted when a element is added to the bin.*/
- MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
- G_CALLBACK(__mmplayer_gst_element_added), player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
+ G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
ERROR:
return decodebin;
}
-static gboolean
+gboolean
__mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
{
MMPlayerGstElement* mainbin = NULL;
player->total_bitrate = 0;
player->total_maximum_bitrate = 0;
- _mmplayer_track_initialize(player);
+ __mmplayer_track_initialize(player);
__mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
MMPLAYER_FENTER();
- if ((player == NULL) ||
- (player->pipeline == NULL) ||
- (player->pipeline->mainbin == NULL)) {
- LOGE("player is null.\n");
+ if (!player || !player->pipeline || !player->pipeline->mainbin) {
+ LOGE("player is not initialized");
goto ERROR;
}
attrs = MMPLAYER_GET_ATTRS(player);
if (!attrs) {
- LOGE("fail to get attributes.\n");
+ LOGE("fail to get attributes");
goto ERROR;
}
mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
- LOGE("failed to parse profile\n");
+ LOGE("failed to parse profile");
msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
goto ERROR;
}
if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
(MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
- LOGE("it's dash or hls. not support.");
+ LOGE("dash or hls is not supportable");
msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
goto ERROR;
}
- /* setup source */
- switch (player->profile.uri_type) {
- /* file source */
- case MM_PLAYER_URI_TYPE_FILE:
- {
- LOGD("using filesrc for 'file://' handler.\n");
- if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
- LOGE("failed to get storage info");
- break;
- }
-
- element = gst_element_factory_make("filesrc", "source");
-
- if (!element) {
- LOGE("failed to create filesrc\n");
- break;
- }
-
- g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
- break;
- }
- case MM_PLAYER_URI_TYPE_URL_HTTP:
- {
- gchar *user_agent, *cookies, **cookie_list;
- gint http_timeout = DEFAULT_HTTP_TIMEOUT;
- user_agent = cookies = NULL;
- cookie_list = NULL;
-
- element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
- if (!element) {
- LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
- break;
- }
- LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
-
- /* 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) {
- LOGD("get timeout from ini\n");
- http_timeout = player->ini.http_timeout;
- }
-
- /* get attribute */
- SECURE_LOGD("location : %s\n", player->profile.uri);
- SECURE_LOGD("cookies : %s\n", cookies);
- SECURE_LOGD("user_agent : %s\n", user_agent);
- LOGD("timeout : %d\n", http_timeout);
-
- /* setting property to streaming source */
- g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
- g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
- g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
-
- /* parsing cookies */
- if ((cookie_list = util_get_cookie_list((const char*)cookies)))
- g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
- if (user_agent)
- g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
- break;
- }
- default:
- LOGE("not support uri type %d\n", player->profile.uri_type);
- break;
- }
-
+ element = __mmplayer_gst_build_source(player);
if (!element) {
- LOGE("no source element was created.\n");
+ LOGE("no source element was created");
goto ERROR;
}
if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
- LOGE("failed to add source element to pipeline\n");
+ LOGE("failed to add source element to pipeline");
gst_object_unref(GST_OBJECT(element));
element = NULL;
goto ERROR;
elemId = MMPLAYER_M_TYPEFIND;
element = gst_element_factory_make("typefind", "typefinder");
- MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
- G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
+ __mmplayer_add_signal_connection(player, G_OBJECT(element),
+ MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
} else {
elemId = MMPLAYER_M_AUTOPLUG;
element = __mmplayer_create_decodebin(player);
/* check autoplug element is OK */
if (!element) {
- LOGE("can not create element(%d)\n", elemId);
+ LOGE("can not create element(%d)", elemId);
goto ERROR;
}
if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
- LOGE("failed to add sinkbin to pipeline\n");
+ LOGE("failed to add sinkbin to pipeline");
gst_object_unref(GST_OBJECT(element));
element = NULL;
goto ERROR;
mainbin[elemId].gst = element;
if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
- LOGE("Failed to link src - autoplug(or typefind)\n");
+ LOGE("Failed to link src - autoplug(or typefind)");
goto ERROR;
}
if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
- LOGE("Failed to change state of src element\n");
+ LOGE("Failed to change state of src element");
goto ERROR;
}
if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
- LOGE("Failed to change state of decodebin\n");
+ LOGE("Failed to change state of decodebin");
goto ERROR;
}
} else {
if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
- LOGE("Failed to change state of src element\n");
+ LOGE("Failed to change state of src element");
goto ERROR;
}
}
goto ERROR;
}
- _mmplayer_track_destroy(player);
+ __mmplayer_track_destroy(player);
__mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
if (player->streamer) {
return ret;
}
-static gint
+gint
__mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
GstCaps* caps, GstElementFactory* factory, gpointer data)
{
MMPLAYER_FLEAVE();
}
-static void
+void
__mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
{
mm_player_t* player = (mm_player_t*)data;
MMPLAYER_FLEAVE();
}
+void
+__mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
+ MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
+{
+ MMPlayerSignalItem* item = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_IF_FAIL(player);
+
+ if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
+ LOGE("invalid signal type [%d]", type);
+ return;
+ }
+
+ item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
+ if (!item) {
+ LOGE("cannot connect signal [%s]", signal);
+ return;
+ }
+
+ item->obj = object;
+ item->sig = g_signal_connect(object, signal, cb_funct, u_data);
+ player->signals[type] = g_list_append(player->signals[type], item);
+
+ MMPLAYER_FLEAVE();
+ return;
+}
+
/* NOTE : be careful with calling this api. please refer to below glib comment
* glib comment : Note that there is a bug in GObject that makes this function much
* less useful than it might seem otherwise. Once gobject is disposed, the callback
MMPLAYER_FLEAVE();
}
-void
-__gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
-{
- mm_player_t *player = (mm_player_t*)user_data;
- MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
- guint64 current_level_bytes = 0;
-
- MMPLAYER_RETURN_IF_FAIL(player);
-
- g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
-
- LOGI("app-src: feed audio(%llu)", current_level_bytes);
- MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
-
- if (player->media_stream_buffer_status_cb[type])
- player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
- MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
-
-}
-
-void
-__gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
-{
- mm_player_t *player = (mm_player_t*)user_data;
- MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
- guint64 current_level_bytes = 0;
-
- MMPLAYER_RETURN_IF_FAIL(player);
-
- g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
-
- LOGI("app-src: feed video(%llu)", current_level_bytes);
-
- MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
- if (player->media_stream_buffer_status_cb[type])
- player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
- MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
-}
-
-void
-__gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
-{
- mm_player_t *player = (mm_player_t*)user_data;
- MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
- guint64 current_level_bytes = 0;
-
- MMPLAYER_RETURN_IF_FAIL(player);
-
- LOGI("app-src: feed subtitle");
-
- g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
-
- MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
- if (player->media_stream_buffer_status_cb[type])
- player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
-
- MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
-}
-
-void
-__gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
-{
- mm_player_t *player = (mm_player_t*)user_data;
- MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
- guint64 current_level_bytes = 0;
-
- MMPLAYER_RETURN_IF_FAIL(player);
-
- LOGI("app-src: audio buffer is full");
-
- g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
-
- MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
-
- if (player->media_stream_buffer_status_cb[type])
- player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
-
- MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
-}
-
-void
-__gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
-{
- mm_player_t *player = (mm_player_t*)user_data;
- MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
- guint64 current_level_bytes = 0;
-
- MMPLAYER_RETURN_IF_FAIL(player);
-
- LOGI("app-src: video buffer is full");
-
- g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
-
- MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
- if (player->media_stream_buffer_status_cb[type])
- player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
-
- MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
-}
-
-gboolean
-__gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
-{
- mm_player_t *player = (mm_player_t*)user_data;
- MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
-
- MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
-
- LOGD("app-src: seek audio data %llu", position);
- MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
-
- if (player->media_stream_seek_data_cb[type])
- player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
- MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
-
- return TRUE;
-}
-
-gboolean
-__gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
-{
- mm_player_t *player = (mm_player_t*)user_data;
- MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
-
- MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
-
- LOGD("app-src: seek video data %llu", position);
- MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
- if (player->media_stream_seek_data_cb[type])
- player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
- MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
-
- return TRUE;
-}
-
-gboolean
-__gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
-{
- mm_player_t *player = (mm_player_t*)user_data;
- MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
-
- MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
-
- LOGD("app-src: seek subtitle data");
- MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
-
- if (player->media_stream_seek_data_cb[type])
- player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
- MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
-
- return TRUE;
-}
-
int
_mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
{