#define MM_VOLUME_FACTOR_MAX 1.0
/* Don't need to sleep for sound fadeout
- * fadeout related fucntion will be deleted(Deprecated)
+ * fadeout related function will be deleted(Deprecated)
*/
#define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
-
-static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
-static void __mmplayer_gst_create_sinkbin(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 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_pipeline_complete(GstElement *decodebin, gpointer data);
+static void __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
+static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
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(mmplayer_t *player, GstCaps *caps);
static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
static void __mmplayer_release_misc(mmplayer_t *player);
static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
-static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
+static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
static gpointer __mmplayer_gapless_play_thread(gpointer data);
static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
+static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
static void __mmplayer_deactivate_old_path(mmplayer_t *player);
static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
static void __mmplayer_set_pause_state(mmplayer_t *player);
static void __mmplayer_set_playing_state(mmplayer_t *player);
+static int __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index);
/*===========================================================================================
| |
| FUNCTION DEFINITIONS |
}
/* this function sets the player state and also report
- * it to applicaton by calling callback function
+ * it to application by calling callback function
*/
void
_mmplayer_set_state(mmplayer_t *player, int state)
MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
#ifdef __DEBUG__
- LOGD("incomming command : %d ", command);
+ LOGD("incoming command : %d ", command);
#endif
current_state = MMPLAYER_CURRENT_STATE(player);
pending_state = MMPLAYER_PENDING_STATE(player);
if (pending_state == MM_PLAYER_STATE_NONE) {
if (current_state == MM_PLAYER_STATE_PAUSED)
goto NO_OP;
- else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
+ else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of browser
goto INVALID_STATE;
} else if (pending_state == MM_PLAYER_STATE_PAUSED) {
goto ALREADY_GOING;
return MM_ERROR_PLAYER_NO_OP;
}
-static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
+int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
{
int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
return MM_ERROR_PLAYER_INTERNAL;
}
+ LOGD("commit [%d type] resource", type);
rm_ret = mm_resource_manager_commit(player->resource_manager);
if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
return MM_ERROR_NONE;
}
+static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
+{
+ int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
+
+ MMPLAYER_RETURN_IF_FAIL(player);
+ MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
+
+ rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
+ if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
+ goto rm_destroy;
+ }
+
+ rm_ret = mm_resource_manager_commit(player->resource_manager);
+ if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
+ LOGW("failed to commit resource, ret(0x%x)", rm_ret);
+
+rm_destroy:
+ /* de-initialize resource manager */
+ rm_ret = mm_resource_manager_destroy(player->resource_manager);
+ if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
+ return;
+ }
+
+ player->resource_manager = NULL;
+
+ LOGD("resource manager is destroyed");
+}
+
static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
{
int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
player->hw_resource[type] = NULL;
+ LOGD("commit [%d type] resource", type);
rm_ret = mm_resource_manager_commit(player->resource_manager);
if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
- LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
+ LOGE("failed to commit resource, ret(0x%x)", rm_ret);
return MM_ERROR_PLAYER_INTERNAL;
}
/* clean found audio decoders */
if (player->audio_decoders) {
- GList *a_dec = player->audio_decoders;
- for (; a_dec; a_dec = g_list_next(a_dec)) {
- gchar *name = a_dec->data;
- MMPLAYER_FREEIF(name);
- }
- g_list_free(player->audio_decoders);
+ g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
player->audio_decoders = NULL;
}
}
void
+_mmplayer_watcher_removed_notify(gpointer data)
+{
+ mmplayer_t *player = (mmplayer_t *)data;
+ MMPLAYER_RETURN_IF_FAIL(player);
+
+ MMPLAYER_BUS_WATCHER_LOCK(player);
+ player->bus_watcher = 0;
+ MMPLAYER_BUS_WATCHER_SIGNAL(player);
+ MMPLAYER_BUS_WATCHER_UNLOCK(player);
+}
+
+void
+_mmplayer_bus_watcher_remove(MMHandleType hplayer)
+{
+ mmplayer_t *player = (mmplayer_t *)hplayer;
+ gint64 end_time = 0;
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_IF_FAIL(player);
+
+ /* disconnecting bus watch */
+ if (player->bus_watcher > 0) {
+ __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
+ MMPLAYER_BUS_WATCHER_LOCK(player);
+ end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
+ while (player->bus_watcher > 0) {
+ if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
+ LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
+ player->bus_watcher);
+ break;
+ }
+ }
+ MMPLAYER_BUS_WATCHER_UNLOCK(player);
+ g_mutex_clear(&player->bus_watcher_mutex);
+ g_cond_clear(&player->bus_watcher_cond);
+ }
+
+ MMPLAYER_FLEAVE();
+}
+
+void
_mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
{
mmplayer_t *player = (mmplayer_t *)hplayer;
MMPLAYER_FENTER();
MMPLAYER_RETURN_IF_FAIL(player);
- /* disconnecting bus watch */
- if (player->bus_watcher)
- __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
- player->bus_watcher = 0;
-
/* destroy the gst bus msg thread */
if (player->bus_msg_thread) {
MMPLAYER_BUS_MSG_THREAD_LOCK(player);
gst_element_set_locked_state(fakesink->gst, TRUE);
/* setting the state to NULL never returns async
- * so no need to wait for completion of state transiton
+ * so no need to wait for completion of state transition
*/
if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
LOGE("fakesink state change failure!");
for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
if ((player->gapless.update_segment[idx] == TRUE) ||
- !(player->selector[idx].event_probe_id)) {
+ !(player->track[idx].event_probe_id)) {
#ifdef __DEBUG__
LOGW("[%d] skip", idx);
#endif
GST_EVENT_TYPE(event) != GST_EVENT_QOS)
return ret;
- MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
+ MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
if (!caps_ret)
goto ERROR;
return ret;
}
-/* create fakesink for audio or video path witout audiobin or videobin */
+/* create fakesink for audio or video path without audiobin or videobin */
static void
__mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
{
}
/* store it as it's sink element */
- __mmplayer_add_sink(player, fakesink);
+ __mmplayer_add_sink(player, fakesink, FALSE);
gst_bin_add(GST_BIN(pipeline), fakesink);
}
static GstElement *
+__mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
+{
+ GstElement *pipeline = NULL;
+ GstElement *concat = NULL;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
+
+ concat = gst_element_factory_make("concat", NULL);
+ if (!concat) {
+ LOGE("failed to create concat");
+ return NULL;
+ }
+
+ LOGD("Create concat [%d] element", elem_idx);
+
+ player->pipeline->mainbin[elem_idx].id = elem_idx;
+ player->pipeline->mainbin[elem_idx].gst = concat;
+
+ gst_element_set_state(concat, GST_STATE_PAUSED);
+
+ pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
+ gst_bin_add(GST_BIN(pipeline), concat);
+
+ MMPLAYER_FLEAVE();
+ return concat;
+}
+
+static GstElement *
__mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
{
GstElement *pipeline = NULL;
player->pipeline->mainbin[elem_idx].id = elem_idx;
player->pipeline->mainbin[elem_idx].gst = selector;
- /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
+ /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
srcpad = gst_element_get_static_pad(selector, "src");
LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
- player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+ player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
__mmplayer_gst_selector_blocked, NULL, NULL);
- player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
+ player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
__mmplayer_gst_selector_event_probe, player, NULL);
gst_element_set_state(selector, GST_STATE_PAUSED);
_mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
{
mmplayer_t *player = (mmplayer_t *)data;
- GstElement *selector = NULL;
+ GstElement *combiner = NULL;
GstCaps *caps = NULL;
GstStructure *str = NULL;
const gchar *name = NULL;
LOGD("pad-added signal handling");
/* get mimetype from caps */
- MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
+ MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
if (!caps_ret)
goto ERROR;
LOGD("surface type : %d", stype);
if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
- __mmplayer_gst_create_sinkbin(elem, pad, player);
+ __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
goto DONE;
}
goto DONE;
}
- LOGD("video selector is required");
- elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
+ if (MMPLAYER_USE_DECODEBIN(player)) {
+ LOGD("video selector is required");
+ elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
+ } else {
+ LOGD("video concat is required");
+ elem_idx = MMPLAYER_M_V_CONCAT;
+ }
stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
} else if (strstr(name, "audio")) {
gint samplerate = 0;
if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
if (player->build_audio_offload)
player->no_more_pad = TRUE; /* remove state holder */
- __mmplayer_gst_create_sinkbin(elem, pad, player);
+ __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
goto DONE;
}
__mmplayer_gst_make_fakesink(player, pad, name);
goto DONE;
}
-
- LOGD("audio selector is required");
- elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
+ if (MMPLAYER_USE_DECODEBIN(player)) {
+ LOGD("audio selector is required");
+ elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
+ } else {
+ LOGD("audio concat is required");
+ elem_idx = MMPLAYER_M_A_CONCAT;
+ }
stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
} else if (strstr(name, "text")) {
- LOGD("text selector is required");
- elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
+ if (MMPLAYER_USE_DECODEBIN(player)) {
+ LOGD("text selector is required");
+ elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
+ } else {
+ LOGD("text concat is required");
+ elem_idx = MMPLAYER_M_T_CONCAT;
+ }
stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
} else {
LOGE("invalid caps info");
}
/* check selector and create it */
- if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
- selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
- if (!selector)
+ if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
+ if (MMPLAYER_USE_DECODEBIN(player))
+ combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
+ else
+ combiner = __mmplayer_gst_make_concat(player, elem_idx);
+
+ if (!combiner)
goto ERROR;
first_track = TRUE;
} else {
- LOGD("input-selector is already created.");
+ LOGD("Combiner element is already created.");
}
/* link */
- sinkpad = gst_element_get_request_pad(selector, "sink_%u");
+ sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
- LOGE("failed to link selector");
- gst_object_unref(GST_OBJECT(selector));
+ LOGE("failed to link combiner");
+ gst_object_unref(GST_OBJECT(combiner));
goto ERROR;
}
if (first_track) {
- LOGD("this track will be activated");
- g_object_set(selector, "active-pad", sinkpad, NULL);
+ if (MMPLAYER_USE_DECODEBIN(player)) {
+ LOGD("this track will be activated");
+ g_object_set(combiner, "active-pad", sinkpad, NULL);
+ }
}
- _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
+ if (MMPLAYER_USE_DECODEBIN(player)) {
+ _mmplayer_track_update_stream(player, stream_type, sinkpad);
+ } else {
+ /* apply the text track information */
+ if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
+ mm_player_set_attribute((MMHandleType)player, NULL,
+ "content_text_track_num", player->track[stream_type].total_track_num,
+ "current_text_track_index", player->track[stream_type].active_track_index, NULL);
+ __mmplayer_create_sink_path(player, combiner, stream_type, caps);
+ }
DONE:
ERROR:
}
static gboolean
-__mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
+__mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
{
GstPad *srcpad = NULL;
LOGD("type %d", type);
- if (!selector) {
+ if (!combiner) {
LOGD("there is no %d track", type);
return TRUE;
}
- srcpad = gst_element_get_static_pad(selector, "src");
+ srcpad = gst_element_get_static_pad(combiner, "src");
if (!srcpad) {
- LOGE("failed to get srcpad from selector");
+ LOGE("failed to get srcpad from combiner");
return FALSE;
}
- LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
+ LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
- __mmplayer_gst_create_sinkbin(selector, srcpad, player);
+ __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
- if (player->selector[type].block_id) {
- gst_pad_remove_probe(srcpad, player->selector[type].block_id);
- player->selector[type].block_id = 0;
+ if (player->track[type].block_id) {
+ gst_pad_remove_probe(srcpad, player->track[type].block_id);
+ player->track[type].block_id = 0;
}
if (srcpad) {
MMPLAYER_FENTER();
MMPLAYER_RETURN_IF_FAIL(player);
- LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
+ LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
/* change track to active pad */
- active_index = player->selector[type].active_pad_index;
- if ((active_index != DEFAULT_TRACK) &&
+ active_index = player->track[type].active_track_index;
+ if ((active_index != DEFAULT_TRACK_INDEX) &&
(__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
LOGW("failed to change %d type track to %d", type, active_index);
- player->selector[type].active_pad_index = DEFAULT_TRACK;
+ player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
return;
}
if (type == MM_PLAYER_TRACK_TYPE_TEXT)
mm_player_set_attribute((MMHandleType)player, NULL,
- "content_text_track_num", player->selector[type].total_track_num,
- "current_text_track_index", player->selector[type].active_pad_index, NULL);
+ "content_text_track_num", player->track[type].total_track_num,
+ "current_text_track_index", player->track[type].active_track_index, NULL);
MMPLAYER_FLEAVE();
return;
}
if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
- __mmplayer_pipeline_complete(NULL, player);
+ _mmplayer_pipeline_complete(NULL, player);
return TRUE;
}
/* apply the audio track information */
- __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
+ if (MMPLAYER_USE_DECODEBIN(player))
+ __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
/* create audio sink path */
- if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
+ if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
LOGE("failed to create audio sink path");
return FALSE;
}
MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
- LOGD("text path is not supproted");
+ LOGD("text path is not supported");
return TRUE;
}
/* apply the text track information */
__mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
- if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
+ if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
player->has_closed_caption = TRUE;
/* create text decode path */
player->no_more_pad = TRUE;
- if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
+ if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
LOGE("failed to create text sink path");
return FALSE;
}
return TRUE;
}
-static void
-__mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
+void
+_mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
{
mmplayer_t *player = NULL;
GstElement *video_selector = NULL;
if (video_selector && !audio_selector && !text_selector)
player->no_more_pad = TRUE;
- if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
+ if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
goto EXIT;
/* create audio path followed by audio-select */
}
static void
-__mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
+__mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
{
mmplayer_t *player = NULL;
GstCaps *caps = NULL;
MMPLAYER_FENTER();
MMPLAYER_RETURN_IF_FAIL(elem && pad);
MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
-
- MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
- if (!caps_ret)
- goto ERROR;
+ MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
+ if (!caps_ret) {
+ MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
+ if (!caps_ret)
+ goto ERROR;
+ if (caps)
+ gst_caps_unref(caps);
+ caps = gst_caps_ref(ref_caps);
+ }
caps_str = gst_caps_to_string(caps);
#ifdef __DEBUG__
LOGD("display_surface_type (%d)", surface_type);
if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
- (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
+ (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
LOGE("failed to acquire video overlay resource");
goto ERROR;
}
player->textsink_linked = 1;
} else {
/* linked textbin exist which means that the external subtitle path exist already */
- LOGW("ignoring internal subtutle since external subtitle is available");
+ LOGW("ignoring internal subtitle since external subtitle is available");
}
}
sink_pad_name = "text_sink";
LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
- __mmplayer_pipeline_complete(NULL, player);
+ _mmplayer_pipeline_complete(NULL, player);
ERROR:
if (rotation_angle >= 360)
rotation_angle -= 360;
- /* chech if supported or not */
+ /* check if supported or not */
if (rotation_angle % 90) {
LOGD("not supported rotation angle = %d", rotation_angle);
return FALSE;
}
if (display_angle) {
- /* update user roation */
+ /* update user rotation */
mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
/* Counter clockwise */
return MM_ERROR_NONE;
}
-int
-_mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
+static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
{
gboolean disable_overlay = FALSE;
- mmplayer_t *player = (mmplayer_t *)hplayer;
MMPLAYER_FENTER();
- MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
player->pipeline->videobin[MMPLAYER_V_SINK].gst,
MM_ERROR_PLAYER_NO_OP); /* invalid op */
g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
- if (audio_only == (bool)disable_overlay) {
- LOGE("It's the same with current setting: (%d)", audio_only);
+ if (disable == (bool)disable_overlay) {
+ LOGE("It's the same with current setting: (%d)", disable);
return MM_ERROR_NONE;
}
- if (audio_only) {
+ if (disable) {
LOGE("disable overlay");
g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
/* release overlay resource */
if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
LOGE("failed to release overlay resource");
- goto ERROR;
+ return MM_ERROR_PLAYER_INTERNAL;
}
} else {
- if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
+ if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
LOGE("failed to acquire video overlay resource");
- goto ERROR;
+ return MM_ERROR_PLAYER_INTERNAL;
}
player->interrupted_by_resource = FALSE;
g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
}
-ERROR:
MMPLAYER_FLEAVE();
return MM_ERROR_NONE;
}
int
-_mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
+_mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
{
+ int ret = MM_ERROR_NONE;
mmplayer_t *player = (mmplayer_t *)hplayer;
- gboolean disable_overlay = FALSE;
MMPLAYER_FENTER();
-
MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
- MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
- MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
- player->pipeline->videobin[MMPLAYER_V_SINK].gst,
- MM_ERROR_PLAYER_NO_OP); /* invalid op */
- if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
- LOGW("Display control is not supported");
- return MM_ERROR_PLAYER_INTERNAL;
+ if (MMPLAYER_USE_DECODEBIN(player)) {
+ ret = __mmplayer_set_disable_overlay_option(player, audio_only);
+ goto EXIT;
}
- g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
+ if (audio_only) {
+ MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
+ player->pipeline->videobin[MMPLAYER_V_SINK].gst,
+ MM_ERROR_PLAYER_NO_OP); /* invalid op */
- *paudio_only = (bool)disable_overlay;
+ __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
+
+ /* release decoder resource */
+ if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
+ LOGE("failed to release video decoder resources");
+ return MM_ERROR_PLAYER_INTERNAL;
+ }
+ player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
+ } else {
+ __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
+ }
- LOGD("audio_only : %d", *paudio_only);
+EXIT:
+ mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
MMPLAYER_FLEAVE();
-
- return MM_ERROR_NONE;
+ return ret;
}
int
MMPLAYER_RETURN_IF_FAIL(unused);
MMPLAYER_RETURN_IF_FAIL(data);
- caps = gst_pad_get_current_caps(pad);
- if (!caps)
- return;
-
- MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
+ MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
if (!caps_ret)
goto ERROR;
G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
(gpointer)player);
- __mmplayer_add_sink(player, sink);
+ __mmplayer_add_sink(player, sink, FALSE);
if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
LOGE("failed to sync state");
MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
player->no_more_pad = TRUE;
- __mmplayer_pipeline_complete(NULL, player);
+ _mmplayer_pipeline_complete(NULL, player);
MMPLAYER_FLEAVE();
return;
"notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
gst_object_unref(GST_OBJECT(sink_pad));
- __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
+ __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
MMPLAYER_FLEAVE();
return MM_ERROR_NONE;
MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
player->no_more_pad = FALSE;
} else {
- /* 4-2. create fakesink to extract interlevaed pcm */
+ /* 4-2. create fakesink to extract interleaved pcm */
LOGD("add audio fakesink for interleaved audio");
MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
(gpointer)player);
- __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
+ __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
}
MMPLAYER_FLEAVE();
g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
"volume", player->sound.volume, "mute", player->sound.mute, NULL);
- __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
+ __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
goto DONE;
}
}
}
- /* release audiobin with it's childs */
+ /* release audiobin with it's children */
if (audiobin[MMPLAYER_A_BIN].gst)
gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
LOGW("failed to find bo %p", bo);
return ret;
}
+static void
+__mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
+{
+ if (!tmp)
+ return;
+
+ if (tmp->bo)
+ tbm_bo_unref(tmp->bo);
+ g_free(tmp);
+}
static void
__mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
{
- GList *l = NULL;
-
MMPLAYER_FENTER();
MMPLAYER_RETURN_IF_FAIL(player);
MMPLAYER_VIDEO_BO_LOCK(player);
if (player->video_bo_list) {
LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
- for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
- mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
- if (tmp) {
- if (tmp->bo)
- tbm_bo_unref(tmp->bo);
- g_free(tmp);
- }
- }
- g_list_free(player->video_bo_list);
+ g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
player->video_bo_list = NULL;
}
player->video_bo_size = 0;
/* set size and timestamp */
mem = gst_buffer_peek_memory(buffer, 0);
stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
- stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
+ stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
/* check zero-copy */
if (player->set_mode.video_zc &&
}
/* store it as it's sink element */
- __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
+ __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
/* adding created elements to bin */
if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
if (pad)
gst_object_unref(GST_OBJECT(pad));
- /* release videobin with it's childs */
+ /* release videobin with it's children */
if (videobin[MMPLAYER_V_BIN].gst)
gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
if (!player->play_subtitle) {
LOGD("add textbin sink as sink element of whole pipeline.");
- __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
+ __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
}
/* adding created elements to bin */
LOGD("adding created elements to bin");
if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
LOGE("failed to add elements");
+ g_list_free(element_bucket);
goto ERROR;
}
LOGD("Linking elements in the bucket by added order.");
if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
LOGE("failed to link elements");
+ g_list_free(element_bucket);
goto ERROR;
}
return MM_ERROR_NONE;
ERROR:
- g_list_free(element_bucket);
if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
LOGE("remove textbin sink from sink list");
}
}
- /* release textbin with it's childs */
+ /* release textbin with it's children */
if (textbin[MMPLAYER_T_BIN].gst)
gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
/* release signal */
__mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
- /* release textbin with it's childs */
+ /* release textbin with it's children */
gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
MMPLAYER_FREEIF(player->pipeline->textbin);
player->pipeline->textbin = textbin = NULL;
if (player->pipeline->textbin) {
LOGE("remove textbin");
- /* release textbin with it's childs */
+ /* release textbin with it's children */
MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
MMPLAYER_FREEIF(player->pipeline->textbin);
player->pipeline->textbin = NULL;
return MM_ERROR_NONE;
}
- /* check current postion */
+ /* check current position */
player->adjust_subtitle_pos = position;
LOGD("save adjust_subtitle_pos in player");
player->pipeline->mainbin = mainbin;
/* create the source and decoder elements */
- if (MMPLAYER_IS_MS_BUFF_SRC(player))
+ if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
ret = _mmplayer_gst_build_es_pipeline(player);
- else
- ret = _mmplayer_gst_build_pipeline(player);
+ } else {
+ if (MMPLAYER_USE_DECODEBIN(player))
+ ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
+ else
+ ret = _mmplayer_gst_build_pipeline_with_src(player);
+ }
if (ret != MM_ERROR_NONE) {
LOGE("failed to create some elements");
goto INIT_ERROR;
}
- /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
+ /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
if (__mmplayer_check_subtitle(player)
&& (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
LOGE("failed to create text pipeline");
return MM_ERROR_NONE;
INIT_ERROR:
+ _mmplayer_bus_watcher_remove(player);
__mmplayer_gst_destroy_pipeline(player);
return MM_ERROR_PLAYER_INTERNAL;
}
MMPLAYER_FREEIF(player->type);
player->no_more_pad = FALSE;
player->num_dynamic_pad = 0;
- player->demux_pad_index = 0;
MMPLAYER_SUBTITLE_INFO_LOCK(player);
player->subtitle_language_list = NULL;
if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
- /* free avsysaudiosink
- avsysaudiosink should be unref when destory pipeline just after start play with BT.
- Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
- */
MMPLAYER_FREEIF(audiobin);
MMPLAYER_FREEIF(videobin);
MMPLAYER_FREEIF(textbin);
}
MMPLAYER_FREEIF(player->album_art);
+ if (player->type_caps) {
+ gst_caps_unref(player->type_caps);
+ player->type_caps = NULL;
+ }
+
if (player->v_stream_caps) {
gst_caps_unref(player->v_stream_caps);
player->v_stream_caps = NULL;
/* destroy pipeline */
ret = __mmplayer_gst_destroy_pipeline(player);
if (ret != MM_ERROR_NONE) {
- LOGE("failed to destory pipeline");
+ LOGE("failed to destroy pipeline");
return ret;
}
return ret;
}
-static gboolean
-__mmplayer_can_do_interrupt(mmplayer_t *player)
-{
- if (!player || !player->pipeline || !player->attrs) {
- LOGW("not initialized");
- goto FAILED;
- }
-
- if (player->audio_decoded_cb) {
- LOGW("not support in pcm extraction mode");
- goto FAILED;
- }
-
- /* check if seeking */
- if (player->seek_state != MMPLAYER_SEEK_NONE) {
- MMMessageParamType msg_param;
- memset(&msg_param, 0, sizeof(MMMessageParamType));
- msg_param.code = MM_ERROR_PLAYER_SEEK;
- player->seek_state = MMPLAYER_SEEK_NONE;
- MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
- goto FAILED;
- }
-
- /* check other thread */
- if (!MMPLAYER_CMD_TRYLOCK(player)) {
- LOGW("locked already, cmd state : %d", player->cmd);
-
- /* check application command */
- if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
- LOGW("playing.. should wait cmd lock then, will be interrupted");
-
- /* lock will be released at mrp_resource_release_cb() */
- MMPLAYER_CMD_LOCK(player);
- goto INTERRUPT;
- }
- LOGW("nothing to do");
- goto FAILED;
- } else {
- LOGW("can interrupt immediately");
- goto INTERRUPT;
- }
-
-FAILED: /* with CMD UNLOCKED */
- return FALSE;
-
-INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
- return TRUE;
-}
-
static int
__resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
void *user_data)
if (!user_data) {
LOGE("user_data is null");
- return FALSE;
+ return TRUE;
}
+
player = (mmplayer_t *)user_data;
- if (!__mmplayer_can_do_interrupt(player)) {
- LOGW("no need to interrupt, so leave");
- /* FIXME: there is no way to avoid releasing resource. */
- return FALSE;
+ if (!player->pipeline || !player->attrs) {
+ LOGW("not initialized");
+ return TRUE;
+ }
+
+ LOGD("cmd lock player, cmd state : %d", player->cmd);
+ MMPLAYER_CMD_LOCK(player);
+ LOGD("cmd locked player");
+
+ if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
+ || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
+ LOGW("player already destroyed");
+ MMPLAYER_CMD_UNLOCK(player);
+ return TRUE;
}
player->interrupted_by_resource = TRUE;
LOGW("failed to get play position.");
}
+ MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
+
LOGD("video resource conflict so, resource will be freed by unrealizing");
if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
LOGE("failed to unrealize");
- /* lock is called in __mmplayer_can_do_interrupt() */
MMPLAYER_CMD_UNLOCK(player);
for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
ret = _mmplayer_initialize_video_capture(player);
if (ret != MM_ERROR_NONE) {
- LOGE("failed to initialize video capture");
- goto ERROR;
+ LOGW("video capture is not supported");
+ /* do not handle as error for headless profile */
}
/* initialize resource manager */
if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
__resource_release_cb, player, &player->resource_manager)
!= MM_RESOURCE_MANAGER_ERROR_NONE) {
- LOGE("failed to initialize resource manager");
+ LOGE("failed to create resource manager");
ret = MM_ERROR_PLAYER_INTERNAL;
goto ERROR;
}
MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
- LOGD("waitting for gapless play thread exit");
+ LOGD("waiting for gapless play thread exit");
g_thread_join(player->gapless_play_thread);
g_mutex_clear(&player->gapless_play_thread_mutex);
g_cond_clear(&player->gapless_play_thread_cond);
_mmplayer_release_video_capture(player);
- /* de-initialize resource manager */
- if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
- player->resource_manager))
- LOGE("failed to deinitialize resource manager");
-
/* release miscellaneous information */
__mmplayer_release_misc(player);
/* release pipeline */
- if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
- LOGE("failed to destory pipeline");
+ if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
+ LOGE("failed to destroy pipeline");
return MM_ERROR_PLAYER_INTERNAL;
}
+ __mmplayer_destroy_hw_resource(player);
+
g_queue_free(player->bus_msg_q);
/* release subtitle info lock and cond */
_mmplayer_deconstruct_attribute(handle);
if (player->uri_info.uri_list) {
- GList *uri_list = player->uri_info.uri_list;
- for (; uri_list; uri_list = g_list_next(uri_list)) {
- gchar *uri = uri_list->data;
- MMPLAYER_FREEIF(uri);
- }
- g_list_free(player->uri_info.uri_list);
+ g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
player->uri_info.uri_list = NULL;
}
char *uri = NULL;
void *param = NULL;
MMHandleType attrs = 0;
- int video_codec_type = 0;
- int audio_codec_type = 0;
- int default_codec_type = 0;
+
MMPLAYER_FENTER();
/* check player handle */
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->streamer->buffering_req.rebuffer_time);
}
- mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
- if (!strcmp(player->ini.audiocodec_default_type, "hw"))
- default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
- else
- default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
-
- if (audio_codec_type != default_codec_type) {
- LOGD("audio dec sorting is required");
- player->need_audio_dec_sorting = TRUE;
- }
-
- mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
- if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
- LOGD("video dec sorting is required");
- player->need_video_dec_sorting = TRUE;
- }
-
/* realize pipeline */
ret = __mmplayer_gst_realize(player);
if (ret != MM_ERROR_NONE)
{
mmplayer_t *player = (mmplayer_t *)hplayer;
int ret = MM_ERROR_NONE;
+ int rm_ret = MM_ERROR_NONE;
+ mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
MMPLAYER_FENTER();
MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
MMPLAYER_CMD_UNLOCK(player);
+ _mmplayer_bus_watcher_remove(player);
/* destroy the gst bus msg thread which is created during realize.
this funct have to be called before getting cmd lock. */
_mmplayer_bus_msg_thread_destroy(player);
/* unrealize pipeline */
ret = __mmplayer_gst_unrealize(player);
- if (!player->interrupted_by_resource) {
- int rm_ret = MM_ERROR_NONE;
- mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
-
- for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
- rm_ret = __mmplayer_release_hw_resource(player, res_idx);
- if (rm_ret != MM_ERROR_NONE)
- LOGE("failed to release [%d] resources", res_idx);
- }
+ for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
+ rm_ret = __mmplayer_release_hw_resource(player, res_idx);
+ if (rm_ret != MM_ERROR_NONE)
+ LOGE("failed to release [%d] resources", res_idx);
}
+ player->interrupted_by_resource = FALSE;
+
MMPLAYER_FLEAVE();
return ret;
}
/* check current state */
MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
- /* check pipline reconfigure state */
+ /* check pipeline reconfigure state */
__mmplayer_check_pipeline_reconfigure_state(player);
switch (MMPLAYER_CURRENT_STATE(player)) {
case MM_PLAYER_STATE_READY:
{
/* check prepare async or not.
- * In the case of streaming playback, it's recommned to avoid blocking wait.
+ * In the case of streaming playback, it's recommended to avoid blocking wait.
*/
mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
LOGD("prepare working mode : %s", (async ? "async" : "sync"));
/* pause pipeline */
ret = _mmplayer_gst_pause(player, async);
-
- if (ret != MM_ERROR_NONE)
+ if (ret != MM_ERROR_NONE) {
LOGE("failed to pause player. ret : 0x%x", ret);
+ MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
+ return ret;
+ }
if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
}
MMPLAYER_FLEAVE();
-
- return ret;
+ return MM_ERROR_NONE;
}
/* in case of streaming, pause could take long time.*/
player->pipeline->mainbin,
MM_ERROR_PLAYER_NOT_INITIALIZED);
- LOGD("set the pipeline state to READY");
+ if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
+ LOGD("set the videobin state to READY");
+ ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
+ GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
- /* set state to READY */
+ }
+
+ if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
+ LOGD("set the audiobin state to READY");
+ ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
+ GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
+
+ }
+
+ LOGD("set the pipeline state to READY");
ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
+
if (ret != MM_ERROR_NONE) {
LOGE("fail to change state to READY");
return MM_ERROR_PLAYER_INTERNAL;
MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
- /* check pipline reconfigure state */
+ /* check pipeline reconfigure state */
__mmplayer_check_pipeline_reconfigure_state(player);
ret = _mmplayer_gst_set_position(player, position, FALSE);
}
int
-_mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
+_mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
{
mmplayer_t *player = (mmplayer_t *)hplayer;
int ret = MM_ERROR_NONE;
return FALSE;
}
-static void
-__mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
+void
+_mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
{
GstStructure *caps_structure = NULL;
gint samplerate = 0;
GstCaps *caps, gpointer data)
{
mmplayer_t *player = (mmplayer_t *)data;
- GstPad *pad = NULL;
MMPLAYER_FENTER();
MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
/* store type string */
+ if (player->type_caps) {
+ gst_caps_unref(player->type_caps);
+ player->type_caps = NULL;
+ }
+
+ player->type_caps = gst_caps_copy(caps);
+ MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
+
MMPLAYER_FREEIF(player->type);
player->type = gst_caps_to_string(caps);
if (player->type)
__mmplayer_update_content_type_info(player);
- pad = gst_element_get_static_pad(tf, "src");
- if (!pad) {
- LOGE("fail to get typefind src pad.");
- return;
- }
+ if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
+ GstPad *pad = NULL;
- if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
- gboolean async = FALSE;
- LOGE("failed to autoplug %s", player->type);
+ pad = gst_element_get_static_pad(tf, "src");
+ if (!pad) {
+ LOGE("fail to get typefind src pad.");
+ return;
+ }
- mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
+ if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
+ gboolean async = FALSE;
+ LOGE("failed to autoplug %s", player->type);
- if (async && player->msg_posted == FALSE)
- __mmplayer_handle_missed_plugin(player);
+ mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
+ if (async && player->msg_posted == FALSE)
+ __mmplayer_handle_missed_plugin(player);
+ }
+ gst_object_unref(GST_OBJECT(pad));
}
-
- gst_object_unref(GST_OBJECT(pad));
-
MMPLAYER_FLEAVE();
-
return;
}
/* no-more-pad pad handling signal */
_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);
+ G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)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);
+ 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_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
- G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
+ 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_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
- G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
+ G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
_mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
/* This signal is emitted once decodebin has finished decoding all the data.*/
_mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
- G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
+ G_CALLBACK(_mmplayer_gst_decode_drained), (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",
return MM_ERROR_NONE;
}
-static void
-__mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
+void
+_mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
{
mmplayer_t *player = (mmplayer_t *)data;
/* remove fakesink. */
if (!_mmplayer_gst_remove_fakesink(player,
&player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
- /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
+ /* 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 FALSE;
}
+static void
+__mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
+{
+ GstPad *sinkpad = g_value_get_object (item);
+ GstElement *element = GST_ELEMENT(user_data);
+ if (!sinkpad || !element) {
+ LOGE("invalid parameter");
+ return;
+ }
+
+ LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
+ gst_element_release_request_pad(element, GST_PAD(sinkpad));
+}
+
+static gboolean
+__mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
+{
+ mmplayer_gst_element_t *sinkbin = NULL;
+ main_element_id_e concatId = MMPLAYER_M_NUM;
+ main_element_id_e sinkId = MMPLAYER_M_NUM;
+ gboolean send_notice = FALSE;
+ GstElement *element;
+ GstIterator *iter;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
+
+ LOGD("type %d", type);
+
+ switch (type) {
+ case MM_PLAYER_TRACK_TYPE_AUDIO:
+ concatId = MMPLAYER_M_A_CONCAT;
+ sinkId = MMPLAYER_A_BIN;
+ sinkbin = player->pipeline->audiobin;
+ break;
+ case MM_PLAYER_TRACK_TYPE_VIDEO:
+ concatId = MMPLAYER_M_V_CONCAT;
+ sinkId = MMPLAYER_V_BIN;
+ sinkbin = player->pipeline->videobin;
+ send_notice = TRUE;
+ break;
+ case MM_PLAYER_TRACK_TYPE_TEXT:
+ concatId = MMPLAYER_M_T_CONCAT;
+ sinkId = MMPLAYER_T_BIN;
+ sinkbin = player->pipeline->textbin;
+ break;
+ default:
+ LOGE("requested type is not supportable");
+ return FALSE;
+ break;
+ }
+
+ element = player->pipeline->mainbin[concatId].gst;
+ if (!element)
+ return TRUE;
+
+ if ((sinkbin) && (sinkbin[sinkId].gst)) {
+ GstPad *srcpad = gst_element_get_static_pad(element, "src");
+ GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
+ if (srcpad && sinkpad) {
+ /* after getting drained signal there is no data flows, so no need to do pad_block */
+ LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
+ gst_pad_unlink(srcpad, sinkpad);
+
+ /* send custom event to sink pad to handle it at video sink */
+ if (send_notice) {
+ LOGD("send custom event to sinkpad");
+ GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
+ GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
+ gst_pad_send_event(sinkpad, event);
+ }
+ }
+ gst_object_unref(srcpad);
+ gst_object_unref(sinkpad);
+ }
+
+ LOGD("release concat request pad");
+ /* release and unref requests pad from the selector */
+ iter = gst_element_iterate_sink_pads(element);
+ while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
+ gst_iterator_resync(iter);
+ gst_iterator_free(iter);
+
+ return TRUE;
+}
+
static gboolean
__mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
{
- mmplayer_selector_t *selector = &player->selector[type];
+ mmplayer_track_t *selector = &player->track[type];
mmplayer_gst_element_t *sinkbin = NULL;
main_element_id_e selectorId = MMPLAYER_M_NUM;
main_element_id_e sinkId = MMPLAYER_M_NUM;
LOGD("selector release");
/* release and unref requests pad from the selector */
- for (n = 0; n < selector->channels->len; n++) {
- GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
+ for (n = 0; n < selector->streams->len; n++) {
+ GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
}
- g_ptr_array_set_size(selector->channels, 0);
+
+ g_ptr_array_set_size(selector->streams, 0);
gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
MMPLAYER_FENTER();
MMPLAYER_RETURN_IF_FAIL(player);
- if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
- (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
- (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
- LOGE("deactivate selector error");
- goto ERROR;
+ if (MMPLAYER_USE_DECODEBIN(player)) {
+ if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
+ (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
+ (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
+ LOGE("deactivate selector error");
+ goto ERROR;
+ }
+ } else {
+ if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
+ (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
+ (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
+ LOGE("deactivate concat error");
+ goto ERROR;
+ }
}
_mmplayer_track_destroy(player);
player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
SECURE_LOGD("add original path : %s", uri);
} else {
- player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
- player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
-
+ g_free(g_list_nth_data(player->uri_info.uri_list, 0));
+ player->uri_info.uri_list = g_list_prepend(
+ g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
SECURE_LOGD("change original path : %s", uri);
}
} else {
if (num_of_list > 0) {
gint uri_idx = player->uri_info.uri_idx;
- if (uri_idx < num_of_list-1)
+ if (uri_idx < num_of_list - 1)
uri_idx++;
else
uri_idx = 0;
return MM_ERROR_NONE;
}
-static void
-__mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
+void
+_mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
GstCaps *caps, gpointer data)
{
mmplayer_t *player = (mmplayer_t *)data;
__mmplayer_check_not_supported_codec(player, klass, mime);
}
-static gboolean
-__mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
- GstCaps *caps, gpointer data)
+gboolean
+_mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
+ GstCaps *caps, gpointer data)
{
mmplayer_t *player = (mmplayer_t *)data;
const char *mime = NULL;
}
gst_object_unref(factory);
- if (__mmplayer_acquire_hw_resource(player,
+ if (_mmplayer_acquire_hw_resource(player,
MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
LOGE("failed to acquire audio offload decoder resource");
goto DONE;
/* set stream information */
if (!player->audiodec_linked)
- __mmplayer_set_audio_attrs(player, caps);
+ _mmplayer_set_audio_attrs(player, caps);
/* update codec info */
player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
goto DONE;
}
- if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
+ if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
LOGE("failed to acquire video decoder resource");
ret = GST_AUTOPLUG_SELECT_SKIP;
goto DONE;
gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
factory = g_value_get_object(g_value_array_get_nth(factories, i));
+ if (!factory) {
+ LOGW("failed to get factory object");
+ continue;
+ }
klass = gst_element_factory_get_klass(factory);
factory_name = GST_OBJECT_NAME(factory);
if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
if (hw_dec_idx < first_sw_dec_idx)
return NULL;
- new_pos = first_sw_dec_idx - 1;
+ new_pos = first_sw_dec_idx;
rm_pos = hw_dec_idx + 1;
} else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
if (last_sw_dec_idx < hw_dec_idx)
}
/* change position - insert H/W decoder according to the new position */
- new_factories = g_value_array_copy(factories);
factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
+ if (!factory) {
+ LOGW("failed to get factory object");
+ return NULL;
+ }
+ new_factories = g_value_array_copy(factories);
g_value_init (&val, G_TYPE_OBJECT);
g_value_set_object (&val, factory);
g_value_array_insert(new_factories, new_pos, &val);
for (int i = 0 ; i < new_factories->n_values ; i++) {
factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
-
- LOGD("[Re-arranged] Klass [%s] Factory [%s]",
- gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
+ if (factory)
+ LOGD("[Re-arranged] Klass [%s] Factory [%s]",
+ gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
+ else
+ LOGE("[Re-arranged] failed to get factory object");
}
return new_factories;
/* filtering exclude keyword */
for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
- LOGW("skipping [%s] by exculde keyword [%s]",
+ LOGW("skipping [%s] by exclude keyword [%s]",
factory_name, player->ini.exclude_element_keyword[idx]);
result = GST_AUTOPLUG_SELECT_SKIP;
return result;
}
-static void
-__mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
+void
+_mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
gpointer data)
{
- //mmplayer_t *player = (mmplayer_t *)data;
- GstCaps *caps = NULL;
+ int ret = MM_ERROR_NONE;
+ mmplayer_t *player = (mmplayer_t *)data;
+ mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
+ mmplayer_gst_element_t *videobin = player->pipeline->videobin;
+ gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
- LOGD("[Decodebin2] pad-removed signal");
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
- caps = gst_pad_query_caps(new_pad, NULL);
- if (!caps) {
- LOGW("query caps is NULL");
+ LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
+
+ if (MMPLAYER_USE_DECODEBIN(player))
+ return;
+
+ if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
+ return;
+
+ ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst, GST_STATE_NULL, FALSE, timeout);
+ if (ret != MM_ERROR_NONE) {
+ LOGE("fail to change state to NULL");
return;
}
- gchar *caps_str = NULL;
- caps_str = gst_caps_to_string(caps);
+ ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL, FALSE, timeout);
+ if (ret != MM_ERROR_NONE) {
+ LOGE("fail to change state to NULL");
+ return;
+ }
- LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
+ if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
+ LOGE("failed to remove video concat");
+ }
- MMPLAYER_FREEIF(caps_str);
- gst_caps_unref(caps);
+ if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
+ LOGE("failed to remove videobin");
+ }
+
+ gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
+ mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
+ mainbin[MMPLAYER_M_V_CONCAT].id = 0;
+
+ gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
+ MMPLAYER_FREEIF(player->pipeline->videobin);
+
+ ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
+ if (ret != MM_ERROR_NONE)
+ LOGE("failed to release overlay resources");
+
+ player->videodec_linked = 0;
+
+ MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
+ MMPLAYER_FLEAVE();
}
-static void
-__mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
+void
+_mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
+{
+ mmplayer_t *player = (mmplayer_t *)data;
+
+ MMPLAYER_FENTER();
+ MMPLAYER_RETURN_IF_FAIL(player);
+
+ LOGD("got about to finish signal");
+
+ if (!MMPLAYER_CMD_TRYLOCK(player)) {
+ LOGW("Fail to get cmd lock");
+ return;
+ }
+
+ if (!__mmplayer_verify_gapless_play_path(player)) {
+ LOGD("decoding is finished.");
+ MMPLAYER_CMD_UNLOCK(player);
+ return;
+ }
+
+ _mmplayer_set_reconfigure_state(player, TRUE);
+ MMPLAYER_CMD_UNLOCK(player);
+
+ MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
+ __mmplayer_deactivate_old_path(player);
+
+ MMPLAYER_FLEAVE();
+}
+
+void
+_mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
{
mmplayer_t *player = (mmplayer_t *)data;
GstIterator *iter = NULL;
MMPLAYER_FENTER();
MMPLAYER_RETURN_IF_FAIL(player);
- LOGD("__mmplayer_gst_decode_drained");
+ LOGD("got drained signal");
if (!MMPLAYER_CMD_TRYLOCK(player)) {
LOGW("Fail to get cmd lock");
player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
/* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
- MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
+ MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
__mmplayer_deactivate_old_path(player);
MMPLAYER_FLEAVE();
gchar *selected = NULL;
selected = g_strdup(GST_ELEMENT_NAME(element));
player->audio_decoders = g_list_append(player->audio_decoders, selected);
+
+ /* update codec info */
+ player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
+ player->can_support_codec |= FOUND_PLUGIN_AUDIO;
+ player->audiodec_linked = 1;
+ } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
+ /* update codec info */
+ player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
+ player->can_support_codec |= FOUND_PLUGIN_VIDEO;
+ player->videodec_linked = 1;
}
if (g_strrstr(klass, "Demuxer/Adaptive")) {
#endif
player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
+ } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
+ player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
+ player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
}
if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
}
} else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
+ } else if (g_strrstr(factory_name, "omxdec_h264")) {
+ GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
+ if (video_parse && (g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
+ g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
+ LOGD("Send SPS and PPS Insertion every IDR frame");
+ }
}
if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
static void
__mmplayer_release_misc_post(mmplayer_t *player)
{
- char *original_uri = NULL;
+ gchar *original_uri = NULL;
MMPLAYER_FENTER();
/* player->pipeline is already released before. */
player->audio_stream_changed_cb = NULL;
player->audio_stream_changed_cb_user_param = NULL;
- mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
+ mm_player_set_attribute((MMHandleType)player, NULL,
+ "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
/* clean found audio decoders */
if (player->audio_decoders) {
- GList *a_dec = player->audio_decoders;
- for (; a_dec; a_dec = g_list_next(a_dec)) {
- gchar *name = a_dec->data;
- MMPLAYER_FREEIF(name);
- }
- g_list_free(player->audio_decoders);
+ g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
player->audio_decoders = NULL;
}
/* clean the uri list except original uri */
if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
+ GList *tmp = NULL;
original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
+ tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
+ g_list_free_full(tmp, (GDestroyNotify)g_free);
+
if (!original_uri)
LOGW("failed to get original uri info");
mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
-
- GList *uri_list = player->uri_info.uri_list;
- for (; uri_list; uri_list = g_list_next(uri_list)) {
- gchar *uri = uri_list->data;
- if (original_uri != uri)
- MMPLAYER_FREEIF(uri);
- }
+ MMPLAYER_FREEIF(original_uri);
}
/* clear the audio stream buffer list */
}
static void
-__mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
+__mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
{
MMPLAYER_FENTER();
MMPLAYER_RETURN_IF_FAIL(player);
MMPLAYER_RETURN_IF_FAIL(sink);
- player->sink_elements = g_list_append(player->sink_elements, sink);
+ if (first)
+ player->sink_elements = g_list_prepend(player->sink_elements, sink);
+ else
+ player->sink_elements = g_list_append(player->sink_elements, sink);
MMPLAYER_FLEAVE();
}
for (; sig_list; sig_list = sig_list->next) {
item = sig_list->data;
- if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
+ if (item && item->obj) {
if (g_signal_handler_is_connected(item->obj, item->sig))
g_signal_handler_disconnect(item->obj, item->sig);
}
/* release signal */
__mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
- /* release textbin with it's childs */
+ /* release textbin with it's children */
MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
MMPLAYER_FREEIF(player->pipeline->textbin);
player->pipeline->textbin = NULL;
}
static int
+__mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
+{
+ guint active_idx = 0;
+ GstStream *stream = NULL;
+ GList *streams = NULL;
+ GstCaps *caps = NULL;
+
+ MMPLAYER_FENTER();
+ LOGD("Switching Streams... type: %d, index: %d", type, index);
+
+ player->track[type].active_track_index = index;
+
+ for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
+ /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
+ LOGD("track type:%d, total: %d, active: %d", i,
+ player->track[i].total_track_num, player->track[i].active_track_index);
+ if (player->track[i].total_track_num > 0 &&
+ player->track[i].active_track_index > INVALID_TRACK_INDEX) {
+ active_idx = player->track[i].active_track_index;
+ stream = g_ptr_array_index(player->track[i].streams, active_idx);
+ streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
+ LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
+
+ if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
+ caps = gst_stream_get_caps(stream);
+ if (caps) {
+ _mmplayer_set_audio_attrs(player, caps);
+ gst_caps_unref(caps);
+ }
+ }
+ }
+ }
+
+ if (streams) {
+ LOGD("send select stream event");
+ gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
+ gst_event_new_select_streams(streams));
+ g_list_free(streams);
+ }
+
+ MMPLAYER_FLEAVE();
+ return MM_ERROR_NONE;
+}
+
+static int
__mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
{
int result = MM_ERROR_NONE;
goto EXIT;
}
- total_track_num = player->selector[type].total_track_num;
+ total_track_num = player->track[type].total_track_num;
if (total_track_num <= 0) {
result = MM_ERROR_PLAYER_NO_OP;
LOGD("Language list is not available");
gst_object_unref(sinkpad);
if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
- __mmplayer_set_audio_attrs(player, caps);
+ _mmplayer_set_audio_attrs(player, caps);
+
+ if (caps)
+ gst_caps_unref(caps);
EXIT:
MMPLAYER_FREEIF(change_pad_name);
gint current_active_index = 0;
GstState current_state = GST_STATE_VOID_PENDING;
- GstEvent *event = NULL;
gint64 time = 0;
MMPLAYER_FENTER();
if (!player->pipeline) {
LOGE("Track %d pre setting -> %d", type, index);
- player->selector[type].active_pad_index = index;
+ player->track[type].active_track_index = index;
goto EXIT;
}
mainbin = player->pipeline->mainbin;
- current_active_index = player->selector[type].active_pad_index;
+ current_active_index = player->track[type].active_track_index;
/*If index is same as running index no need to change the pad*/
if (current_active_index == index)
current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
if (current_state < GST_STATE_PAUSED) {
result = MM_ERROR_PLAYER_INVALID_STATE;
- LOGW("Pipeline not in porper state");
+ LOGW("Pipeline not in proper state");
goto EXIT;
}
- result = __mmplayer_change_selector_pad(player, type, index);
+ if (MMPLAYER_USE_DECODEBIN(player))
+ result = __mmplayer_change_selector_pad(player, type, index);
+ else
+ result = __mmplayer_switch_stream(player, type, index);
+
if (result != MM_ERROR_NONE) {
- LOGE("change selector pad error");
+ LOGE("failed to change track");
goto EXIT;
}
- player->selector[type].active_pad_index = index;
+ player->track[type].active_track_index = index;
- if (current_state == GST_STATE_PLAYING) {
- event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
- (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
- GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
- if (event) {
- _mmplayer_gst_send_event_to_sink(player, event);
- } else {
- result = MM_ERROR_PLAYER_INTERNAL;
- goto EXIT;
+ if (MMPLAYER_USE_DECODEBIN(player)) {
+ GstEvent *event = NULL;
+ if (current_state == GST_STATE_PLAYING) {
+ event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
+ (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
+ GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
+ if (event) {
+ _mmplayer_gst_send_event_to_sink(player, event);
+ } else {
+ result = MM_ERROR_PLAYER_INTERNAL;
+ goto EXIT;
+ }
}
}
if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
return MM_ERROR_NONE;
- /* FIXME: text path should be handled seperately. */
+ /* FIXME: text path should be handled separately. */
if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
&& (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
{
#define IDX_FIRST_SW_CODEC 0
mmplayer_t *player = (mmplayer_t *)hplayer;
- const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
+ int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
+ const char *attr_name = NULL;
+ const char *default_type = NULL;
+ const char *element_hw = NULL;
+ const char *element_sw = NULL;
MMPLAYER_FENTER();
MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
- LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
- player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
- player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
+ LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
+ /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
switch (stream_type) {
case MM_PLAYER_STREAM_TYPE_AUDIO:
- /* to support audio codec selection, codec info have to be added in ini file as below.
- audio codec element hw = xxxx
- audio codec element sw = avdec
- and in case of audio hw codec is supported and selected,
- audio filter elements should be applied depending on the hw capabilities.
- */
- if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
- (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
- ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
- (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
- LOGE("There is no audio codec info for codec_type %d", codec_type);
- return MM_ERROR_PLAYER_NO_OP;
- }
- break;
+ attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
+ default_type = player->ini.audiocodec_default_type;
+ element_hw = player->ini.audiocodec_element_hw;
+ element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
+ break;
case MM_PLAYER_STREAM_TYPE_VIDEO:
- /* to support video codec selection, codec info have to be added in ini file as below.
- video codec element hw = omx
- video codec element sw = avdec */
- if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
- (!strcmp(player->ini.videocodec_element_hw, ""))) ||
- ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
- (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
- LOGE("There is no video codec info for codec_type %d", codec_type);
- return MM_ERROR_PLAYER_NO_OP;
- }
- break;
+ attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
+ default_type = player->ini.videocodec_default_type;
+ element_hw = player->ini.videocodec_element_hw;
+ element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
+ break;
default:
LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
return MM_ERROR_COMMON_INVALID_ARGUMENT;
- break;
+ break;
+ }
+
+ LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
+
+ if (!strcmp(default_type, "sw"))
+ default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
+ else
+ default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
+
+ if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
+ codec_type = default_codec_type;
+
+ /* to support codec selection, codec info have to be added in ini file.
+ in case of hw codec is selected, filter elements should be applied
+ depending on the hw capabilities. */
+ if (codec_type != default_codec_type) {
+ if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
+ ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
+ LOGE("There is no codec for type %d", codec_type);
+ return MM_ERROR_PLAYER_NO_OP;
+ }
+
+ LOGD("sorting is required");
+ if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
+ player->need_audio_dec_sorting = TRUE;
+ else
+ player->need_video_dec_sorting = TRUE;
}
LOGD("update %s codec_type to %d", attr_name, codec_type);
}
if (!caps_v) {
- LOGD("no negitiated caps from videosink");
+ LOGD("no negotiated caps from videosink");
gst_object_unref(pad);
return FALSE;
}
gchar *path = NULL;
struct stat sb;
- /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
+ /* FIXIT : please make it clear the dependency with duration/codec/uritype */
if (!player->duration)
return FALSE;
/* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
if (ret == MM_ERROR_NONE) {
- g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
if (_mmplayer_is_sdp_file(path)) {
LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
+ g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
} else {
+ g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
data->uri_type = MM_PLAYER_URI_TYPE_FILE;
}
} else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
/* try to get content metadata */
/* NOTE : giving ATTR_MISSING_ONLY may have dependency with
- * c-api since c-api doesn't use _start() anymore. It may not work propery with
+ * c-api since c-api doesn't use _start() anymore. It may not work properly with
* legacy mmfw-player api
*/
_mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);