X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fmm_player_priv.c;h=6b19906a6b7585bb4f6c1b9f8f2964c6a4564797;hb=88c7b7ae174c0de56c378c3ed15bd82bd1f74f85;hp=f1c55cbc1ee75dab5ff755114ad2d55d08afd229;hpb=3d694beb71bd99abcbfc4ea26b5b6aa4ba9ce1d9;p=platform%2Fcore%2Fmultimedia%2Flibmm-player.git diff --git a/src/mm_player_priv.c b/src/mm_player_priv.c index f1c55cb..6b19906 100644 --- a/src/mm_player_priv.c +++ b/src/mm_player_priv.c @@ -43,7 +43,6 @@ #include "mm_player_priv.h" #include "mm_player_ini.h" -#include "mm_player_attrs.h" #include "mm_player_capture.h" #include "mm_player_utils.h" #include "mm_player_tracks.h" @@ -84,12 +83,11 @@ #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 #define DEFAULT_PLAYBACK_RATE 1.0 -#define DEFAULT_NUM_OF_V_OUT_BUFFER 3 #define PLAYER_DISPLAY_MODE_DST_ROI 5 @@ -142,18 +140,10 @@ static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player); 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 GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data); -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); @@ -167,7 +157,7 @@ static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_typ 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); @@ -181,16 +171,15 @@ static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCal /* util */ static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player); -static void __mmplayer_activate_next_source(mmplayer_t *player, GstState target); -static void __mmplayer_check_pipeline(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_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data); static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer); static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type); -static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data); static gboolean __mmplayer_update_duration_value(mmplayer_t *player); static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs); static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs); @@ -213,40 +202,10 @@ static void __mmplayer_set_playing_state(mmplayer_t *player); | | ========================================================================================== */ -#if 0 //debug -static void -print_tag(const GstTagList *list, const gchar *tag, gpointer unused) -{ - gint i, count; - - count = gst_tag_list_get_tag_size(list, tag); - - LOGD("count = %d", count); - - for (i = 0; i < count; i++) { - gchar *str; - - if (gst_tag_get_type(tag) == G_TYPE_STRING) { - if (!gst_tag_list_get_string_index(list, tag, i, &str)) - g_assert_not_reached(); - } else { - str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i)); - } - - if (i == 0) - g_print(" %15s: %s", gst_tag_get_nick(tag), str); - else - g_print(" : %s", str); - - g_free(str); - } -} -#endif - /* This function should be called after the pipeline goes PAUSED or higher state. */ gboolean -__mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag) +_mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag) { static gboolean has_duration = FALSE; static gboolean has_video_attrs = FALSE; @@ -308,19 +267,13 @@ __mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag) if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs); - /* validate all */ - if (mm_attrs_commit_all(attrs)) { - LOGE("failed to update attributes"); - return FALSE; - } - MMPLAYER_FLEAVE(); return TRUE; } MMStreamingType -__mmplayer_get_stream_service_type(mmplayer_t *player) +_mmplayer_get_stream_service_type(mmplayer_t *player) { MMStreamingType streaming_type = STREAMING_SERVICE_NONE; @@ -357,10 +310,10 @@ __mmplayer_get_stream_service_type(mmplayer_t *player) } /* 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_set_state(mmplayer_t *player, int state) { MMMessageParamType msg = {0, }; @@ -430,15 +383,15 @@ __mmplayer_set_state(mmplayer_t *player, int state) } int -__mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command) +_mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command) { mmplayer_state_e current_state = MM_PLAYER_STATE_NUM; mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM; MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - //LOGD("incomming command : %d ", command); - +#ifdef __DEBUG__ + LOGD("incoming command : %d ", command); +#endif current_state = MMPLAYER_CURRENT_STATE(player); pending_state = MMPLAYER_PENDING_STATE(player); @@ -538,7 +491,7 @@ __mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command) 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; @@ -598,6 +551,176 @@ ALREADY_GOING: return MM_ERROR_PLAYER_NO_OP; } +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; + + switch (type) { + case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER: + rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER; + break; + case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY: + rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY; + break; + case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD: + rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD; + break; + default: + LOGE("invalid mmplayer resource type %d", type); + return MM_ERROR_PLAYER_INTERNAL; + } + + if (player->hw_resource[type] != NULL) { + LOGD("[%d type] resource was already acquired", type); + return MM_ERROR_NONE; + } + + LOGD("mark for acquire [%d type] resource", type); + rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager, + rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]); + if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) { + LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret); + 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_PLAYER_INTERNAL; + } + + MMPLAYER_FLEAVE(); + 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; + + MMPLAYER_FENTER(); + + if (player->hw_resource[type] == NULL) { + LOGD("there is no acquired [%d type] resource", type); + return MM_ERROR_NONE; + } + + LOGD("mark for release [%d type] resource", type); + rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]); + if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) { + LOGE("failed to mark resource for release, ret(0x%x)", rm_ret); + return MM_ERROR_PLAYER_INTERNAL; + } + + 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 resource, ret(0x%x)", rm_ret); + return MM_ERROR_PLAYER_INTERNAL; + } + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; +} + +static void +__mmplayer_initialize_gapless_play(mmplayer_t *player) +{ + int i; + + MMPLAYER_FENTER(); + + player->smooth_streaming = FALSE; + player->videodec_linked = 0; + player->audiodec_linked = 0; + player->textsink_linked = 0; + player->is_external_subtitle_present = FALSE; + player->is_external_subtitle_added_now = FALSE; + player->not_supported_codec = MISSING_PLUGIN_NONE; + player->can_support_codec = FOUND_PLUGIN_NONE; + player->pending_seek.is_pending = false; + player->pending_seek.pos = 0; + player->msg_posted = FALSE; + player->has_many_types = FALSE; + player->no_more_pad = FALSE; + player->not_found_demuxer = 0; + player->seek_state = MMPLAYER_SEEK_NONE; + player->is_subtitle_force_drop = FALSE; + player->play_subtitle = FALSE; + player->adjust_subtitle_pos = 0; + + player->total_bitrate = 0; + player->total_maximum_bitrate = 0; + + _mmplayer_track_initialize(player); + __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX); + + for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) { + player->bitrate[i] = 0; + player->maximum_bitrate[i] = 0; + } + + if (player->v_stream_caps) { + gst_caps_unref(player->v_stream_caps); + player->v_stream_caps = NULL; + } + + mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL); + + /* clean found audio decoders */ + if (player->audio_decoders) { + g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free); + player->audio_decoders = NULL; + } + + __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER); + + MMPLAYER_FLEAVE(); +} + +void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state) +{ + LOGI("set pipeline reconfigure state %d", state); + MMPLAYER_RECONFIGURE_LOCK(player); + player->gapless.reconfigure = state; + if (!state) /* wake up the waiting job */ + MMPLAYER_RECONFIGURE_SIGNAL(player); + MMPLAYER_RECONFIGURE_UNLOCK(player); +} + static gpointer __mmplayer_gapless_play_thread(gpointer data) { @@ -614,10 +737,7 @@ __mmplayer_gapless_play_thread(gpointer data) LOGD("reconfigure pipeline for gapless play."); if (player->gapless_play_thread_exit) { - if (player->gapless.reconfigure) { - player->gapless.reconfigure = false; - MMPLAYER_PLAYBACK_UNLOCK(player); - } + _mmplayer_set_reconfigure_state(player, FALSE); LOGD("exiting gapless play thread"); break; } @@ -630,7 +750,10 @@ __mmplayer_gapless_play_thread(gpointer data) MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND); MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC); - __mmplayer_activate_next_source(player, GST_STATE_PLAYING); + /* Initialize Player values */ + __mmplayer_initialize_gapless_play(player); + + _mmplayer_activate_next_source(player, GST_STATE_PLAYING); } MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player); @@ -654,19 +777,50 @@ __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id) } void -__mmplayer_bus_msg_thread_destroy(MMHandleType hplayer) +_mmplayer_watcher_removed_notify(gpointer data) { - mmplayer_t *player = (mmplayer_t *)hplayer; - GstMessage *msg = NULL; - GQueue *queue = NULL; + 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) + if (player->bus_watcher > 0) { __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher); - player->bus_watcher = 0; + MMPLAYER_BUS_WATCHER_LOCK(player); + end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND; + while (player->bus_watcher > 0) + MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time); + 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; + GstMessage *msg = NULL; + GQueue *queue = NULL; + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player); /* destroy the gst bus msg thread */ if (player->bus_msg_thread) { @@ -700,22 +854,16 @@ __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer) } gboolean -__mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink) +_mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink) { GstElement *parent = NULL; MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE); - - /* if we have no fakesink. this meas we are using decodebin which doesn' - t need to add extra fakesink */ - MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE); + MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE); /* lock */ MMPLAYER_FSINK_LOCK(player); - if (!fakesink->gst) - goto ERROR; - /* get parent of fakesink */ parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst); if (!parent) { @@ -726,7 +874,7 @@ __mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakes 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!"); @@ -776,8 +924,10 @@ __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_typ 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)) { - /* LOGW("[%d] skip", idx); */ + !(player->track[idx].event_probe_id)) { +#ifdef __DEBUG__ + LOGW("[%d] skip", idx); +#endif continue; } @@ -838,18 +988,14 @@ __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO; gboolean caps_ret = TRUE; - if (GST_EVENT_IS_DOWNSTREAM(event) && - GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START && - GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP && - GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT && - GST_EVENT_TYPE(event) != GST_EVENT_EOS) { - return ret; - } else if (GST_EVENT_IS_UPSTREAM(event) && - GST_EVENT_TYPE(event) != GST_EVENT_QOS) { + if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START && + GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP && + GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT && + GST_EVENT_TYPE(event) != GST_EVENT_EOS && + 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; @@ -944,11 +1090,13 @@ __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer break; } +#ifdef __DEBUG__ LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(timestamp), GST_TIME_ARGS(running_time_diff), GST_TIME_ARGS(timestamp - running_time_diff)); +#endif timestamp -= running_time_diff; @@ -974,7 +1122,7 @@ 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) { @@ -995,7 +1143,7 @@ __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); @@ -1031,6 +1179,35 @@ EXIT: } 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; @@ -1050,14 +1227,14 @@ __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmp 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); @@ -1072,10 +1249,10 @@ __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmp } void -__mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data) +_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; @@ -1093,12 +1270,14 @@ __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data) 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; MMPLAYER_LOG_GST_CAPS_TYPE(caps); - /* LOGD("detected mimetype : %s", name); */ +#ifdef __DEBUG__ + LOGD("detected mimetype : %s", name); +#endif if (strstr(name, "video")) { gint stype = 0; @@ -1111,13 +1290,13 @@ __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data) MMPLAYER_FREEIF(caps_str); - mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE); + mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL); mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype); 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; } @@ -1128,8 +1307,13 @@ __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data) 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; @@ -1138,7 +1322,7 @@ __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data) 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; } @@ -1149,14 +1333,23 @@ __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data) __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"); @@ -1164,32 +1357,47 @@ __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data) } /* 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: @@ -1206,7 +1414,7 @@ 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; @@ -1215,25 +1423,25 @@ __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_t 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) { @@ -1248,35 +1456,26 @@ __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_t static void __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type) { - MMHandleType attrs = 0; gint active_index = 0; 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; + active_index = player->track[type].active_track_index; if ((active_index != DEFAULT_TRACK) && (__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; return; } - if (type == MM_PLAYER_TRACK_TYPE_TEXT) { - attrs = MMPLAYER_GET_ATTRS(player); - if (attrs) { - mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num); - mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index); - - if (mm_attrs_commit_all(attrs)) - LOGW("failed to commit attrs."); - } else { - LOGW("cannot get content attribute"); - } - } + if (type == MM_PLAYER_TRACK_TYPE_TEXT) + mm_player_set_attribute((MMHandleType)player, 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; @@ -1303,16 +1502,17 @@ __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector } 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; } @@ -1328,20 +1528,20 @@ __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector) 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; } @@ -1364,7 +1564,7 @@ __mmplayer_gst_set_queue2_buffering(mmplayer_t *player) /* there is no mq, enable use-buffering on queue2 (ex) wav streaming * use file information was already set on Q2 when it was created. */ - __mm_player_streaming_set_queue2(player->streamer, + _mm_player_streaming_set_queue2(player->streamer, player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, TRUE, /* use_buffering */ MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */ @@ -1374,8 +1574,8 @@ __mmplayer_gst_set_queue2_buffering(mmplayer_t *player) 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; @@ -1416,7 +1616,7 @@ __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data) 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 */ @@ -1430,11 +1630,7 @@ __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data) __mmplayer_create_text_sink_path(player, text_selector); EXIT: - if (player->gapless.reconfigure) { - player->gapless.reconfigure = FALSE; - MMPLAYER_PLAYBACK_UNLOCK(player); - } - + _mmplayer_set_reconfigure_state(player, FALSE); MMPLAYER_FLEAVE(); } @@ -1501,7 +1697,7 @@ EXIT: } 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; @@ -1519,20 +1715,27 @@ __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data) 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); - - /* LOGD("detected mimetype : %s", name); */ +#ifdef __DEBUG__ + LOGD("detected mimetype : %s", name); +#endif if (strstr(name, "audio")) { if (player->pipeline->audiobin == NULL) { const gchar *audio_format = gst_structure_get_string(str, "format"); if (audio_format) { LOGD("original audio format %s", audio_format); - mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format); + mm_player_set_attribute((MMHandleType)player, NULL, + "content_audio_format", audio_format, strlen(audio_format), NULL); } if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) { @@ -1546,7 +1749,7 @@ __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data) reusing = TRUE; sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst; LOGD("reusing audiobin"); - __mmplayer_update_content_attrs(player, ATTR_AUDIO); + _mmplayer_update_content_attrs(player, ATTR_AUDIO); } } else if (strstr(name, "video")) { /* 1. zero copy is updated at _decode_pad_added() @@ -1557,26 +1760,14 @@ __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data) mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type); LOGD("display_surface_type (%d)", surface_type); - if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) { - LOGD("mark video overlay for acquire"); - if (mm_resource_manager_mark_for_acquire(player->resource_manager, - MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY, - MM_RESOURCE_MANAGER_RES_VOLUME_FULL, - &player->video_overlay_resource) - != MM_RESOURCE_MANAGER_ERROR_NONE) { - LOGE("could not mark video_overlay resource for acquire"); - goto ERROR; - } + if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) && + (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) { + LOGE("failed to acquire video overlay resource"); + goto ERROR; } player->interrupted_by_resource = FALSE; - if (mm_resource_manager_commit(player->resource_manager) != - MM_RESOURCE_MANAGER_ERROR_NONE) { - LOGE("could not acquire resources for video playing"); - goto ERROR; - } - if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) { LOGE("failed to create videobin. continuing without video"); goto ERROR; @@ -1588,7 +1779,7 @@ __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data) reusing = TRUE; sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst; LOGD("re-using videobin"); - __mmplayer_update_content_attrs(player, ATTR_VIDEO); + _mmplayer_update_content_attrs(player, ATTR_VIDEO); } } else if (strstr(name, "text")) { if (player->pipeline->textbin == NULL) { @@ -1608,7 +1799,7 @@ __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data) 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"; @@ -1633,7 +1824,7 @@ __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data) 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: @@ -1674,7 +1865,7 @@ __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle 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; @@ -1701,21 +1892,7 @@ __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle } int -__mmplayer_video_param_check_video_sink_bin(mmplayer_t *player) -{ - /* check video sinkbin is created */ - MMPLAYER_RETURN_VAL_IF_FAIL(player && - player->pipeline && - player->pipeline->videobin && - player->pipeline->videobin[MMPLAYER_V_BIN].gst && - player->pipeline->videobin[MMPLAYER_V_SINK].gst, - MM_ERROR_PLAYER_NOT_INITIALIZED); - - return MM_ERROR_NONE; -} - -int -__mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation) +_mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation) { int display_rotation = 0; gchar *org_orient = NULL; @@ -1727,7 +1904,7 @@ __mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientat } if (display_angle) { - /* update user roation */ + /* update user rotation */ mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation); /* Counter clockwise */ @@ -1774,8 +1951,7 @@ __mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientat return MM_ERROR_NONE; } -void -__mmplayer_video_param_set_display_rotation(mmplayer_t *player) +static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player) { int rotation_value = 0; int orientations = 0; // current supported angle values are 0, 90, 180, 270 @@ -1783,10 +1959,10 @@ __mmplayer_video_param_set_display_rotation(mmplayer_t *player) MMPLAYER_FENTER(); /* check video sinkbin is created */ - if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) + if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) return; - __mmplayer_get_video_angle(player, &display_angle, &orientations); + _mmplayer_get_video_angle(player, &display_angle, &orientations); /* get rotation value to set */ __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value); @@ -1794,15 +1970,14 @@ __mmplayer_video_param_set_display_rotation(mmplayer_t *player) LOGD("set video param : rotate %d", rotation_value); } -void -__mmplayer_video_param_set_display_visible(mmplayer_t *player) +static void __mmplayer_video_param_set_display_visible(mmplayer_t *player) { MMHandleType attrs = 0; int visible = 0; MMPLAYER_FENTER(); /* check video sinkbin is created */ - if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) + if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) return; attrs = MMPLAYER_GET_ATTRS(player); @@ -1813,15 +1988,14 @@ __mmplayer_video_param_set_display_visible(mmplayer_t *player) LOGD("set video param : visible %d", visible); } -void -__mmplayer_video_param_set_display_method(mmplayer_t *player) +static void __mmplayer_video_param_set_display_method(mmplayer_t *player) { MMHandleType attrs = 0; int display_method = 0; MMPLAYER_FENTER(); /* check video sinkbin is created */ - if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) + if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) return; attrs = MMPLAYER_GET_ATTRS(player); @@ -1832,36 +2006,33 @@ __mmplayer_video_param_set_display_method(mmplayer_t *player) LOGD("set video param : method %d", display_method); } -void -__mmplayer_video_param_set_video_roi_area(mmplayer_t *player) +static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player) { MMHandleType attrs = 0; - void *handle = NULL; + int handle = 0; MMPLAYER_FENTER(); /* check video sinkbin is created */ - if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) { - LOGW("There is no video sink"); + if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) return; - } attrs = MMPLAYER_GET_ATTRS(player); MMPLAYER_RETURN_IF_FAIL(attrs); - mm_attrs_get_data_by_name(attrs, "display_overlay", &handle); - if (handle) { - gst_video_overlay_set_video_roi_area( - GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst), - player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height); - LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)", - player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height); - } + + mm_attrs_get_int_by_name(attrs, "display_overlay", &handle); + MMPLAYER_RETURN_IF_FAIL(handle); + + gst_video_overlay_set_video_roi_area( + GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst), + player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height); + LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)", + player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height); } -void -__mmplayer_video_param_set_roi_area(mmplayer_t *player) +static void __mmplayer_video_param_set_roi_area(mmplayer_t *player) { MMHandleType attrs = 0; - void *handle = NULL; + int handle = 0; /*set wl_display*/ int win_roi_x = 0; int win_roi_y = 0; @@ -1870,74 +2041,67 @@ __mmplayer_video_param_set_roi_area(mmplayer_t *player) MMPLAYER_FENTER(); /* check video sinkbin is created */ - if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) { - LOGW("There is no video sink"); + if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) return; - } attrs = MMPLAYER_GET_ATTRS(player); MMPLAYER_RETURN_IF_FAIL(attrs); - mm_attrs_get_data_by_name(attrs, "display_overlay", &handle); + mm_attrs_get_int_by_name(attrs, "display_overlay", &handle); + MMPLAYER_RETURN_IF_FAIL(handle); - if (handle) { - /* It should be set after setting window */ - mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x); - mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y); - mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width); - mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height); + /* It should be set after setting window */ + mm_attrs_multiple_get(attrs, NULL, + "display_win_roi_x", &win_roi_x, + "display_win_roi_y", &win_roi_y, + "display_win_roi_width", &win_roi_width, + "display_win_roi_height", &win_roi_height, NULL); - /* After setting window handle, set display roi area */ - gst_video_overlay_set_display_roi_area( - GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst), - win_roi_x, win_roi_y, win_roi_width, win_roi_height); - LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)", - win_roi_x, win_roi_y, win_roi_width, win_roi_height); - } + /* After setting window handle, set display roi area */ + gst_video_overlay_set_display_roi_area( + GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst), + win_roi_x, win_roi_y, win_roi_width, win_roi_height); + LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)", + win_roi_x, win_roi_y, win_roi_width, win_roi_height); } -void -__mmplayer_video_param_set_display_overlay(mmplayer_t *player) +static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player) { MMHandleType attrs = 0; - void *handle = NULL; + int handle = 0; /* check video sinkbin is created */ - if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) + if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) return; attrs = MMPLAYER_GET_ATTRS(player); MMPLAYER_RETURN_IF_FAIL(attrs); /* common case if using overlay surface */ - mm_attrs_get_data_by_name(attrs, "display_overlay", &handle); - - if (handle) { - /* default is using wl_surface_id */ - unsigned int wl_surface_id = 0; - wl_surface_id = *(int *)handle; - LOGD("set video param : wl_surface_id %d", wl_surface_id); - gst_video_overlay_set_wl_window_wl_surface_id( - GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst), - *(int *)handle); - } else { - /* FIXIT : is it error case? */ - LOGW("still we don't have a window handle on player attribute. create it's own surface."); - } + mm_attrs_get_int_by_name(attrs, "display_overlay", &handle); + MMPLAYER_RETURN_IF_FAIL(handle); + + /* default is using wl_surface_id */ + LOGD("set video param : wl_surface_id %d", handle); + gst_video_overlay_set_wl_window_wl_surface_id( + GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst), + handle); } int -__mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name) +_mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name) { gboolean update_all_param = FALSE; + MMPLAYER_FENTER(); - /* check video sinkbin is created */ - if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) + if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) { + LOGW("videosink is not ready yet"); return MM_ERROR_PLAYER_NOT_INITIALIZED; + } if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) { - LOGE("can not find tizenwlsink"); + LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay); return MM_ERROR_PLAYER_INTERNAL; } @@ -1958,55 +2122,16 @@ __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_ if (update_all_param) __mmplayer_video_param_set_video_roi_area(player); + + MMPLAYER_FLEAVE(); return MM_ERROR_NONE; } int -_mmplayer_update_video_param(mmplayer_t *player, char *param_name) -{ - MMHandleType attrs = 0; - int surface_type = 0; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - /* check video sinkbin is created */ - if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) - return MM_ERROR_PLAYER_NOT_INITIALIZED; - - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("cannot get content attribute"); - return MM_ERROR_PLAYER_INTERNAL; - } - LOGD("param_name : %s", param_name); - - /* update display surface */ - mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type); - LOGD("check display surface type attribute: %d", surface_type); - - /* configuring display */ - switch (surface_type) { - case MM_DISPLAY_SURFACE_OVERLAY: - { - ret = __mmplayer_update_wayland_videosink_video_param(player, param_name); - if (ret != MM_ERROR_NONE) - return ret; - } - break; - } - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only) +_mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only) { gboolean disable_overlay = FALSE; mmplayer_t *player = (mmplayer_t *)hplayer; - int ret = MM_ERROR_NONE; MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); @@ -2031,41 +2156,16 @@ _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only) g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL); /* release overlay resource */ - if (player->video_overlay_resource != NULL) { - ret = mm_resource_manager_mark_for_release(player->resource_manager, - player->video_overlay_resource); - if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { - LOGE("failed to mark overlay resource for release, ret(0x%x)", ret); - goto ERROR; - } - player->video_overlay_resource = NULL; - } - - ret = mm_resource_manager_commit(player->resource_manager); - if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { - LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret); + if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) { + LOGE("failed to release overlay resource"); goto ERROR; } } else { - /* mark video overlay for acquire */ - if (player->video_overlay_resource == NULL) { - ret = mm_resource_manager_mark_for_acquire(player->resource_manager, - MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY, - MM_RESOURCE_MANAGER_RES_VOLUME_FULL, - &player->video_overlay_resource); - if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { - LOGE("could not prepare for video_overlay resource"); - goto ERROR; - } - } - - player->interrupted_by_resource = FALSE; - /* acquire resources for video overlay */ - ret = mm_resource_manager_commit(player->resource_manager); - if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { - LOGE("could not acquire resources for video playing"); + if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) { + LOGE("failed to acquire video overlay resource"); goto ERROR; } + player->interrupted_by_resource = FALSE; LOGD("enable overlay"); __mmplayer_video_param_set_display_overlay(player); @@ -2108,11 +2208,12 @@ _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only) } int -__mmplayer_gst_element_link_bucket(GList *element_bucket) +_mmplayer_gst_element_link_bucket(GList *element_bucket) { GList *bucket = element_bucket; mmplayer_gst_element_t *element = NULL; mmplayer_gst_element_t *prv_element = NULL; + GstElement *tee_element = NULL; gint successful_link_count = 0; MMPLAYER_FENTER(); @@ -2127,11 +2228,25 @@ __mmplayer_gst_element_link_bucket(GList *element_bucket) if (element && element->gst) { if (prv_element && prv_element->gst) { + if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) { + if (tee_element) { + prv_element->gst = tee_element; + } else { + LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported", + GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)), + GST_ELEMENT_NAME(GST_ELEMENT(element->gst))); + return -1; + } + } if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) { LOGD("linking [%s] to [%s] success", GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)), GST_ELEMENT_NAME(GST_ELEMENT(element->gst))); successful_link_count++; + if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) { + LOGD("keep audio-tee element for next audio pipeline branch"); + tee_element = prv_element->gst; + } } else { LOGD("linking [%s] to [%s] failed", GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)), @@ -2150,7 +2265,7 @@ __mmplayer_gst_element_link_bucket(GList *element_bucket) } int -__mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket) +_mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket) { GList *bucket = element_bucket; mmplayer_gst_element_t *element = NULL; @@ -2166,7 +2281,7 @@ __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket) if (element && element->gst) { if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) { - LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed", + LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed", GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), GST_ELEMENT_NAME(GST_ELEMENT(bin))); return 0; @@ -2195,18 +2310,14 @@ __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data) 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; LOGD("name = %s", name); if (strstr(name, "audio")) { - __mmplayer_update_content_attrs(player, ATTR_AUDIO); + _mmplayer_update_content_attrs(player, ATTR_AUDIO); if (player->audio_stream_changed_cb) { LOGE("call the audio stream changed cb"); @@ -2216,12 +2327,8 @@ __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data) if ((name = gst_structure_get_string(str, "format"))) player->set_mode.video_zc = name[0] == 'S'; - __mmplayer_update_content_attrs(player, ATTR_VIDEO); - - if (player->video_stream_changed_cb) { - LOGE("call the video stream changed cb"); - player->video_stream_changed_cb(player->video_stream_changed_cb_user_param); - } + _mmplayer_update_content_attrs(player, ATTR_VIDEO); + MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL); } else { LOGW("invalid caps info"); } @@ -2235,33 +2342,8 @@ ERROR: return; } -/** - * This function is to create audio pipeline for playing. - * - * @param player [in] handle of player - * - * @return This function returns zero on success. - * @remark - * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin - */ -/* macro for code readability. just for sinkbin-creation functions */ -#define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \ - do {\ - x_bin[x_id].id = x_id;\ - x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\ - if (!x_bin[x_id].gst) {\ - LOGE("failed to create %s", x_factory);\ - goto ERROR;\ - } else {\ - if (x_player->ini.set_dump_element_flag)\ - __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\ - } \ - if (x_add_bucket)\ - element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\ - } while (0); - void -__mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all) +_mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all) { GList *l = NULL; @@ -2297,13 +2379,13 @@ __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff audio_stream.bitrate = a_buffer->bitrate; audio_stream.channel = a_buffer->channel; - audio_stream.depth = a_buffer->depth; - audio_stream.is_little_endian = a_buffer->is_little_endian; audio_stream.channel_mask = a_buffer->channel_mask; audio_stream.data_size = a_buffer->data_size; audio_stream.data = a_buffer->pcm_data; - - /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */ + audio_stream.pcm_format = a_buffer->pcm_format; +#ifdef __DEBUG__ + LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); +#endif player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param); MMPLAYER_FLEAVE(); @@ -2316,8 +2398,6 @@ __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, const gchar *pcm_format = NULL; gint channel = 0; gint rate = 0; - gint depth = 0; - gint endianness = 0; guint64 channel_mask = 0; void *a_data = NULL; gint a_size = 0; @@ -2334,13 +2414,12 @@ __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstCaps *caps = gst_pad_get_current_caps(pad); GstStructure *structure = gst_caps_get_structure(caps, 0); - - /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */ +#ifdef __DEBUG__ + MMPLAYER_LOG_GST_CAPS_TYPE(caps); +#endif pcm_format = gst_structure_get_string(structure, "format"); gst_structure_get_int(structure, "rate", &rate); gst_structure_get_int(structure, "channels", &channel); - gst_structure_get_int(structure, "depth", &depth); - gst_structure_get_int(structure, "endianness", &endianness); gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL); gst_caps_unref(GST_CAPS(caps)); @@ -2351,7 +2430,9 @@ __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data; if (tmp) { if (channel_mask == tmp->channel_mask) { - /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */ +#ifdef __DEBUG__ + LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); +#endif if (tmp->data_size + a_size < tmp->buff_size) { memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size); tmp->data_size += a_size; @@ -2381,7 +2462,7 @@ __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, } } - /* create new audio stream data */ + /* create new audio stream data for newly found audio channel */ a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t)); if (a_buffer == NULL) { LOGE("failed to alloc data."); @@ -2389,11 +2470,9 @@ __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, } a_buffer->bitrate = rate; a_buffer->channel = channel; - a_buffer->depth = depth; - a_buffer->is_little_endian = (endianness == 1234 ? true : false); a_buffer->channel_mask = channel_mask; a_buffer->data_size = a_size; - a_buffer->pcm_format = util_convert_audio_pcm_str_to_media_format_mime(pcm_format); + a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format); if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) { /* If sync is FALSE, use buffer list to reduce the IPC. */ @@ -2405,7 +2484,9 @@ __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, goto DONE; } memcpy(a_buffer->pcm_data, a_data, a_size); - /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */ +#ifdef __DEBUG__ + LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); +#endif player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer); } else { /* If sync is TRUE, send data directly. */ @@ -2463,16 +2544,32 @@ __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpoin g_object_set(sink, "sync", TRUE, NULL); g_object_set(sink, "signal-handoffs", TRUE, NULL); - gst_element_set_state(sink, GST_STATE_PAUSED); - gst_element_set_state(queue, GST_STATE_PAUSED); + /* keep the first sink reference only */ + if (!audiobin[MMPLAYER_A_SINK].gst) { + audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK; + audiobin[MMPLAYER_A_SINK].gst = sink; + } + - __mmplayer_add_signal_connection(player, + _mmplayer_add_signal_connection(player, G_OBJECT(sink), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN, "handoff", G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb), (gpointer)player); + __mmplayer_add_sink(player, sink, FALSE); + + if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) { + LOGE("failed to sync state"); + goto ERROR; + } + + if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) { + LOGE("failed to sync state"); + goto ERROR; + } + MMPLAYER_FLEAVE(); return; @@ -2495,9 +2592,25 @@ ERROR: } void -__mmplayer_gst_set_pulsesink_property(mmplayer_t *player, MMHandleType attrs) +__mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data) +{ + mmplayer_t *player = (mmplayer_t *)data; + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); + + player->no_more_pad = TRUE; + _mmplayer_pipeline_complete(NULL, player); + + MMPLAYER_FLEAVE(); + return; +} + +void +__mmplayer_gst_set_pulsesink_property(mmplayer_t *player) { #define MAX_PROPS_LEN 128 + mmplayer_gst_element_t *audiobin = NULL; gint latency_mode = 0; gchar *stream_type = NULL; gchar *latency = NULL; @@ -2512,37 +2625,48 @@ __mmplayer_gst_set_pulsesink_property(mmplayer_t *player, MMHandleType attrs) MMPLAYER_FENTER(); MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin); - mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id); - mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type); + audiobin = player->pipeline->audiobin; - if (!stream_type) { - LOGE("stream_type is null."); - } else { - snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d", - stream_type, stream_id); - props = gst_structure_from_string(stream_props, NULL); - g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL); - LOGI("stream_type[%s], stream_id[%d], result[%s].", stream_type, stream_id, stream_props); - gst_structure_free(props); + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL); + if (player->sound.mute) { + LOGD("mute enabled"); + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL); } - mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode); + mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id); + mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type); + + if (!stream_type) + snprintf(stream_props, sizeof(stream_props) - 1, + "props,application.process.id.origin=%d", player->client_pid); + else + snprintf(stream_props, sizeof(stream_props) - 1, + "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d", + stream_type, stream_id, player->client_pid); + + props = gst_structure_from_string(stream_props, NULL); + g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL); + LOGI("props result[%s].", stream_props); + gst_structure_free(props); + + mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode); switch (latency_mode) { case AUDIO_LATENCY_MODE_LOW: - latency = g_strndup("low", 3); + latency = g_strdup("low"); break; case AUDIO_LATENCY_MODE_MID: - latency = g_strndup("mid", 3); + latency = g_strdup("mid"); break; case AUDIO_LATENCY_MODE_HIGH: - latency = g_strndup("high", 4); + latency = g_strdup("high"); + break; + default: + latency = g_strdup("mid"); break; }; - g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, - "latency", latency, - NULL); + g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL); LOGD("audiosink property - latency=%s", latency); @@ -2551,18 +2675,23 @@ __mmplayer_gst_set_pulsesink_property(mmplayer_t *player, MMHandleType attrs) MMPLAYER_FLEAVE(); } -void +int __mmplayer_gst_set_openalsink_property(mmplayer_t *player) { mmplayer_gst_element_t *audiobin = NULL; MMPLAYER_FENTER(); - MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && + player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED); audiobin = player->pipeline->audiobin; g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL); - sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info); + if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) { + LOGE("failed to create media stream info"); + return MM_ERROR_PLAYER_INTERNAL; + } + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL); if (player->video360_yaw_radians <= M_PI && @@ -2579,16 +2708,16 @@ __mmplayer_gst_set_openalsink_property(mmplayer_t *player) } MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; } static int -__mmplayer_gst_fill_audio_bucket(mmplayer_t *player, GList **bucket) +__mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket) { mmplayer_gst_element_t *audiobin = NULL; - MMHandleType attrs = 0; - GList *element_bucket = NULL; - GstCaps *acaps = NULL; GstPad *sink_pad = NULL; + GstCaps *acaps = NULL; + gint channels = 0; int pitch_control = 0; double pitch_value = 1.0; @@ -2597,17 +2726,17 @@ __mmplayer_gst_fill_audio_bucket(mmplayer_t *player, GList **bucket) player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED); audiobin = player->pipeline->audiobin; - attrs = MMPLAYER_GET_ATTRS(player); - if (player->build_audio_offload) { /* skip all the audio filters */ - LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element); - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player); - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL); - __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst); - goto DONE; - } + LOGD("make element for normal audio playback"); + + /* audio bin structure for playback. {} means optional. + optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content + + * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume - + {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink} + */ - /* pitch */ + /* for pitch control */ mm_attrs_multiple_get(player->attrs, NULL, MM_PLAYER_PITCH_CONTROL, &pitch_control, MM_PLAYER_PITCH_VALUE, &pitch_value, @@ -2622,10 +2751,10 @@ __mmplayer_gst_fill_audio_bucket(mmplayer_t *player, GList **bucket) gst_object_unref(factory); /* converter */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", TRUE, player); + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player); /* pitch */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", TRUE, player); + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player); g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL); } else { LOGW("there is no pitch element"); @@ -2633,187 +2762,314 @@ __mmplayer_gst_fill_audio_bucket(mmplayer_t *player, GList **bucket) } /* converter */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player); + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player); /* replaygain volume */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player); + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player); if (player->sound.rg_enable) g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL); else g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL); /* resampler */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player); + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player); - if (player->audio_decoded_cb) { /* pcm extraction only, no sound output */ - gchar *dst_format = NULL; - int dst_len = 0; - int dst_samplerate = 0; - int dst_channels = 0; - GstCaps *caps = NULL; - char *caps_str = NULL; + if (g_strrstr(player->ini.audiosink_element, "openalsink")) { + /* currently, only openalsink uses volume element */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player); + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL); - /* get conf. values */ - mm_attrs_multiple_get(player->attrs, NULL, - "pcm_audioformat", &dst_format, &dst_len, - "pcm_extraction_samplerate", &dst_samplerate, - "pcm_extraction_channels", &dst_channels, - NULL); + if (player->sound.mute) { + LOGD("mute enabled"); + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL); + } + } + + mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels); - LOGD("required pcm format - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels); - if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) { - mm_attrs_multiple_get(player->attrs, NULL, - "content_audio_format", &dst_format, &dst_len, /* get string and len */ - "content_audio_samplerate", &dst_samplerate, - "content_audio_channels", &dst_channels, - NULL); + /* audio effect element. if audio effect is enabled */ + if ((strcmp(player->ini.audioeffect_element, "")) + && (channels <= 2) + && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) { + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player); - LOGD("decoded pcm format - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels); + LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type); - /* If there is no enough information, set it to platform default value. */ - if (dst_format == NULL || util_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) { - LOGD("set platform default format"); - dst_format = DEFAULT_PCM_OUT_FORMAT; + if ((!player->bypass_audio_effect) + && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) { + if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) { + if (!_mmplayer_audio_effect_custom_apply(player)) + LOGI("apply audio effect(custom) setting success"); } - if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE; - if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL; } - /* capsfilter */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player); - caps = gst_caps_new_simple("audio/x-raw", - "format", G_TYPE_STRING, dst_format, - "rate", G_TYPE_INT, dst_samplerate, - "channels", G_TYPE_INT, dst_channels, - NULL); + if ((strcmp(player->ini.audioeffect_element_custom, "")) + && (player->set_mode.rich_audio)) { + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player); + } + } - caps_str = gst_caps_to_string(caps); - LOGD("new caps : %s", caps_str); + /* create audio sink */ + LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d", + player->is_content_spherical, channels, player->video360_metadata.ambisonic_type, + player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order); - g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL); + /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */ + if (player->is_360_feature_enabled && + player->is_content_spherical && + channels == 4 && + player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC && + player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB && + player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) { - /* clean */ - gst_caps_unref(caps); - MMPLAYER_FREEIF(caps_str); + strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1); - if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) { - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player); + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player); - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL); + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player); + acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS); + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL); + gst_caps_unref(acaps); - /* raw pad handling signal, audiosink will be added after getting signal */ - __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 { - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "audiosink", TRUE, player); - if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK)) - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL); - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "signal-handoffs", TRUE, NULL); - - __mmplayer_add_signal_connection(player, - G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), - MM_PLAYER_SIGNAL_TYPE_AUDIOBIN, - "handoff", - G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb), - (gpointer)player); - } + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player); + + player->is_openal_plugin_used = TRUE; } else { - /* normal playback */ - gint channels = 0; + if (player->is_360_feature_enabled && player->is_content_spherical) + LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound."); + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player); + } - /* for logical volume control */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player); - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL); + if ((MMPLAYER_IS_RTSP_STREAMING(player)) || + (player->videodec_linked && player->ini.use_system_clock)) { + LOGD("system clock will be used."); + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL); + } - if (player->sound.mute) { - LOGD("mute enabled"); - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL); - } + if (g_strrstr(player->ini.audiosink_element, "pulsesink")) { + __mmplayer_gst_set_pulsesink_property(player); + } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) { + if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE) + goto ERROR; + } - mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels); + /* qos on */ + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */ + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL); - /* audio effect element. if audio effect is enabled */ - if ((strcmp(player->ini.audioeffect_element, "")) - && (channels <= 2) - && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) { - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player); + sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink"); + _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)); - LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type); + __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE); - if ((!player->bypass_audio_effect) - && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) { - if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) { - if (!_mmplayer_audio_effect_custom_apply(player)) - LOGI("apply audio effect(custom) setting success"); - } - } + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; - if ((strcmp(player->ini.audioeffect_element_custom, "")) - && (player->set_mode.rich_audio)) - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player); - } +ERROR: /* MMPLAYER_CREATE_ELEMENT */ + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; +} + +static int +__mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket) +{ + mmplayer_gst_element_t *audiobin = NULL; + enum audio_element_id extract_sink_id = MMPLAYER_A_SINK; + + gchar *dst_format = NULL; + int dst_len = 0; + int dst_samplerate = 0; + int dst_channels = 0; + GstCaps *caps = NULL; + char *caps_str = NULL; + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && + player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED); - /* create audio sink */ - LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d", - player->is_content_spherical, channels, player->video360_metadata.ambisonic_type, - player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order); + audiobin = player->pipeline->audiobin; - /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */ - if (player->is_360_feature_enabled && - player->is_content_spherical && - channels == 4 && - player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC && - player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB && - player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) { + LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt); - strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1); + /* audio bin structure according to the mmplayer_audio_extract_opt_e. - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player); + [case 1] extract interleave audio pcm without playback + : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync) + MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync) - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player); - acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS); - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL); - gst_caps_unref(acaps); + * src - ... - aconv - resample - capsfilter - fakesink (sync or not) - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player); + [case 2] deinterleave for each channel without playback + : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync) + MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync) - player->is_openal_plugin_used = TRUE; - } else { - if (player->is_360_feature_enabled && player->is_content_spherical) - LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound."); - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player); - } + * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not) + - fakesink (sync or not) + - ... (sync or not) + + [case 3] [case 1(sync only)] + playback + : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK + + * src - ... - tee - queue1 - playback path + - queue2 - [case1 pipeline with sync] + + [case 4] [case 2(sync only)] + playback + : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK + + * src - ... - tee - queue1 - playback path + - queue2 - [case2 pipeline with sync] + + */ + + /* 1. create tee and playback path + 'tee' should be added at first to copy the decoded stream + */ + if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) { + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player); + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL); + + /* tee - path 1 : for playback path */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player); + __mmplayer_gst_make_audio_playback_sink(player, bucket); + + /* tee - path 2 : for extract path */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player); + extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */ + } + + /* if there is tee, 'tee - path 2' is linked here */ + /* converter */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player); + + /* resampler */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player); + + /* 2. decide the extract pcm format */ + mm_attrs_multiple_get(player->attrs, NULL, + MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len, + MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate, + MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels, + NULL); + + LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d", + dst_format, dst_len, dst_samplerate, dst_channels); + + if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) { + mm_attrs_multiple_get(player->attrs, NULL, + "content_audio_format", &dst_format, &dst_len, /* get string and len */ + "content_audio_samplerate", &dst_samplerate, + "content_audio_channels", &dst_channels, + NULL); - if ((MMPLAYER_IS_RTSP_STREAMING(player)) || - (player->videodec_linked && player->ini.use_system_clock)) { - LOGD("system clock will be used."); - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL); + LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d", + dst_format, dst_len, dst_samplerate, dst_channels); + + /* If there is no enough information, set it to platform default value. */ + if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) { + LOGD("set platform default format"); + dst_format = DEFAULT_PCM_OUT_FORMAT; } + if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE; + if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL; + } - if (g_strrstr(player->ini.audiosink_element, "pulsesink")) - __mmplayer_gst_set_pulsesink_property(player, attrs); - else if (g_strrstr(player->ini.audiosink_element, "openalsink")) - __mmplayer_gst_set_openalsink_property(player); + /* 3. create capsfilter */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player); + caps = gst_caps_new_simple("audio/x-raw", + "format", G_TYPE_STRING, dst_format, + "rate", G_TYPE_INT, dst_samplerate, + "channels", G_TYPE_INT, dst_channels, + NULL); + + caps_str = gst_caps_to_string(caps); + LOGD("new caps : %s", caps_str); - /* qos on */ - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */ - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL); + g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL); - sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink"); - __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)); + /* clean */ + gst_caps_unref(caps); + MMPLAYER_FREEIF(caps_str); + + /* 4-1. create deinterleave to extract pcm for each channel */ + if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) { + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player); + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL); + + /* audiosink will be added after getting signal for each channel */ + _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player); + _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), + 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 */ + 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_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL); + g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL); + + _mmplayer_add_signal_connection(player, + G_OBJECT(audiobin[extract_sink_id].gst), + MM_PLAYER_SIGNAL_TYPE_AUDIOBIN, + "handoff", + G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb), + (gpointer)player); + + __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE); + } + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; + +ERROR: /* MMPLAYER_CREATE_ELEMENT */ + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; +} + +static int +__mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket) +{ + int ret = MM_ERROR_NONE; + mmplayer_gst_element_t *audiobin = NULL; + GList *element_bucket = NULL; + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && + player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED); - __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst); + audiobin = player->pipeline->audiobin; + + if (player->build_audio_offload) { /* skip all the audio filters */ + LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element); + + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player); + 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, FALSE); + goto DONE; } + /* FIXME: need to mention the supportable condition at API reference */ + if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player))) + ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket); + else + ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket); + + if (ret != MM_ERROR_NONE) + goto ERROR; DONE: + LOGD("success to make audio bin element"); *bucket = element_bucket; MMPLAYER_FLEAVE(); return MM_ERROR_NONE; ERROR: + LOGE("failed to make audio bin element"); g_list_free(element_bucket); *bucket = NULL; @@ -2853,17 +3109,17 @@ __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player) player->pipeline->audiobin = audiobin; /* create audio filters and audiosink */ - if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE) + if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE) goto ERROR; /* adding created elements to bin */ LOGD("adding created elements to bin"); - if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) + if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) goto ERROR; /* linking elements in the bucket by added order. */ LOGD("Linking elements in the bucket by added order."); - if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) + if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) goto ERROR; /* get first element's sinkpad for creating ghostpad */ @@ -2924,7 +3180,7 @@ ERROR: } } - /* 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)); @@ -2972,27 +3228,27 @@ _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo) 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; @@ -3048,16 +3304,16 @@ __mmplayer_video_stream_get_bo(mmplayer_t *player, int size) } /* update video num buffers */ - player->video_num_buffers = idx; - if (idx == player->ini.num_of_video_bo) - player->video_extra_num_buffers = player->ini.num_of_video_bo/2; + LOGD("video_num_buffers : %d", idx); + mm_player_set_attribute((MMHandleType)player, NULL, + MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx, + MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)), + NULL); if (idx == 0) { MMPLAYER_VIDEO_BO_UNLOCK(player); return NULL; } - - LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers); } while (TRUE) { @@ -3127,12 +3383,12 @@ __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, return; } - __mmplayer_get_video_angle(player, NULL, &stream->orientation); + _mmplayer_get_video_angle(player, NULL, &stream->orientation); /* 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 && @@ -3250,7 +3506,7 @@ __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType sur /* create video360 filter */ if (player->is_360_feature_enabled && player->is_content_spherical) { LOGD("create video360 element"); - MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player); + MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player); __mmplayer_gst_set_video360_property(player); goto EXIT; } @@ -3263,7 +3519,7 @@ __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType sur /* in case of sw codec & overlay surface type, except 360 playback. * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */ LOGD("create video converter: %s", video_csc); - MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player); + MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player); EXIT: *bucket = element_bucket; @@ -3322,22 +3578,24 @@ __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType s return MM_ERROR_PLAYER_INTERNAL; } - LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name); if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) { bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)); - if (!use_tbm) { - /* support shard memory with S/W codec on HawkP */ - if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) { - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, - "use-tbm", use_tbm, NULL); - } + if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) { + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, + "use-tbm", use_tbm, NULL); } + + if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE) + return MM_ERROR_PLAYER_INTERNAL; + + LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm); + } else { g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL); } - mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless); + mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless); if (gapless > 0) { LOGD("disable last-sample"); g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL); @@ -3349,14 +3607,14 @@ __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType s if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL)) g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL); - __mmplayer_add_signal_connection(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_add_signal_connection(player, + _mmplayer_add_signal_connection(player, G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, "preroll-handoff", @@ -3364,14 +3622,11 @@ __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType s (gpointer)player); } - if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE) - return MM_ERROR_PLAYER_INTERNAL; - if (videobin[MMPLAYER_V_SINK].gst) { GstPad *sink_pad = NULL; sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink"); if (sink_pad) { - __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, + _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 { @@ -3417,7 +3672,7 @@ __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDispla goto ERROR; videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type); - MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player); + MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player); /* additional setting for sink plug-in */ if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) { @@ -3426,16 +3681,16 @@ __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDispla } /* 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 (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) { LOGE("failed to add elements"); goto ERROR; } /* Linking elements in the bucket by added order */ - if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) { + if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) { LOGE("failed to link elements"); goto ERROR; } @@ -3475,7 +3730,7 @@ ERROR: 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)); @@ -3491,14 +3746,14 @@ __mmplayer_gst_create_plain_text_elements(mmplayer_t *player) GList *element_bucket = NULL; mmplayer_gst_element_t *textbin = player->pipeline->textbin; - MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player); - MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player); + MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player); + MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player); g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst), "signal-handoffs", FALSE, NULL); - MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player); - __mmplayer_add_signal_connection(player, + MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player); + _mmplayer_add_signal_connection(player, G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), MM_PLAYER_SIGNAL_TYPE_TEXTBIN, "handoff", @@ -3510,12 +3765,12 @@ __mmplayer_gst_create_plain_text_elements(mmplayer_t *player) 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)) { + if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) { LOGE("failed to add elements"); goto ERROR; } @@ -3526,7 +3781,7 @@ __mmplayer_gst_create_plain_text_elements(mmplayer_t *player) /* linking elements in the bucket by added order. */ LOGD("Linking elements in the bucket by added order."); - if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) { + if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) { LOGE("failed to link elements"); goto ERROR; } @@ -3649,11 +3904,11 @@ ERROR: } } - /* 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)); - MMPLAYER_FREEIF(player->pipeline->textbin); + MMPLAYER_FREEIF(textbin); player->pipeline->textbin = NULL; MMPLAYER_FLEAVE(); @@ -3693,7 +3948,7 @@ __mmplayer_gst_create_text_pipeline(mmplayer_t *player) return MM_ERROR_PLAYER_INVALID_URI; } - if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) { + if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) { LOGE("failed to get storage info of subtitle path"); return MM_ERROR_PLAYER_INVALID_URI; } @@ -3730,7 +3985,7 @@ __mmplayer_gst_create_text_pipeline(mmplayer_t *player) goto ERROR; } - charset = util_get_charset(subtitle_uri); + charset = _mmplayer_get_charset(subtitle_uri); if (charset) { LOGD("detected charset is %s", charset); g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL); @@ -3771,7 +4026,7 @@ __mmplayer_gst_create_text_pipeline(mmplayer_t *player) /* 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; @@ -3822,7 +4077,7 @@ ERROR: 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; @@ -3947,7 +4202,7 @@ __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position) return MM_ERROR_NONE; } - /* check current postion */ + /* check current position */ player->adjust_subtitle_pos = position; LOGD("save adjust_subtitle_pos in player"); @@ -3990,8 +4245,6 @@ __mmplayer_gst_create_pipeline(mmplayer_t *player) } player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t)); - if (player->pipeline == NULL) - goto INIT_ERROR; /* create mainbin */ mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM); @@ -4010,23 +4263,27 @@ __mmplayer_gst_create_pipeline(mmplayer_t *player) player->pipeline->mainbin = mainbin; /* create the source and decoder elements */ - if (MMPLAYER_IS_MS_BUFF_SRC(player)) - ret = __mmplayer_gst_build_es_pipeline(player); - else - ret = __mmplayer_gst_build_pipeline(player); + if (MMPLAYER_IS_MS_BUFF_SRC(player)) { + ret = _mmplayer_gst_build_es_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"); /* add bus watch */ - ret = __mmplayer_gst_add_bus_watch(player); + ret = _mmplayer_gst_add_bus_watch(player); if (ret != MM_ERROR_NONE) { LOGE("failed to add bus watch"); goto INIT_ERROR; @@ -4036,6 +4293,7 @@ __mmplayer_gst_create_pipeline(mmplayer_t *player) return MM_ERROR_NONE; INIT_ERROR: + _mmplayer_bus_watcher_remove(player); __mmplayer_gst_destroy_pipeline(player); return MM_ERROR_PLAYER_INTERNAL; } @@ -4069,17 +4327,18 @@ __mmplayer_gst_destroy_pipeline(mmplayer_t *player) 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; MMPLAYER_SUBTITLE_INFO_UNLOCK(player); + MMPLAYER_RECONFIGURE_LOCK(player); __mmplayer_reset_gapless_state(player); + MMPLAYER_RECONFIGURE_UNLOCK(player); if (player->streamer) { - __mm_player_streaming_initialize(player->streamer, FALSE); - __mm_player_streaming_destroy(player->streamer); + _mm_player_streaming_initialize(player->streamer, FALSE); + _mm_player_streaming_destroy(player->streamer); player->streamer = NULL; } @@ -4089,7 +4348,7 @@ __mmplayer_gst_destroy_pipeline(mmplayer_t *player) MMPLAYER_FREEIF(player->unlinked_demuxer_mime); /* cleanup running stuffs */ - __mmplayer_cancel_eos_timer(player); + _mmplayer_cancel_eos_timer(player); /* cleanup gst stuffs */ if (player->pipeline) { @@ -4108,7 +4367,7 @@ __mmplayer_gst_destroy_pipeline(mmplayer_t *player) gst_object_unref(bus); timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); - ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout); + ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout); if (ret != MM_ERROR_NONE) { LOGE("fail to change state to NULL"); return MM_ERROR_PLAYER_INTERNAL; @@ -4122,10 +4381,6 @@ __mmplayer_gst_destroy_pipeline(mmplayer_t *player) 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); @@ -4139,6 +4394,11 @@ __mmplayer_gst_destroy_pipeline(mmplayer_t *player) } 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; @@ -4153,7 +4413,7 @@ __mmplayer_gst_destroy_pipeline(mmplayer_t *player) 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); @@ -4192,7 +4452,7 @@ __mmplayer_gst_realize(mmplayer_t *player) /* set pipeline state to READY */ /* NOTE : state change to READY must be performed sync. */ timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); - ret = __mmplayer_gst_set_state(player, + ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout); if (ret != MM_ERROR_NONE) { @@ -4229,7 +4489,7 @@ __mmplayer_gst_unrealize(mmplayer_t *player) /* 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; } @@ -4265,7 +4525,7 @@ __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callba } int -__mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data) +_mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data) { int ret = MM_ERROR_NONE; char *path = NULL; @@ -4313,103 +4573,63 @@ __mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t 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, released at mrp_resource_release_cb() */ - return TRUE; -} - static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data) { mmplayer_t *player = NULL; + MMMessageParamType msg = {0, }; + gint64 pos = 0; + mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX; MMPLAYER_FENTER(); - if (user_data == NULL) { - LOGE("- user_data is null"); - return FALSE; + if (!user_data) { + LOGE("user_data is null"); + return TRUE; } - player = (mmplayer_t *)user_data; - /* do something to release resource here. - * player stop and interrupt forwarding */ - if (!__mmplayer_can_do_interrupt(player)) { - LOGW("no need to interrupt, so leave"); - } else { - MMMessageParamType msg = {0, }; - gint64 pos = 0; + player = (mmplayer_t *)user_data; - player->interrupted_by_resource = TRUE; + if (!player->pipeline || !player->attrs) { + LOGW("not initialized"); + return TRUE; + } - /* get last play position */ - if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) { - LOGW("failed to get play position."); - } else { - msg.union_type = MM_MSG_UNION_TIME; - msg.time.elapsed = pos; - MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg); - } - LOGD("video resource conflict so, resource will be freed by unrealizing"); - if (_mmplayer_unrealize((MMHandleType)player)) - LOGW("failed to unrealize"); + LOGD("cmd lock player, cmd state : %d", player->cmd); + MMPLAYER_CMD_LOCK(player); + LOGD("cmd locked player"); - /* lock is called in __mmplayer_can_do_interrupt() */ + 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; } - if (res == player->video_overlay_resource) - player->video_overlay_resource = FALSE; - else - player->video_decoder_resource = FALSE; + player->interrupted_by_resource = TRUE; - MMPLAYER_FLEAVE(); + /* get last play position */ + if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) { + msg.union_type = MM_MSG_UNION_TIME; + msg.time.elapsed = pos; + MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg); + } else { + LOGW("failed to get play position."); + } - return FALSE; + LOGD("video resource conflict so, resource will be freed by unrealizing"); + if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE) + LOGE("failed to unrealize"); + + MMPLAYER_CMD_UNLOCK(player); + + for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) { + player->hw_resource[res_idx] = NULL; + } + + MMPLAYER_FLEAVE(); + return TRUE; /* release all the resources */ } static void @@ -4497,7 +4717,7 @@ _mmplayer_create_player(MMHandleType handle) 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; } @@ -4506,9 +4726,6 @@ _mmplayer_create_player(MMHandleType handle) g_mutex_init(&player->video_bo_mutex); g_cond_init(&player->video_bo_cond); - /* create media stream callback mutex */ - g_mutex_init(&player->media_stream_cb_lock); - /* create subtitle info lock and cond */ g_mutex_init(&player->subtitle_info_mutex); g_cond_init(&player->subtitle_info_cond); @@ -4522,8 +4739,6 @@ _mmplayer_create_player(MMHandleType handle) player->play_subtitle = FALSE; player->has_closed_caption = FALSE; - player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER; - player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER; player->pending_resume = FALSE; if (player->ini.dump_element_keyword[0][0] == '\0') player->ini.set_dump_element_flag = FALSE; @@ -4572,6 +4787,7 @@ ERROR: /* free update tag lock */ g_mutex_clear(&player->update_tag_lock); g_queue_free(player->bus_msg_q); + player->bus_msg_q = NULL; /* free gapless play thread */ if (player->gapless_play_thread) { MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player); @@ -4670,7 +4886,9 @@ __mmplayer_init_gstreamer(mmplayer_t *player) } /* release */ for (i = 0; i < arg_count; i++) { - //LOGD("release - argv[%d] : %s", i, argv2[i]); +#ifdef __DEBUG__ + LOGD("release - argv[%d] : %s", i, argv2[i]); +#endif MMPLAYER_FREEIF(argv2[i]); } @@ -4734,7 +4952,7 @@ __mmplayer_check_async_state_transition(mmplayer_t *player) gst_element_state_get_name(element_pending_state)); /* dump state of all element */ - __mmplayer_dump_pipeline_state(player); + _mmplayer_dump_pipeline_state(player); return; } @@ -4766,7 +4984,7 @@ _mmplayer_destroy(MMHandleType handle) 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); @@ -4775,17 +4993,17 @@ _mmplayer_destroy(MMHandleType handle) _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 */ @@ -4794,9 +5012,6 @@ _mmplayer_destroy(MMHandleType handle) __mmplayer_release_dump_list(player->dump_list); - /* release miscellaneous information */ - __mmplayer_release_misc(player); - /* release miscellaneous information. these info needs to be released after pipeline is destroyed. */ __mmplayer_release_misc_post(player); @@ -4804,6 +5019,11 @@ _mmplayer_destroy(MMHandleType handle) /* release attributes */ _mmplayer_deconstruct_attribute(handle); + if (player->uri_info.uri_list) { + g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free); + player->uri_info.uri_list = NULL; + } + /* release lock */ g_mutex_clear(&player->fsink_lock); @@ -4814,9 +5034,6 @@ _mmplayer_destroy(MMHandleType handle) g_mutex_clear(&player->video_bo_mutex); g_cond_clear(&player->video_bo_cond); - /* release media stream callback lock */ - g_mutex_clear(&player->media_stream_cb_lock); - MMPLAYER_FLEAVE(); return MM_ERROR_NONE; @@ -4826,10 +5043,10 @@ int _mmplayer_realize(MMHandleType hplayer) { mmplayer_t *player = (mmplayer_t *)hplayer; + int ret = MM_ERROR_NONE; char *uri = NULL; void *param = NULL; MMHandleType attrs = 0; - int ret = MM_ERROR_NONE; MMPLAYER_FENTER(); @@ -4848,7 +5065,7 @@ _mmplayer_realize(MMHandleType hplayer) mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m); if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) { - ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile); + ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile); if (ret != MM_ERROR_NONE) { LOGE("failed to parse profile"); @@ -4882,21 +5099,21 @@ _mmplayer_realize(MMHandleType hplayer) 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; - __mmplayer_track_initialize(player); + _mmplayer_track_initialize(player); __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX); if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) { gint prebuffer_ms = 0, rebuffer_ms = 0; - player->streamer = __mm_player_streaming_create(); - __mm_player_streaming_initialize(player->streamer, TRUE); + player->streamer = _mm_player_streaming_create(); + _mm_player_streaming_initialize(player->streamer, TRUE); - mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms); - mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms); + mm_attrs_multiple_get(player->attrs, NULL, + MM_PLAYER_PREBUFFER_MS, &prebuffer_ms, + MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL); if (prebuffer_ms > 0) { prebuffer_ms = MAX(prebuffer_ms, 1000); @@ -4930,15 +5147,18 @@ _mmplayer_unrealize(MMHandleType hplayer) { 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); + _mmplayer_bus_msg_thread_destroy(player); MMPLAYER_CMD_LOCK(player); /* check current state */ @@ -4950,36 +5170,15 @@ _mmplayer_unrealize(MMHandleType hplayer) /* unrealize pipeline */ ret = __mmplayer_gst_unrealize(player); - /* set asm stop if success */ - if (MM_ERROR_NONE == ret) { - if (!player->interrupted_by_resource) { - if (player->video_decoder_resource != NULL) { - ret = mm_resource_manager_mark_for_release(player->resource_manager, - player->video_decoder_resource); - if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) - LOGE("failed to mark decoder resource for release, ret(0x%x)", ret); - else - player->video_decoder_resource = NULL; - } - - if (player->video_overlay_resource != NULL) { - ret = mm_resource_manager_mark_for_release(player->resource_manager, - player->video_overlay_resource); - if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) - LOGE("failed to mark overlay resource for release, ret(0x%x)", ret); - else - player->video_overlay_resource = NULL; - } + 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); + } - ret = mm_resource_manager_commit(player->resource_manager); - if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) - LOGE("failed to commit resource releases, ret(0x%x)", ret); - } - } else - LOGE("failed and don't change asm state to stop"); + player->interrupted_by_resource = FALSE; MMPLAYER_FLEAVE(); - return ret; } @@ -5005,157 +5204,130 @@ _mmplayer_get_state(MMHandleType hplayer, int *state) return MM_ERROR_NONE; } - -int -_mmplayer_set_volume(MMHandleType hplayer, mmplayer_volume_type_t volume) +static int +__mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name) { - mmplayer_t *player = (mmplayer_t *)hplayer; GstElement *vol_element = NULL; - int i = 0; + enum audio_element_id volume_elem_id = MMPLAYER_A_VOL; MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - LOGD("volume [L]=%f:[R]=%f", - volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]); - - /* invalid factor range or not */ - for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) { - if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) { - LOGE("Invalid factor!(valid factor:0~1.0)"); - return MM_ERROR_INVALID_ARGUMENT; - } - } - - /* not support to set other value into each channel */ - if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT])) - return MM_ERROR_INVALID_ARGUMENT; - - /* Save volume to handle. Currently the first array element will be saved. */ - player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT]; + MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT); /* check pipeline handle */ if (!player->pipeline || !player->pipeline->audiobin) { - LOGD("audiobin is not created yet"); - LOGD("but, current stored volume will be set when it's created."); + LOGD("'%s' will be applied when audiobin is created", prop_name); - /* NOTE : stored volume will be used in create_audiobin + /* NOTE : stored value will be used in create_audiobin * returning MM_ERROR_NONE here makes application to able to - * set volume at anytime. + * set audio volume or mute at anytime. */ return MM_ERROR_NONE; } - /* setting volume to volume element */ - vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst; + if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink")) + volume_elem_id = MMPLAYER_A_SINK; - if (vol_element) { - LOGD("volume is set [%f]", player->sound.volume); - g_object_set(vol_element, "volume", player->sound.volume, NULL); + vol_element = player->pipeline->audiobin[volume_elem_id].gst; + if (!vol_element) { + LOGE("failed to get vol element %d", volume_elem_id); + return MM_ERROR_PLAYER_INTERNAL; } - MMPLAYER_FLEAVE(); + LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element)); + + if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) { + LOGE("there is no '%s' property", prop_name); + return MM_ERROR_PLAYER_INTERNAL; + } + + if (!strcmp(prop_name, "volume")) { + g_object_set(vol_element, "volume", player->sound.volume, NULL); + } else if (!strcmp(prop_name, "mute")) { + g_object_set(vol_element, "mute", player->sound.mute, NULL); + } else { + LOGE("invalid property %s", prop_name); + return MM_ERROR_PLAYER_INTERNAL; + } return MM_ERROR_NONE; } int -_mmplayer_get_volume(MMHandleType hplayer, mmplayer_volume_type_t *volume) +_mmplayer_set_volume(MMHandleType hplayer, float volume) { + int ret = MM_ERROR_NONE; mmplayer_t *player = (mmplayer_t *)hplayer; - int i = 0; MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT); - /* returning stored volume */ - for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) - volume->level[i] = player->sound.volume; + LOGD("volume = %f", volume); - MMPLAYER_FLEAVE(); + /* invalid factor range or not */ + if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) { + LOGE("Invalid volume value"); + return MM_ERROR_INVALID_ARGUMENT; + } - return MM_ERROR_NONE; + player->sound.volume = volume; + + ret = __mmplayer_gst_set_volume_property(player, "volume"); + + MMPLAYER_FLEAVE(); + return ret; } int -_mmplayer_set_mute(MMHandleType hplayer, int mute) +_mmplayer_get_volume(MMHandleType hplayer, float *volume) { mmplayer_t *player = (mmplayer_t *)hplayer; - GstElement *vol_element = NULL; MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT); - /* mute value shoud 0 or 1 */ - if (mute != 0 && mute != 1) { - LOGE("bad mute value"); - - /* FIXIT : definitly, we need _BAD_PARAM error code */ - return MM_ERROR_INVALID_ARGUMENT; - } - - player->sound.mute = mute; - - /* just hold mute value if pipeline is not ready */ - if (!player->pipeline || !player->pipeline->audiobin) { - LOGD("pipeline is not ready. holding mute value"); - return MM_ERROR_NONE; - } - - vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst; + *volume = player->sound.volume; - /* NOTE : volume will only created when the bt is enabled */ - if (vol_element) { - LOGD("mute : %d", mute); - g_object_set(vol_element, "mute", mute, NULL); - } else - LOGD("volume elemnet is not created. using volume in audiosink"); + LOGD("current vol = %f", *volume); MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; } int -_mmplayer_get_mute(MMHandleType hplayer, int *pmute) +_mmplayer_set_mute(MMHandleType hplayer, bool mute) { + int ret = MM_ERROR_NONE; mmplayer_t *player = (mmplayer_t *)hplayer; MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT); - /* just hold mute value if pipeline is not ready */ - if (!player->pipeline || !player->pipeline->audiobin) { - LOGD("pipeline is not ready. returning stored value"); - *pmute = player->sound.mute; - return MM_ERROR_NONE; - } + LOGD("mute = %d", mute); - *pmute = player->sound.mute; + player->sound.mute = mute; - MMPLAYER_FLEAVE(); + ret = __mmplayer_gst_set_volume_property(player, "mute"); - return MM_ERROR_NONE; + MMPLAYER_FLEAVE(); + return ret; } int -_mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param) +_mmplayer_get_mute(MMHandleType hplayer, bool *mute) { mmplayer_t *player = (mmplayer_t *)hplayer; MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT); + + *mute = player->sound.mute; - player->video_stream_changed_cb = callback; - player->video_stream_changed_cb_user_param = user_param; - LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb); + LOGD("current mute = %d", *mute); MMPLAYER_FLEAVE(); @@ -5236,7 +5408,7 @@ _mmplayer_start(MMHandleType hplayer) MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START); /* start pipeline */ - ret = __mmplayer_gst_start(player); + ret = _mmplayer_gst_start(player); if (ret != MM_ERROR_NONE) LOGE("failed to start player."); @@ -5333,28 +5505,32 @@ __mmplayer_handle_missed_plugin(mmplayer_t *player) return MM_ERROR_NONE; } -static void -__mmplayer_check_pipeline(mmplayer_t *player) +static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player) { GstState element_state = GST_STATE_VOID_PENDING; GstState element_pending_state = GST_STATE_VOID_PENDING; - gint timeout = 0; - int ret = MM_ERROR_NONE; + GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; + gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); - if (!player->gapless.reconfigure) - return; + MMPLAYER_RETURN_IF_FAIL(player && player->pipeline); - LOGW("pipeline is under construction."); + MMPLAYER_RECONFIGURE_LOCK(player); + if (!player->gapless.reconfigure) { + MMPLAYER_RECONFIGURE_UNLOCK(player); + return; + } - MMPLAYER_PLAYBACK_LOCK(player); - MMPLAYER_PLAYBACK_UNLOCK(player); + LOGI("reconfigure is under process"); + MMPLAYER_RECONFIGURE_WAIT(player); + MMPLAYER_RECONFIGURE_UNLOCK(player); + LOGI("reconfigure is completed."); - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); + result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, + &element_state, &element_pending_state, timeout * GST_SECOND); + if (result == GST_STATE_CHANGE_FAILURE) + LOGW("failed to get pipeline state in %d sec", timeout); - /* wait for state transition */ - ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND); - if (ret == GST_STATE_CHANGE_FAILURE) - LOGE("failed to change pipeline state within %d sec", timeout); + return; } /* NOTE : it should be able to call 'stop' anytime*/ @@ -5371,18 +5547,20 @@ _mmplayer_stop(MMHandleType hplayer) /* check current state */ MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP); - /* check pipline building state */ - __mmplayer_check_pipeline(player); + /* need to wait till the rebuilding pipeline is completed */ + __mmplayer_check_pipeline_reconfigure_state(player); + MMPLAYER_RECONFIGURE_LOCK(player); __mmplayer_reset_gapless_state(player); + MMPLAYER_RECONFIGURE_UNLOCK(player); /* NOTE : application should not wait for EOS after calling STOP */ - __mmplayer_cancel_eos_timer(player); + _mmplayer_cancel_eos_timer(player); /* reset */ player->seek_state = MMPLAYER_SEEK_NONE; /* stop pipeline */ - ret = __mmplayer_gst_stop(player); + ret = _mmplayer_gst_stop(player); if (ret != MM_ERROR_NONE) LOGE("failed to stop player."); @@ -5407,14 +5585,14 @@ _mmplayer_pause(MMHandleType hplayer) /* check current state */ MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE); - /* check pipline building state */ - __mmplayer_check_pipeline(player); + /* 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")); @@ -5443,7 +5621,7 @@ _mmplayer_pause(MMHandleType hplayer) This causes problem is position calculation during normal pause resume scenarios also. Currently during pause , we are sending the current position to rtspsrc module for position saving. */ if ((MMPLAYER_IS_RTSP_STREAMING(player)) && - (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) { + (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) { g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL); } } @@ -5456,19 +5634,20 @@ _mmplayer_pause(MMHandleType hplayer) } /* pause pipeline */ - ret = __mmplayer_gst_pause(player, async); - - if (ret != MM_ERROR_NONE) + ret = _mmplayer_gst_pause(player, async); + 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 (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation")) + if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE) LOGE("failed to update display_rotation"); } MMPLAYER_FLEAVE(); - - return ret; + return MM_ERROR_NONE; } /* in case of streaming, pause could take long time.*/ @@ -5488,7 +5667,7 @@ _mmplayer_abort_pause(MMHandleType hplayer) LOGD("set the pipeline state to READY"); /* set state to READY */ - ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, + 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"); @@ -5524,7 +5703,7 @@ _mmplayer_resume(MMHandleType hplayer) /* check current state */ MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME); - ret = __mmplayer_gst_resume(player, async); + ret = _mmplayer_gst_resume(player, async); if (ret != MM_ERROR_NONE) LOGE("failed to resume player."); @@ -5544,7 +5723,7 @@ _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming) mmplayer_t *player = (mmplayer_t *)hplayer; gint64 pos_nsec = 0; int ret = MM_ERROR_NONE; - int mute = FALSE; + bool mute = false; signed long long start = 0, stop = 0; mmplayer_state_e current_state = MM_PLAYER_STATE_NONE; MMPLAYER_FENTER(); @@ -5555,7 +5734,7 @@ _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming) /* The sound of video is not supported under 0.0 and over 2.0. */ if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) { if (player->can_support_codec & FOUND_PLUGIN_VIDEO) - mute = TRUE; + mute = true; } _mmplayer_set_mute(hplayer, mute); @@ -5588,7 +5767,7 @@ _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming) stop = pos_nsec; } - if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, + if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), @@ -5615,10 +5794,10 @@ _mmplayer_set_position(MMHandleType hplayer, gint64 position) MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - /* check pipline building state */ - __mmplayer_check_pipeline(player); + /* check pipeline reconfigure state */ + __mmplayer_check_pipeline_reconfigure_state(player); - ret = __mmplayer_gst_set_position(player, position, FALSE); + ret = _mmplayer_gst_set_position(player, position, FALSE); MMPLAYER_FLEAVE(); @@ -5626,19 +5805,6 @@ _mmplayer_set_position(MMHandleType hplayer, gint64 position) } int -_mmplayer_get_position(MMHandleType hplayer, gint64 *position) -{ - mmplayer_t *player = (mmplayer_t *)hplayer; - int ret = MM_ERROR_NONE; - - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - ret = __mmplayer_gst_get_position(player, position); - - return ret; -} - -int _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration) { mmplayer_t *player = (mmplayer_t *)hplayer; @@ -5662,13 +5828,13 @@ _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos); + ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos); return ret; } 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; @@ -5710,8 +5876,8 @@ __mmplayer_is_only_mp3_type(gchar *str_caps) 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; @@ -5724,10 +5890,11 @@ __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps) /* set stream information */ gst_structure_get_int(caps_structure, "rate", &samplerate); - mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate); - gst_structure_get_int(caps_structure, "channels", &channels); - mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels); + + mm_player_set_attribute((MMHandleType)player, NULL, + "content_audio_samplerate", samplerate, + "content_audio_channels", channels, NULL); LOGD("audio samplerate : %d channels : %d", samplerate, channels); } @@ -5776,17 +5943,24 @@ __mmplayer_update_content_type_info(mmplayer_t *player) } void -__mmplayer_typefind_have_type(GstElement *tf, guint probability, +_mmplayer_typefind_have_type(GstElement *tf, guint probability, 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) @@ -5812,32 +5986,32 @@ __mmplayer_typefind_have_type(GstElement *tf, guint probability, __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; } GstElement * -__mmplayer_gst_make_decodebin(mmplayer_t *player) +_mmplayer_gst_make_decodebin(mmplayer_t *player) { GstElement *decodebin = NULL; @@ -5852,38 +6026,42 @@ __mmplayer_gst_make_decodebin(mmplayer_t *player) } /* 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); + _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_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_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_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", - G_CALLBACK(__mmplayer_gst_decode_pad_removed), (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); /* 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); + _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_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", - G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)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); + + 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", + G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (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); + _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_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained", - G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)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_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added", - G_CALLBACK(__mmplayer_gst_element_added), (gpointer)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; @@ -5924,7 +6102,7 @@ __mmplayer_gst_make_queue2(mmplayer_t *player) dur_bytes = 0; } - __mm_player_streaming_set_queue2(player->streamer, + _mm_player_streaming_set_queue2(player->streamer, queue2, FALSE, type, @@ -5934,7 +6112,7 @@ __mmplayer_gst_make_queue2(mmplayer_t *player) } gboolean -__mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps) +_mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps) { mmplayer_gst_element_t *mainbin = NULL; GstElement *decodebin = NULL; @@ -5988,7 +6166,7 @@ __mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps } /* create decodebin */ - decodebin = __mmplayer_gst_make_decodebin(player); + decodebin = _mmplayer_gst_make_decodebin(player); if (!decodebin) { LOGE("failed to make decodebin"); goto ERROR; @@ -6147,8 +6325,8 @@ DONE: 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; @@ -6157,9 +6335,9 @@ __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data) MMPLAYER_RETURN_IF_FAIL(player); /* remove fakesink. */ - if (!__mmplayer_gst_remove_fakesink(player, + 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. @@ -6169,8 +6347,7 @@ __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data) LOGD("[handle: %p] pipeline has completely constructed", player); - if ((player->ini.async_start) && - (player->msg_posted == FALSE) && + if ((player->msg_posted == FALSE) && (player->cmd >= MMPLAYER_COMMAND_START)) __mmplayer_handle_missed_plugin(player); @@ -6220,7 +6397,7 @@ __mmplayer_get_next_uri(mmplayer_t *player) continue; } - if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) { + if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) { LOGE("failed to parse profile"); continue; } @@ -6235,16 +6412,15 @@ __mmplayer_get_next_uri(mmplayer_t *player) break; } - if (uri_idx == num_of_list) { + if (!uri || uri_idx == num_of_list) { LOGE("failed to find next uri"); return FALSE; } player->uri_info.uri_idx = uri_idx; - mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri); - - if (mm_attrs_commit_all(player->attrs)) { - LOGE("failed to commit"); + if (mm_player_set_attribute((MMHandleType)player, NULL, + "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) { + LOGE("failed to set attribute"); return FALSE; } @@ -6255,20 +6431,26 @@ __mmplayer_get_next_uri(mmplayer_t *player) static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player) { -#define REPEAT_COUNT_INFINITELY -1 +#define REPEAT_COUNT_INFINITE -1 #define REPEAT_COUNT_MIN 2 +#define ORIGINAL_URI_ONLY 1 MMHandleType attrs = 0; gint video = 0; gint count = 0; gint gapless = 0; - guint num_of_list = 0; + guint num_of_uri = 0; int profile_tv = -1; MMPLAYER_FENTER(); LOGD("checking for gapless play option"); + if (player->build_audio_offload) { + LOGE("offload path is not supportable."); + goto ERROR; + } + if (player->pipeline->textbin) { LOGE("subtitle path is enabled. gapless play is not supported."); goto ERROR; @@ -6280,7 +6462,10 @@ __mmplayer_verify_gapless_play_path(mmplayer_t *player) goto ERROR; } - mm_attrs_get_int_by_name(attrs, "content_video_found", &video); + mm_attrs_multiple_get(player->attrs, NULL, + "content_video_found", &video, + "profile_play_count", &count, + MM_PLAYER_GAPLESS_MODE, &gapless, NULL); /* gapless playback is not supported in case of video at TV profile. */ profile_tv = __mmplayer_check_profile(); @@ -6289,35 +6474,25 @@ __mmplayer_verify_gapless_play_path(mmplayer_t *player) goto ERROR; } - if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) - LOGE("failed to get play count"); - - if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE) - LOGE("failed to get gapless mode"); - /* check repeat count in case of audio */ if (!gapless && - (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) { + (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) { LOGW("gapless is disabled"); goto ERROR; } - num_of_list = g_list_length(player->uri_info.uri_list); + num_of_uri = g_list_length(player->uri_info.uri_list); - LOGD("repeat count = %d, num_of_list = %d", count, num_of_list); + LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri); - if (num_of_list == 0) { + if (num_of_uri == ORIGINAL_URI_ONLY) { /* audio looping path */ if (count >= REPEAT_COUNT_MIN) { /* decrease play count */ /* we succeeded to rewind. update play count and then wait for next EOS */ count--; - mm_attrs_set_int_by_name(attrs, "profile_play_count", count); - /* commit attribute */ - if (mm_attrs_commit_all(attrs)) - LOGE("failed to commit attribute"); - - } else if (count != REPEAT_COUNT_INFINITELY) { + mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL); + } else if (count != REPEAT_COUNT_INFINITE) { LOGD("there is no next uri and no repeat"); goto ERROR; } @@ -6337,200 +6512,95 @@ ERROR: } static void -__mmplayer_initialize_gapless_play(mmplayer_t *player) +__mmplayer_remove_sinkpad (const GValue *item, gpointer user_data) { - int i; - - MMPLAYER_FENTER(); - - player->smooth_streaming = FALSE; - player->videodec_linked = 0; - player->audiodec_linked = 0; - player->textsink_linked = 0; - player->is_external_subtitle_present = FALSE; - player->is_external_subtitle_added_now = FALSE; - player->not_supported_codec = MISSING_PLUGIN_NONE; - player->can_support_codec = FOUND_PLUGIN_NONE; - player->pending_seek.is_pending = false; - player->pending_seek.pos = 0; - player->msg_posted = FALSE; - player->has_many_types = FALSE; - player->no_more_pad = FALSE; - player->not_found_demuxer = 0; - player->seek_state = MMPLAYER_SEEK_NONE; - player->is_subtitle_force_drop = FALSE; - player->play_subtitle = FALSE; - player->adjust_subtitle_pos = 0; - - player->total_bitrate = 0; - player->total_maximum_bitrate = 0; - - __mmplayer_track_initialize(player); - __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX); - - for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) { - player->bitrate[i] = 0; - player->maximum_bitrate[i] = 0; - } - - if (player->v_stream_caps) { - gst_caps_unref(player->v_stream_caps); - player->v_stream_caps = NULL; - } - - mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0); - - /* 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); - player->audio_decoders = NULL; + GstPad *sinkpad = g_value_get_object (item); + GstElement *element = GST_ELEMENT(user_data); + if (!sinkpad || !element) { + LOGE("invalid parameter"); + return; } - MMPLAYER_FLEAVE(); + 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 void -__mmplayer_activate_next_source(mmplayer_t *player, GstState target) +static gboolean +__mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type) { - mmplayer_gst_element_t *mainbin = NULL; - MMMessageParamType msg_param = {0,}; - GstElement *element = NULL; - MMHandleType attrs = 0; - char *uri = NULL; - main_element_id_e elem_idx = MMPLAYER_M_NUM; + 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); - if (!player || !player->pipeline || !player->pipeline->mainbin) { - LOGE("player is not initialized"); - goto ERROR; - } - - mainbin = player->pipeline->mainbin; - msg_param.code = MM_ERROR_PLAYER_INTERNAL; - - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("fail to get attributes"); - goto ERROR; - } - - /* Initialize Player values */ - __mmplayer_initialize_gapless_play(player); - - 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"); - msg_param.code = MM_ERROR_PLAYER_INVALID_URI; - goto ERROR; - } - - if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) || - (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) { - LOGE("dash or hls is not supportable"); - msg_param.code = MM_ERROR_PLAYER_INVALID_URI; - goto ERROR; - } - - element = __mmplayer_gst_create_source(player); - if (!element) { - 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"); - gst_object_unref(GST_OBJECT(element)); - element = NULL; - goto ERROR; - } - - /* take source element */ - mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC; - mainbin[MMPLAYER_M_SRC].gst = element; - - element = NULL; - - if (MMPLAYER_IS_HTTP_STREAMING(player)) { - if (player->streamer == NULL) { - player->streamer = __mm_player_streaming_create(); - __mm_player_streaming_initialize(player->streamer, TRUE); - } - - elem_idx = MMPLAYER_M_TYPEFIND; - element = gst_element_factory_make("typefind", "typefinder"); - __mmplayer_add_signal_connection(player, G_OBJECT(element), - MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player); - } else { - elem_idx = MMPLAYER_M_AUTOPLUG; - element = __mmplayer_gst_make_decodebin(player); - } - - /* check autoplug element is OK */ - if (!element) { - LOGE("can not create element(%d)", elem_idx); - goto ERROR; - } - - if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) { - LOGE("failed to add sinkbin to pipeline"); - gst_object_unref(GST_OBJECT(element)); - element = NULL; - goto ERROR; - } - - mainbin[elem_idx].id = elem_idx; - mainbin[elem_idx].gst = element; + LOGD("type %d", type); - if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) { - LOGE("Failed to link src - autoplug(or typefind)"); - goto ERROR; + 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; } - if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) { - LOGE("Failed to change state of src element"); - goto ERROR; - } + element = player->pipeline->mainbin[concatId].gst; + if (!element) + return TRUE; - 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"); - 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"); - goto ERROR; + 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); } - player->gapless.stream_changed = TRUE; - player->gapless.running = TRUE; - MMPLAYER_FLEAVE(); - return; - -ERROR: - if (player) { - MMPLAYER_PLAYBACK_UNLOCK(player); + 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); - if (!player->msg_posted) { - MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); - player->msg_posted = TRUE; - } - } - return; + 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; @@ -6601,11 +6671,12 @@ __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type) 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); @@ -6623,25 +6694,32 @@ __mmplayer_deactivate_old_path(mmplayer_t *player) 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); + _mmplayer_track_destroy(player); __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG); if (player->streamer) { - __mm_player_streaming_initialize(player->streamer, FALSE); - __mm_player_streaming_destroy(player->streamer); + _mm_player_streaming_initialize(player->streamer, FALSE); + _mm_player_streaming_destroy(player->streamer); player->streamer = NULL; } - MMPLAYER_PLAYBACK_LOCK(player); MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player); - MMPLAYER_FLEAVE(); return; @@ -6668,10 +6746,11 @@ _mmplayer_set_uri(MMHandleType hplayer, const char *uri) MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT); - mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri); - if (mm_attrs_commit_all(player->attrs)) { - LOGE("failed to commit the original uri."); + if (mm_player_set_attribute(hplayer, NULL, + "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) { + LOGE("failed to set attribute"); result = MM_ERROR_PLAYER_INTERNAL; } else { if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE) @@ -6705,9 +6784,9 @@ _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path 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 { @@ -6755,7 +6834,7 @@ _mmplayer_get_next_uri(MMHandleType hplayer, char **uri) 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; @@ -6770,8 +6849,8 @@ _mmplayer_get_next_uri(MMHandleType hplayer, char **uri) 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; @@ -6792,9 +6871,9 @@ __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, __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; @@ -6821,15 +6900,10 @@ __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, caps_str = gst_caps_to_string(caps); /* set it directly because not sent by TAG */ if (g_strrstr(caps_str, "mobile-xmf")) - mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf"); + mm_player_set_attribute((MMHandleType)player, NULL, + "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL); + MMPLAYER_FREEIF(caps_str); - } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) { - MMMessageParamType msg_param; - memset(&msg_param, 0, sizeof(MMMessageParamType)); - msg_param.code = MM_ERROR_NOT_SUPPORT_API; - MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); - LOGD("video file is not supported on this device"); - ret = FALSE; } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) { LOGD("already video linked"); ret = FALSE; @@ -6843,7 +6917,7 @@ __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, static gboolean __mmplayer_is_audio_offload_device_type(mmplayer_t *player) { - gboolean ret = TRUE; + gboolean ret = FALSE; GDBusConnection *conn = NULL; GError *err = NULL; GVariant *result = NULL; @@ -6853,9 +6927,8 @@ __mmplayer_is_audio_offload_device_type(mmplayer_t *player) conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); if (!conn || err) { - LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL); + LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null")); g_error_free(err); - ret = FALSE; goto DONE; } @@ -6871,9 +6944,8 @@ __mmplayer_is_audio_offload_device_type(mmplayer_t *player) NULL, &err); if (!result || err) { - LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL); + LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null")); g_error_free(err); - ret = FALSE; goto DONE; } @@ -6881,10 +6953,8 @@ __mmplayer_is_audio_offload_device_type(mmplayer_t *player) g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret); LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret); - if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) { - ret = FALSE; + if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) goto DONE; - } /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */ for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) { @@ -6896,11 +6966,11 @@ __mmplayer_is_audio_offload_device_type(mmplayer_t *player) } LOGD("audio offload is not supportable"); - ret = FALSE; DONE: g_variant_unref(result); - g_object_unref(conn); + if (conn) + g_object_unref(conn); return ret; } @@ -6925,9 +6995,7 @@ static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player) _mmplayer_set_position((MMHandleType)player, position); /* async not to be blocked in streaming case */ - mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE); - if (mm_attrs_commit_all(player->attrs)) - LOGE("failed to commit"); + mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL); _mmplayer_pause((MMHandleType)player); @@ -6992,6 +7060,37 @@ __mmplayer_add_audio_device_connected_cb(mmplayer_t *player) return TRUE; } +int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated) +{ + mmplayer_t *player = (mmplayer_t *)hplayer; + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT); + + *activated = player->build_audio_offload; + + LOGD("offload activated : %d", (int)*activated); + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; +} + +static gboolean +__mmplayer_is_offload_supported_type(mmplayer_t *player) +{ + /* NOTE : + this function need to be updated according to the supported media format + @see player->ini.audio_offload_media_format */ + + if (__mmplayer_is_only_mp3_type(player->type)) { + LOGD("offload supportable media format type"); + return TRUE; + } + + return FALSE; +} + static gboolean __mmplayer_can_build_audio_offload_path(mmplayer_t *player) { @@ -7002,7 +7101,7 @@ __mmplayer_can_build_audio_offload_path(mmplayer_t *player) MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE); LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element); - if (!__mmplayer_is_only_mp3_type(player->type)) + if (!__mmplayer_is_offload_supported_type(player)) goto DONE; if (!strcmp(player->ini.audio_offload_sink_element, "")) { @@ -7022,6 +7121,12 @@ __mmplayer_can_build_audio_offload_path(mmplayer_t *player) } gst_object_unref(factory); + if (_mmplayer_acquire_hw_resource(player, + MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) { + LOGE("failed to acquire audio offload decoder resource"); + goto DONE; + } + if (!__mmplayer_add_audio_device_connected_cb(player)) goto DONE; @@ -7032,6 +7137,9 @@ __mmplayer_can_build_audio_offload_path(mmplayer_t *player) ret = TRUE; DONE: + if (!ret) + __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD); + MMPLAYER_FLEAVE(); return ret; } @@ -7040,8 +7148,6 @@ static GstAutoplugSelectResult __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name) { GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY; - int idx = 0; - int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT; int audio_offload = 0; if ((g_strrstr(klass, "Codec/Decoder/Audio"))) { @@ -7059,88 +7165,37 @@ __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps goto DONE; } - mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type); - - LOGD("audio codec type: %d", codec_type); - if (codec_type == MM_PLAYER_CODEC_TYPE_HW) { - /* sw codec will be skipped */ - for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) { - if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) { - LOGW("skipping sw acodec:[%s] by codec type", factory_name); - ret = GST_AUTOPLUG_SELECT_SKIP; - goto DONE; - } - } - } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) { - /* hw codec will be skipped */ - if (strcmp(player->ini.audiocodec_element_hw, "") && - g_strrstr(factory_name, player->ini.audiocodec_element_hw)) { - LOGW("skipping hw acodec:[%s] by codec type", factory_name); - ret = GST_AUTOPLUG_SELECT_SKIP; - goto DONE; - } - } + /* FIXME: If HW audio decoder is selected, related resource have to be acquired here. + And need to consider the multi-track audio content. + There is no HW audio decoder in public. */ /* 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; - player->can_support_codec |= FOUND_PLUGIN_AUDIO; - player->audiodec_linked = 1; - - } else if (g_strrstr(klass, "Codec/Decoder/Video")) { - - mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type); - - LOGD("video codec type: %d", codec_type); - if (codec_type == MM_PLAYER_CODEC_TYPE_HW) { - /* sw codec is skipped */ - for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) { - if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) { - LOGW("skipping sw vcodec:[%s] by codec type", factory_name); - ret = GST_AUTOPLUG_SELECT_SKIP; - goto DONE; - } - } - } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) { - /* hw codec is skipped */ - if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) { - LOGW("skipping hw vcodec:[%s] by codec type", factory_name); - ret = GST_AUTOPLUG_SELECT_SKIP; - goto DONE; - } - } + 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")) { if ((strlen(player->ini.videocodec_element_hw) > 0) && (g_strrstr(factory_name, player->ini.videocodec_element_hw))) { /* mark video decoder for acquire */ - if (player->video_decoder_resource == NULL) { - if (mm_resource_manager_mark_for_acquire(player->resource_manager, - MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER, - MM_RESOURCE_MANAGER_RES_VOLUME_FULL, - &player->video_decoder_resource) - != MM_RESOURCE_MANAGER_ERROR_NONE) { - LOGE("could not mark video_decoder resource for acquire"); - ret = GST_AUTOPLUG_SELECT_SKIP; - goto DONE; - } - } else { + if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) { LOGW("video decoder resource is already acquired, skip it."); ret = GST_AUTOPLUG_SELECT_SKIP; goto DONE; } - player->interrupted_by_resource = FALSE; - /* acquire resources for video playing */ - if (mm_resource_manager_commit(player->resource_manager) - != MM_RESOURCE_MANAGER_ERROR_NONE) { - LOGE("could not acquire resources for video decoding"); + 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; } + player->interrupted_by_resource = FALSE; } /* update codec info */ @@ -7153,8 +7208,132 @@ DONE: return ret; } +GValueArray * +_mmplayer_gst_decode_autoplug_sort(GstElement *bin, + GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data) +{ +#define DEFAULT_IDX 0xFFFF +#define MIN_FACTORY_NUM 2 + mmplayer_t *player = (mmplayer_t *)data; + GValueArray *new_factories = NULL; + GValue val = { 0, }; + GstElementFactory *factory = NULL; + const gchar *klass = NULL; + gchar *factory_name = NULL; + guint hw_dec_idx = DEFAULT_IDX; + guint first_sw_dec_idx = DEFAULT_IDX; + guint last_sw_dec_idx = DEFAULT_IDX; + guint new_pos = DEFAULT_IDX; + guint rm_pos = DEFAULT_IDX; + int audio_codec_type; + int video_codec_type; + mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT; + + if (factories->n_values < MIN_FACTORY_NUM) + return NULL; + + mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type); + mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type); + +#ifdef __DEBUG__ + LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type); +#endif + for (int i = 0 ; i < factories->n_values ; i++) { + gchar *hw_dec_info = NULL; + 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); + +#ifdef __DEBUG__ + LOGD("Klass [%s] Factory [%s]", klass, factory_name); +#endif + if (g_strrstr(klass, "Codec/Decoder/Audio")) { + if (!player->need_audio_dec_sorting) { + LOGD("sorting is not required"); + return NULL; + } + codec_type = audio_codec_type; + hw_dec_info = player->ini.audiocodec_element_hw; + sw_dec_info = player->ini.audiocodec_element_sw; + } else if (g_strrstr(klass, "Codec/Decoder/Video")) { + if (!player->need_video_dec_sorting) { + LOGD("sorting is not required"); + return NULL; + } + codec_type = video_codec_type; + hw_dec_info = player->ini.videocodec_element_hw; + sw_dec_info = player->ini.videocodec_element_sw; + } else { + continue; + } + + if (g_strrstr(factory_name, hw_dec_info)) { + hw_dec_idx = i; + } else { + for (int j = 0; sw_dec_info[j][0] != '\0'; j++) { + if (strstr(factory_name, sw_dec_info[j])) { + last_sw_dec_idx = i; + if (first_sw_dec_idx == DEFAULT_IDX) { + first_sw_dec_idx = i; + } + } + } + + if (first_sw_dec_idx == DEFAULT_IDX) + LOGW("unknown codec %s", factory_name); + } + } + + if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX) + return NULL; + + if (codec_type == MM_PLAYER_CODEC_TYPE_HW) { + if (hw_dec_idx < first_sw_dec_idx) + return NULL; + 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) + return NULL; + new_pos = last_sw_dec_idx + 1; + rm_pos = hw_dec_idx; + } else { + return NULL; + } + + /* change position - insert H/W decoder according to the new position */ + 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); + g_value_unset (&val); + g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */ + + for (int i = 0 ; i < new_factories->n_values ; i++) { + factory = g_value_get_object(g_value_array_get_nth(new_factories, i)); + 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; +} + gint -__mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad, +_mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *factory, gpointer data) { GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY; @@ -7180,7 +7359,7 @@ __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad, /* 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; @@ -7283,8 +7462,8 @@ DONE: return result; } -static void -__mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, +void +_mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data) { //mmplayer_t *player = (mmplayer_t *)data; @@ -7307,8 +7486,38 @@ __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gst_caps_unref(caps); } -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_GAPLESS_CONSTRUCTION, 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; @@ -7320,22 +7529,21 @@ __mmplayer_gst_decode_drained(GstElement *bin, gpointer data) 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"); return; } - if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */ - !__mmplayer_verify_gapless_play_path(player)) { + if (!__mmplayer_verify_gapless_play_path(player)) { LOGD("decoding is finished."); - __mmplayer_reset_gapless_state(player); MMPLAYER_CMD_UNLOCK(player); return; } - player->gapless.reconfigure = TRUE; + _mmplayer_set_reconfigure_state(player, TRUE); + MMPLAYER_CMD_UNLOCK(player); /* check decodebin src pads whether they received EOS or not */ iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst); @@ -7365,7 +7573,6 @@ __mmplayer_gst_decode_drained(GstElement *bin, gpointer data) if (!is_all_drained) { LOGD("Wait util the all pads get EOS."); - MMPLAYER_CMD_UNLOCK(player); MMPLAYER_FLEAVE(); return; } @@ -7376,13 +7583,12 @@ __mmplayer_gst_decode_drained(GstElement *bin, gpointer data) /* 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_deactivate_old_path(player); - MMPLAYER_CMD_UNLOCK(player); MMPLAYER_FLEAVE(); } void -__mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data) +_mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data) { mmplayer_t *player = (mmplayer_t *)data; const gchar *klass = NULL; @@ -7400,6 +7606,16 @@ __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data 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")) { @@ -7415,7 +7631,9 @@ __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data "max-video-height", player->adaptive_info.limit.height, NULL); } else if (g_strrstr(klass, "Demuxer")) { - //LOGD("plugged element is demuxer. take it"); +#ifdef __DEBUG__ + LOGD("plugged element is demuxer. take it"); +#endif player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX; player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element; } @@ -7454,8 +7672,8 @@ __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) { /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/ - __mm_player_streaming_set_multiqueue(player->streamer, element); - __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst); + _mm_player_streaming_set_multiqueue(player->streamer, element); + _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst); } } @@ -7472,20 +7690,6 @@ __mmplayer_release_misc(mmplayer_t *player) MMPLAYER_RETURN_IF_FAIL(player); - player->video_decoded_cb = NULL; - player->video_decoded_cb_user_param = NULL; - player->video_stream_prerolled = false; - - player->audio_decoded_cb = NULL; - player->audio_decoded_cb_user_param = NULL; - player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT; - - player->video_stream_changed_cb = NULL; - player->video_stream_changed_cb_user_param = NULL; - - player->audio_stream_changed_cb = NULL; - player->audio_stream_changed_cb_user_param = NULL; - player->sent_bos = FALSE; player->playback_rate = DEFAULT_PLAYBACK_RATE; @@ -7515,7 +7719,8 @@ __mmplayer_release_misc(mmplayer_t *player) /* recover mode */ player->set_mode.rich_audio = cur_mode; - if (mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE) + if (player->audio_device_cb_id > 0 && + mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE) LOGW("failed to remove audio device_connected_callback"); player->audio_device_cb_id = 0; @@ -7524,17 +7729,6 @@ __mmplayer_release_misc(mmplayer_t *player) player->maximum_bitrate[i] = 0; } - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); - - /* remove media stream cb(appsrc cb) */ - for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) { - player->media_stream_buffer_status_cb[i] = NULL; - player->media_stream_seek_data_cb[i] = NULL; - player->buffer_cb_user_param[i] = NULL; - player->seek_cb_user_param[i] = NULL; - } - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); - /* free memory related to audio effect */ MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin); @@ -7572,49 +7766,48 @@ __mmplayer_release_misc(mmplayer_t *player) 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. */ - MMPLAYER_RETURN_IF_FAIL(player); - mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0); + player->video_decoded_cb = NULL; + player->video_decoded_cb_user_param = NULL; + player->video_stream_prerolled = false; + + player->audio_decoded_cb = NULL; + player->audio_decoded_cb_user_param = NULL; + player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT; + + 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); /* 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) { + 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 (player->attrs) { - mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri); - LOGD("restore original uri = %s", original_uri); - - if (mm_attrs_commit_all(player->attrs)) - LOGE("failed to commit the original uri."); - } + if (!original_uri) + LOGW("failed to get original uri info"); - 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); - player->uri_info.uri_list = NULL; + mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri", + original_uri, (original_uri) ? strlen(original_uri) : (0), NULL); + MMPLAYER_FREEIF(original_uri); } /* clear the audio stream buffer list */ - __mmplayer_audio_stream_clear_buffer(player, FALSE); + _mmplayer_audio_stream_clear_buffer(player, FALSE); /* clear the video stream bo list */ __mmplayer_video_stream_destroy_bo_list(player); @@ -7659,7 +7852,7 @@ __mmplayer_check_subtitle(mmplayer_t *player) } void -__mmplayer_cancel_eos_timer(mmplayer_t *player) +_mmplayer_cancel_eos_timer(mmplayer_t *player) { MMPLAYER_RETURN_IF_FAIL(player); @@ -7673,14 +7866,17 @@ __mmplayer_cancel_eos_timer(mmplayer_t *player) } 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(); } @@ -7699,7 +7895,7 @@ __mmplayer_del_sink(mmplayer_t *player, GstElement *sink) } void -__mmplayer_add_signal_connection(mmplayer_t *player, GObject *object, +_mmplayer_add_signal_connection(mmplayer_t *player, GObject *object, mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data) { mmplayer_signal_item_t *item = NULL; @@ -7786,22 +7982,20 @@ __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e } int -_mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay) +_mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id) { mmplayer_t *player = 0; int prev_display_surface_type = 0; - void *prev_display_overlay = NULL; MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT); - MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT); player = MM_PLAYER_CAST(handle); /* check video sinkbin is created */ - if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) { - LOGE("Videosink is already created"); + if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) { + LOGW("Videosink is already created"); return MM_ERROR_NONE; } @@ -7816,7 +8010,6 @@ _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_typ /* load previous attributes */ if (player->attrs) { mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type); - mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay); LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type); if (prev_display_surface_type == surface_type) { LOGD("incoming display surface type is same as previous one, do nothing.."); @@ -7831,13 +8024,8 @@ _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_typ /* videobin is not created yet, so we just set attributes related to display surface */ LOGD("store display attribute for given surface type(%d)", surface_type); - mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type); - mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay)); - if (mm_attrs_commit_all(player->attrs)) { - LOGE("failed to commit attribute"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; - } + mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type, + "display_overlay", wl_surface_id, NULL); MMPLAYER_FLEAVE(); return MM_ERROR_NONE; @@ -7934,7 +8122,7 @@ _mmplayer_sync_subtitle_pipeline(mmplayer_t *player) LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate); event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1); if (event) { - __mmplayer_gst_send_event_to_sink(player, event); + _mmplayer_gst_send_event_to_sink(player, event); } else { result = MM_ERROR_PLAYER_INTERNAL; LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */ @@ -7955,7 +8143,7 @@ ERROR: /* 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; @@ -8014,22 +8202,22 @@ __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *fil goto EXIT; } - if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) { + if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) { LOGE("failed to get storage info of subtitle path"); result = MM_ERROR_PLAYER_INVALID_URI; goto EXIT; } - LOGD("old subtitle file path is [%s]", subtitle_uri); - LOGD("new subtitle file path is [%s]", filepath); + SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri); + SECURE_LOGD("new subtitle file path is [%s]", filepath); if (!strcmp(filepath, subtitle_uri)) { - LOGD("No need to swtich subtitle, as input filepath is same as current filepath"); + LOGD("subtitle path is not changed"); goto EXIT; } else { - mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); - if (mm_attrs_commit_all(player->attrs)) { - LOGE("failed to commit."); + if (mm_player_set_attribute((MMHandleType)player, NULL, + "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) { + LOGE("failed to set attribute"); goto EXIT; } } @@ -8064,7 +8252,7 @@ __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *fil g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL); - charset = util_get_charset(filepath); + charset = _mmplayer_get_charset(filepath); if (charset) { LOGD("detected charset is %s", charset); g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL); @@ -8094,9 +8282,9 @@ _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath) if (filepath) { /* check file path */ if ((path = strstr(filepath, "file://"))) - result = util_exist_file_path(path + 7); + result = _mmplayer_exist_file_path(path + 7); else - result = util_exist_file_path(filepath); + result = _mmplayer_exist_file_path(filepath); if (result != MM_ERROR_NONE) { LOGE("invalid subtitle path 0x%X", result); @@ -8106,9 +8294,9 @@ _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath) if (!player->pipeline) { /* IDLE state */ - mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); - if (mm_attrs_commit_all(player->attrs)) { - LOGE("failed to commit"); /* subtitle path will not be created */ + if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath, + (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) { + LOGE("failed to set attribute"); return MM_ERROR_PLAYER_INTERNAL; } } else { @@ -8117,13 +8305,13 @@ _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath) MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT); if (!__mmplayer_check_subtitle(player)) { - mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); - if (mm_attrs_commit_all(player->attrs)) { - LOGE("failed to commit"); + if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", + filepath, strlen(filepath), NULL) != MM_ERROR_NONE) { + LOGE("failed to set attribute"); return MM_ERROR_PLAYER_INTERNAL; } - if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) { + if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) { LOGE("fail to create text pipeline"); return MM_ERROR_PLAYER_INTERNAL; } @@ -8150,6 +8338,44 @@ _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath) } 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; + GstEvent *ev = NULL; + GstCaps *caps = NULL; + + 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 */ + if (player->track[i].total_track_num > 0) { + 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); + } + } + } + } + + ev = gst_event_new_select_streams(streams); + gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev); + g_list_free(streams); + + 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; @@ -8185,7 +8411,7 @@ __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, i 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"); @@ -8225,7 +8451,10 @@ __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, i 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); @@ -8242,7 +8471,6 @@ _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type gint current_active_index = 0; GstState current_state = GST_STATE_VOID_PENDING; - GstEvent *event = NULL; gint64 time = 0; MMPLAYER_FENTER(); @@ -8253,13 +8481,13 @@ _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type 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) @@ -8273,27 +8501,34 @@ _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type 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; + } } } @@ -8374,9 +8609,9 @@ __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_ MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS); gst_buffer_map(buffer, &probe_info, GST_MAP_READ); - -// LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); - +#ifdef __DEBUG__ + LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); +#endif fwrite(probe_info.data, 1, probe_info.size , dump_data); gst_buffer_unmap(buffer, &probe_info); @@ -8431,7 +8666,9 @@ _mm_player_video_stream_internal_buffer_unref(void *buffer) { MMPLAYER_FENTER(); if (buffer) { - // LOGD("unref internal gst buffer %p", buffer); +#ifdef __DEBUG__ + LOGD("unref internal gst buffer %p", buffer); +#endif gst_buffer_unref((GstBuffer *)buffer); buffer = NULL; } @@ -8459,25 +8696,6 @@ _mmplayer_get_timeout(MMHandleType hplayer, int *timeout) return MM_ERROR_NONE; } -int -_mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num) -{ - mmplayer_t *player = (mmplayer_t *)hplayer; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT); - - *num = player->video_num_buffers; - *extra_num = player->video_extra_num_buffers; - - LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num); - - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; -} - static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type) { @@ -8516,7 +8734,7 @@ _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state) 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) @@ -8656,61 +8874,71 @@ _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, } int -_mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type) +_mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type) { #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); - MMHandleType attrs = 0; + 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 */ - 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("update %s codec_type to %d", attr_name, codec_type); + LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw); - attrs = MMPLAYER_GET_ATTRS(player); - mm_attrs_set_int_by_name(attrs, attr_name, codec_type); + 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; + } - if (mm_attrs_commit_all(player->attrs)) { - LOGE("failed to commit codec_type attributes"); - return MM_ERROR_PLAYER_INTERNAL; + 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); + mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL); + MMPLAYER_FLEAVE(); return MM_ERROR_NONE; } @@ -8789,7 +9017,7 @@ _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_ { mmplayer_t *player = (mmplayer_t *)hplayer; MMHandleType attrs = 0; - void *handle = NULL; + int handle = 0; int ret = MM_ERROR_NONE; MMPLAYER_FENTER(); @@ -8799,7 +9027,7 @@ _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_ attrs = MMPLAYER_GET_ATTRS(player); MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL); - mm_attrs_get_data_by_name(attrs, "display_overlay", &handle); + mm_attrs_get_int_by_name(attrs, "display_overlay", &handle); if (!handle) { LOGE("Display handle is NULL, after setting window handle, set video roi area"); return MM_ERROR_PLAYER_INTERNAL; @@ -8811,7 +9039,7 @@ _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_ player->video_roi.scale_height = scale_height; /* check video sinkbin is created */ - if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) + if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) return MM_ERROR_NONE; if (!gst_video_overlay_set_video_roi_area( @@ -8849,6 +9077,93 @@ _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scal return ret; } +int +_mmplayer_set_client_pid(MMHandleType hplayer, int pid) +{ + mmplayer_t *player = (mmplayer_t *)hplayer; + + MMPLAYER_FENTER(); + + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + player->client_pid = pid; + + LOGD("client pid[%d] %p", pid, player); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available) +{ + mmplayer_t *player = (mmplayer_t *)hplayer; + mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT; + enum audio_element_id elem_id = MMPLAYER_A_NUM; + + MMPLAYER_FENTER(); + + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT); + + *available = true; + mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type); + + LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type); + + if (codec_type == MM_PLAYER_CODEC_TYPE_SW) + return MM_ERROR_NONE; + + /* in case of audio codec default type is HW */ + switch(opt) { + case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT: + if (player->ini.support_audio_effect) + return MM_ERROR_NONE; + elem_id = MMPLAYER_A_FILTER; + break; + case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN: + if (player->ini.support_replaygain_control) + return MM_ERROR_NONE; + elem_id = MMPLAYER_A_RGVOL; + break; + case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH: + if (player->ini.support_pitch_control) + return MM_ERROR_NONE; + elem_id = MMPLAYER_A_PITCH; + break; + case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING: + if (player->ini.support_audio_effect) + return MM_ERROR_NONE; + break; + /* default case handling is not required */ + } + + if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) { + LOGW("audio control option [%d] is not available", opt); + *available = false; + } else { + /* setting pcm exporting option is allowed before READY state */ + if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING) + return MM_ERROR_PLAYER_INVALID_STATE; + + /* check whether the audio filter exist or not after READY state, + because the sw codec could be added during auto-plugging in some cases */ + if (!player->pipeline || + !player->pipeline->audiobin || + !player->pipeline->audiobin[elem_id].gst) { + LOGW("there is no audio elem [%d]", elem_id); + *available = false; + } + } + + LOGD("audio control opt %d, available %d", opt, *available); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + static gboolean __mmplayer_update_duration_value(mmplayer_t *player) { @@ -8868,7 +9183,7 @@ __mmplayer_update_duration_value(mmplayer_t *player) } /* update streaming service type */ - player->streaming_type = __mmplayer_get_stream_service_type(player); + player->streaming_type = _mmplayer_get_stream_service_type(player); /* check duration is OK */ if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) @@ -8889,17 +9204,25 @@ __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs) GstPad *pad = NULL; gint samplerate = 0, channels = 0; GstStructure *p = NULL; + GstElement *aconv = NULL; LOGD("try to update audio attrs"); MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE); - pad = gst_element_get_static_pad( - player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink"); + if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) { + aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst; + } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) { + aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst; + } else { + LOGE("there is no audio converter"); + return FALSE; + } + + pad = gst_element_get_static_pad(aconv, "sink"); if (!pad) { - LOGW("failed to get pad from audiosink"); + LOGW("failed to get pad from audio converter"); return FALSE; } @@ -8915,10 +9238,11 @@ __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs) mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate); gst_structure_get_int(p, "rate", &samplerate); - mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate); - gst_structure_get_int(p, "channels", &channels); - mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels); + + mm_player_set_attribute((MMHandleType)player, NULL, + "content_audio_samplerate", samplerate, + "content_audio_channels", channels, NULL); SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels); @@ -8956,17 +9280,17 @@ __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs) } if (!caps_v) { - LOGD("no negitiated caps from videosink"); + LOGD("no negotiated caps from videosink"); gst_object_unref(pad); return FALSE; } p = gst_caps_get_structure(caps_v, 0); gst_structure_get_int(p, "width", &width); - mm_attrs_set_int_by_name(attrs, "content_video_width", width); - gst_structure_get_int(p, "height", &height); - mm_attrs_set_int_by_name(attrs, "content_video_height", height); + + mm_player_set_attribute((MMHandleType)player, NULL, + MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL); gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe); @@ -8976,7 +9300,8 @@ __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs) gst_object_unref(pad); if (tmpDe > 0) { - mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe); + mm_player_set_attribute((MMHandleType)player, NULL, + MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL); SECURE_LOGD("fps : %d", tmpNu / tmpDe); } @@ -8991,7 +9316,7 @@ __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs) 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; @@ -9013,9 +9338,10 @@ __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs) msec_dur = GST_TIME_AS_MSECONDS(player->duration); if (msec_dur > 0) { bitrate = data_size * 8 * 1000 / msec_dur; - SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate); - mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate); - + SECURE_LOGD("file size : %"G_GUINT64_FORMAT + ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate); + mm_player_set_attribute((MMHandleType)player, NULL, + MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL); ret = TRUE; } else { LOGD("player duration is less than 0"); @@ -9024,7 +9350,8 @@ __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs) if (MMPLAYER_IS_RTSP_STREAMING(player)) { if (player->total_bitrate) { - mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate); + mm_player_set_attribute((MMHandleType)player, NULL, + MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL); ret = TRUE; } } @@ -9130,15 +9457,16 @@ __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri) path = (location != NULL) ? (location) : ((char *)uri); - ret = util_exist_file_path(path); + ret = _mmplayer_exist_file_path(path); /* 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 (util_is_sdp_file(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) { @@ -9171,7 +9499,9 @@ __mmplayer_create_stream_from_pad(GstPad *pad) return NULL; } - /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */ +#ifdef __DEBUG__ + MMPLAYER_LOG_GST_CAPS_TYPE(caps); +#endif structure = gst_caps_get_structure(caps, 0); gst_structure_get_int(structure, "width", &width); gst_structure_get_int(structure, "height", &height); @@ -9179,7 +9509,7 @@ __mmplayer_create_stream_from_pad(GstPad *pad) if (string_format) fourcc = _mmplayer_convert_fourcc_string_to_value(string_format); - format = util_get_pixtype(fourcc); + format = _mmplayer_get_pixtype(fourcc); gst_video_info_from_caps(&info, caps); gst_caps_unref(caps); @@ -9207,6 +9537,7 @@ static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem) { unsigned int pitch = 0; + unsigned int size = 0; int index = 0; tbm_surface_h surface = gst_tizen_memory_get_surface(mem); tbm_bo bo = NULL; @@ -9220,9 +9551,12 @@ __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t * } for (index = 0; index < stream->plane_num; index++) { - tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch); + tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch); stream->stride[index] = pitch; - stream->elevation[index] = stream->height; + if (pitch) + stream->elevation[index] = size / pitch; + else + stream->elevation[index] = stream->height; } } @@ -9356,7 +9690,7 @@ __mmplayer_set_pause_state(mmplayer_t *player) return; /* it's first time to update all content attrs. */ - __mmplayer_update_content_attrs(player, ATTR_ALL); + _mmplayer_update_content_attrs(player, ATTR_ALL); } static void @@ -9376,10 +9710,10 @@ __mmplayer_set_playing_state(mmplayer_t *player) /* 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); + _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY); if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) { @@ -9406,10 +9740,9 @@ __mmplayer_set_playing_state(mmplayer_t *player) else audio_codec = "unknown"; - mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec); - - if (mm_attrs_commit_all(player->attrs)) - LOGE("failed to update attributes"); + if (mm_player_set_attribute((MMHandleType)player, NULL, + "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE) + LOGE("failed to set attribute"); LOGD("set audio codec type with caps"); }