X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fmm_player_priv.c;h=df00ea4465c6d2cf9a4c7d2b64db00efc6c369c0;hb=3c4de62cdaa506abec6bc3a1f4f93e588ec6ef3c;hp=e164e2fa242f4076223b33ec1ab2474798219284;hpb=9eef0cad8c097609a5b7cb914837ea70a69279e6;p=platform%2Fcore%2Fmultimedia%2Flibmm-player.git diff --git a/src/mm_player_priv.c b/src/mm_player_priv.c old mode 100755 new mode 100644 index e164e2f..df00ea4 --- a/src/mm_player_priv.c +++ b/src/mm_player_priv.c @@ -27,7 +27,6 @@ ========================================================================================== */ #include #include -#include #include #include #include @@ -36,10 +35,11 @@ #include #include #include +#include #include #include -#include +#include #include "mm_player_priv.h" #include "mm_player_ini.h" @@ -48,9 +48,12 @@ #include "mm_player_utils.h" #include "mm_player_tracks.h" #include "mm_player_360.h" +#include "mm_player_gst.h" #include #include +#include +#include /*=========================================================================================== | | @@ -88,22 +91,10 @@ #define DEFAULT_PLAYBACK_RATE 1.0 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3 -#define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \ - (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \ - (player->ini.http_use_file_buffer) && \ - (player->http_file_buffering_path) && \ - (strlen(player->http_file_buffering_path) > 0)) - #define PLAYER_DISPLAY_MODE_DST_ROI 5 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */ -/* For PD mode */ -#define PLAYER_PD_EXT_MAX_SIZE_BYTE 1024 * 1024 * 3 - -#define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */ -#define PLAYER_BUS_MSG_PREPARE_TIMEOUT 10 - #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */ #define PLAYER_SPHERICAL_DEFAULT_PITCH 0 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120 @@ -112,6 +103,12 @@ #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4" #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video" +#define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */ + +#define DEFAULT_PCM_OUT_FORMAT "F32LE" +#define DEFAULT_PCM_OUT_SAMPLERATE 44100 +#define DEFAULT_PCM_OUT_CHANNEL 2 + /*--------------------------------------------------------------------------- | LOCAL CONSTANT DEFINITIONS: | ---------------------------------------------------------------------------*/ @@ -119,6 +116,13 @@ /*--------------------------------------------------------------------------- | LOCAL DATA TYPE DEFINITIONS: | ---------------------------------------------------------------------------*/ +/* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed + We are defining our own and will be removed when it actually exposed */ +typedef enum { + GST_AUTOPLUG_SELECT_TRY, + GST_AUTOPLUG_SELECT_EXPOSE, + GST_AUTOPLUG_SELECT_SKIP +} GstAutoplugSelectResult; /*--------------------------------------------------------------------------- | GLOBAL VARIABLE DEFINITIONS: | @@ -132,126 +136,77 @@ static sound_stream_info_h stream_info; /*--------------------------------------------------------------------------- | LOCAL FUNCTION PROTOTYPES: | ---------------------------------------------------------------------------*/ -static int __mmplayer_gst_create_pipeline(mm_player_t* player); -static int __mmplayer_gst_destroy_pipeline(mm_player_t* player); -static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type); -static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player); -static int __mmplayer_gst_create_text_pipeline(mm_player_t* player); -static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player); -static int __mmplayer_gst_element_link_bucket(GList* element_bucket); - -static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data); -static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data); -static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data); -static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data); -static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data); -static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data); -static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data); -static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data); +static int __mmplayer_gst_create_pipeline(mmplayer_t *player); +static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player); +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_gst_element_added(GstElement* bin, GstElement* element, gpointer data); -static GstElement * __mmplayer_create_decodebin(mm_player_t* player); -static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps); -static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data); static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data); -static gboolean __mmplayer_is_midi_type(gchar* str_caps); +static gboolean __mmplayer_is_midi_type(gchar *str_caps); static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps); -static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps); - -static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data); -static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data); -static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player); -static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data); -static void __mmplayer_release_misc(mm_player_t* player); -static void __mmplayer_release_misc_post(mm_player_t* player); -static gboolean __mmplayer_init_gstreamer(mm_player_t* player); -static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data); -static void __mmplayer_gst_callback(GstMessage *msg, gpointer data); -static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg); -static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg); -static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink); -static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data); -static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data); -static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data); +static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps); + +static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data); +static void __mmplayer_release_misc(mmplayer_t *player); +static void __mmplayer_release_misc_post(mmplayer_t *player); +static gboolean __mmplayer_init_gstreamer(mmplayer_t *player); +static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data); +static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data); static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data); -static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index); - -static gboolean __mmplayer_check_subtitle(mm_player_t* player); -static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message); -static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms); -static void __mmplayer_cancel_eos_timer(mm_player_t* player); -static gboolean __mmplayer_eos_timer_cb(gpointer u_data); -static int __mmplayer_handle_missed_plugin(mm_player_t* player); -static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime); -static gboolean __mmplayer_configure_audio_callback(mm_player_t* player); -static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink); -static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink); -static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type); -static gpointer __mmplayer_next_play_thread(gpointer data); -static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag); - -static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element); +static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index); + +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_del_sink(mmplayer_t *player, GstElement *sink); +static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type); +static gpointer __mmplayer_gapless_play_thread(gpointer data); +static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element); static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data); static void __mmplayer_release_dump_list(GList *dump_list); - -static int __gst_realize(mm_player_t* player); -static int __gst_unrealize(mm_player_t* player); -static int __gst_start(mm_player_t* player); -static int __gst_stop(mm_player_t* player); -static int __gst_pause(mm_player_t* player, gboolean async); -static int __gst_resume(mm_player_t* player, gboolean async); -static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate, - GstFormat format, GstSeekFlags flags, GstSeekType cur_type, - gint64 cur, GstSeekType stop_type, gint64 stop); -static int __gst_pending_seek(mm_player_t* player); - -static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called); -static int __gst_get_position(mm_player_t* player, int format, unsigned long *position); -static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos); -static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position); -static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param); - -static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event); - -static int __mmplayer_set_pcm_extraction(mm_player_t* player); -static gboolean __mmplayer_can_extract_pcm(mm_player_t* player); +static int __mmplayer_gst_realize(mmplayer_t *player); +static int __mmplayer_gst_unrealize(mmplayer_t *player); +static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position); +static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param); /* util */ -static gboolean __is_ms_buff_src(mm_player_t* player); -static gboolean __has_suffix(mm_player_t * player, const gchar * suffix); - -static int __mmplayer_realize_streaming_ext(mm_player_t* player); -static int __mmplayer_unrealize_streaming_ext(mm_player_t *player); -static int __mmplayer_start_streaming_ext(mm_player_t *player); -static int __mmplayer_destroy_streaming_ext(mm_player_t* player); -static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay); - -static gboolean __mmplayer_verify_next_play_path(mm_player_t *player); -static void __mmplayer_activate_next_source(mm_player_t *player, GstState target); -static void __mmplayer_check_pipeline(mm_player_t* player); -static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type); -static void __mmplayer_deactivate_old_path(mm_player_t *player); - -static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg); -static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name); - -static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player); -static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name); -static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data); -static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data); -static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data); -static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data); -static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data); -static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data); -static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data); -static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data); -static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data); -static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all); -static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer); -static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type); -static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata); +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 gboolean __mmplayer_deactivate_selector(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); +static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs); + +static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type); +static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param); +static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri); + +static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad); +static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem); +static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream); +static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem); + +static void __mmplayer_set_pause_state(mmplayer_t *player); +static void __mmplayer_set_playing_state(mmplayer_t *player); /*=========================================================================================== | | | FUNCTION DEFINITIONS | @@ -260,7 +215,7 @@ static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_ #if 0 //debug static void -print_tag(const GstTagList * list, const gchar * tag, gpointer unused) +print_tag(const GstTagList *list, const gchar *tag, gpointer unused) { gint i, count; @@ -274,13 +229,14 @@ print_tag(const GstTagList * list, const gchar * tag, gpointer unused) 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 + } else { str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i)); + } if (i == 0) - g_print(" %15s: %s\n", gst_tag_get_nick(tag), str); + g_print(" %15s: %s", gst_tag_get_nick(tag), str); else - g_print(" : %s\n", str); + g_print(" : %s", str); g_free(str); } @@ -290,7 +246,7 @@ print_tag(const GstTagList * list, const gchar * tag, gpointer unused) /* This function should be called after the pipeline goes PAUSED or higher state. */ gboolean -_mmplayer_update_content_attrs(mm_player_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; @@ -298,11 +254,7 @@ _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) static gboolean has_bitrate = FALSE; gboolean missing_only = FALSE; gboolean all = FALSE; - gint64 dur_nsec = 0; - GstStructure* p = NULL; MMHandleType attrs = 0; - gchar *path = NULL; - struct stat sb; MMPLAYER_FENTER(); @@ -344,178 +296,21 @@ _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) missing_only = FALSE; } - if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) { - LOGD("try to update duration"); - has_duration = FALSE; - - if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) { - player->duration = dur_nsec; - LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec)); - } - - if (player->duration < 0) { - LOGW("duration : %lld is Non-Initialized !!! \n", player->duration); - player->duration = 0; - } - - /* update streaming service type */ - player->streaming_type = __mmplayer_get_stream_service_type(player); - - /* check duration is OK */ - if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) { - /* FIXIT : find another way to get duration here. */ - LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!"); - } else { - /*update duration */ - mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec)); - has_duration = TRUE; - } - } - - if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) { - /* update audio params - NOTE : We need original audio params and it can be only obtained from src pad of audio - decoder. Below code only valid when we are not using 'resampler' just before - 'audioconverter'. */ - - LOGD("try to update audio attrs"); - has_audio_attrs = FALSE; - - if (player->pipeline->audiobin && - player->pipeline->audiobin[MMPLAYER_A_SINK].gst) { - GstCaps *caps_a = NULL; - GstPad* pad = NULL; - gint samplerate = 0, channels = 0; - - pad = gst_element_get_static_pad( - player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink"); - - if (pad) { - caps_a = gst_pad_get_current_caps(pad); - - if (caps_a) { - p = gst_caps_get_structure(caps_a, 0); - - 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); - - SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels); - - gst_caps_unref(caps_a); - caps_a = NULL; - - has_audio_attrs = TRUE; - } else - LOGW("not ready to get audio caps"); - - gst_object_unref(pad); - } else - LOGW("failed to get pad from audiosink"); - } - } - - if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) { - LOGD("try to update video attrs"); - has_video_attrs = FALSE; - - if (player->pipeline->videobin && - player->pipeline->videobin[MMPLAYER_V_SINK].gst) { - GstCaps *caps_v = NULL; - GstPad* pad = NULL; - gint tmpNu, tmpDe; - gint width, height; - - pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink"); - if (pad) { - caps_v = gst_pad_get_current_caps(pad); - - /* Use v_stream_caps, if fail to get video_sink sink pad*/ - if (!caps_v && player->v_stream_caps) { - caps_v = player->v_stream_caps; - gst_caps_ref(caps_v); - } - - if (caps_v) { - 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); - - gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe); - - SECURE_LOGD("width : %d height : %d", width, height); - - gst_caps_unref(caps_v); - caps_v = NULL; - - if (tmpDe > 0) { - mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe); - SECURE_LOGD("fps : %d", tmpNu / tmpDe); - } - - has_video_attrs = TRUE; - } else - LOGD("no negitiated caps from videosink"); - gst_object_unref(pad); - pad = NULL; - } else - LOGD("no videosink sink pad"); - } - } - - - if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) { - has_bitrate = FALSE; - - /* FIXIT : please make it clear the dependancy with duration/codec/uritype */ - if (player->duration) { - guint64 data_size = 0; - - if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) { - mm_attrs_get_string_by_name(attrs, "profile_uri", &path); - - if (stat(path, &sb) == 0) - data_size = (guint64)sb.st_size; - } else if (MMPLAYER_IS_HTTP_STREAMING(player)) { - data_size = player->http_content_size; - } - LOGD("try to update bitrate : data_size = %lld", data_size); - - if (data_size) { - guint64 bitrate = 0; - guint64 msec_dur = 0; + if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) + has_duration = __mmplayer_update_duration_value(player); - msec_dur = GST_TIME_AS_MSECONDS(player->duration); - if (msec_dur > 0) { - bitrate = data_size * 8 * 1000 / msec_dur; - SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate); - mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate); + if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) + has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs); - has_bitrate = TRUE; - } else { - LOGD("player duration is less than 0"); - } - } + if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) + has_video_attrs = __mmplayer_update_video_attrs(player, attrs); - if (MMPLAYER_IS_RTSP_STREAMING(player)) { - if (player->total_bitrate) { - mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate); - has_bitrate = TRUE; - } - } - } - } + if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) + has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs); /* validate all */ - if (mmf_attrs_commit(attrs)) { - LOGE("failed to update attributes\n"); + if (mm_attrs_commit_all(attrs)) { + LOGE("failed to update attributes"); return FALSE; } @@ -524,7 +319,8 @@ _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) return TRUE; } -static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player) +MMStreamingType +__mmplayer_get_stream_service_type(mmplayer_t *player) { MMStreamingType streaming_type = STREAMING_SERVICE_NONE; @@ -540,9 +336,8 @@ static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player) if (!MMPLAYER_IS_STREAMING(player)) return STREAMING_SERVICE_NONE; - if (MMPLAYER_IS_HTTP_STREAMING(player)) - streaming_type = (player->duration == 0) ? - STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD; + streaming_type = (player->duration == 0) ? + STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD; switch (streaming_type) { case STREAMING_SERVICE_LIVE: @@ -561,22 +356,20 @@ static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player) return streaming_type; } - /* this function sets the player state and also report * it to applicaton by calling callback function */ -int -__mmplayer_set_state(mm_player_t* player, int state) +void +__mmplayer_set_state(mmplayer_t *player, int state) { MMMessageParamType msg = {0, }; - gboolean post_bos = FALSE; - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); + MMPLAYER_RETURN_IF_FAIL(player); if (MMPLAYER_CURRENT_STATE(player) == state) { - LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state)); + LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state)); MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; - return MM_ERROR_NONE; + return; } /* update player states */ @@ -593,83 +386,15 @@ __mmplayer_set_state(mm_player_t* player, int state) case MM_PLAYER_STATE_NULL: case MM_PLAYER_STATE_READY: break; - case MM_PLAYER_STATE_PAUSED: - { - if (!player->sent_bos) { - /* rtsp case, get content attrs by GstMessage */ - if (!MMPLAYER_IS_RTSP_STREAMING(player)) { - /* it's first time to update all content attrs. */ - _mmplayer_update_content_attrs(player, ATTR_ALL); - } - } - - /* add audio callback probe if condition is satisfied */ - if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex) - __mmplayer_configure_audio_callback(player); - - /* FIXIT : handle return value */ - } + __mmplayer_set_pause_state(player); break; - case MM_PLAYER_STATE_PLAYING: - { - /* try to get content metadata */ - if (!player->sent_bos) { - /* 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 - * legacy mmfw-player api */ - _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY); - } - - if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) { - if (!player->sent_bos) - __mmplayer_handle_missed_plugin(player); - } - - if (player->resumed_by_rewind && player->playback_rate < 0.0) { - /* initialize because auto resume is done well. */ - player->resumed_by_rewind = FALSE; - player->playback_rate = 1.0; - } - - if (!player->sent_bos) { - /* check audio codec field is set or not - * we can get it from typefinder or codec's caps. - */ - gchar *audio_codec = NULL; - mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec); - - /* The codec format can't be sent for audio only case like amr, mid etc. - * Because, parser don't make related TAG. - * So, if it's not set yet, fill it with found data. - */ - if (!audio_codec) { - if (g_strrstr(player->type, "audio/midi")) - audio_codec = g_strdup("MIDI"); - else if (g_strrstr(player->type, "audio/x-amr")) - audio_codec = g_strdup("AMR"); - else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1")) - audio_codec = g_strdup("AAC"); - else - audio_codec = g_strdup("unknown"); - mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec); - - MMPLAYER_FREEIF(audio_codec); - if (mmf_attrs_commit(player->attrs)) - LOGE("failed to update attributes\n"); - - LOGD("set audio codec type with caps\n"); - } - - post_bos = TRUE; - } - } + __mmplayer_set_playing_state(player); break; - case MM_PLAYER_STATE_NONE: default: - LOGW("invalid target state, there is nothing to do.\n"); + LOGW("invalid target state, there is nothing to do."); break; } @@ -684,293 +409,264 @@ __mmplayer_set_state(mm_player_t* player, int state) LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player))); /* state changed by resource callback */ - if (player->interrupted_by_resource) { - msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT; + if (player->interrupted_by_resource) MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg); - } else { /* state changed by usecase */ + else /* state changed by usecase */ MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg); - } + } else { - LOGD("intermediate state, do nothing.\n"); + LOGD("intermediate state, do nothing."); MMPLAYER_PRINT_STATE(player); - return MM_ERROR_NONE; + return; } - if (post_bos) { + if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING + && !player->sent_bos) { MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL); player->sent_bos = TRUE; } - return MM_ERROR_NONE; + return; } -static gpointer __mmplayer_next_play_thread(gpointer data) +int +__mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command) { - mm_player_t* player = (mm_player_t*) data; - MMPlayerGstElement *mainbin = NULL; - - MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL); + mmplayer_state_e current_state = MM_PLAYER_STATE_NUM; + mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM; - MMPLAYER_NEXT_PLAY_THREAD_LOCK(player); - while (!player->next_play_thread_exit) { - LOGD("next play thread started. waiting for signal.\n"); - MMPLAYER_NEXT_PLAY_THREAD_WAIT(player); + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - LOGD("reconfigure pipeline for gapless play.\n"); + //LOGD("incomming command : %d ", command); - if (player->next_play_thread_exit) { - if (player->gapless.reconfigure) { - player->gapless.reconfigure = false; - MMPLAYER_PLAYBACK_UNLOCK(player); - } - LOGD("exiting gapless play thread\n"); - break; - } + current_state = MMPLAYER_CURRENT_STATE(player); + pending_state = MMPLAYER_PENDING_STATE(player); - mainbin = player->pipeline->mainbin; + MMPLAYER_PRINT_STATE(player); - MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER); - MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX); - MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); - MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND); - MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC); + switch (command) { + case MMPLAYER_COMMAND_CREATE: + { + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL; - __mmplayer_activate_next_source(player, GST_STATE_PLAYING); + if (current_state == MM_PLAYER_STATE_NULL || + current_state == MM_PLAYER_STATE_READY || + current_state == MM_PLAYER_STATE_PAUSED || + current_state == MM_PLAYER_STATE_PLAYING) + goto NO_OP; } - MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player); + break; - return NULL; -} + case MMPLAYER_COMMAND_DESTROY: + { + /* destroy can called anytime */ -static void -__mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg) -{ - MMHandleType attrs = 0; - guint64 data_size = 0; - gchar* path = NULL; - unsigned long pos_msec = 0; - struct stat sb; + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE; + } + break; - MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); + case MMPLAYER_COMMAND_REALIZE: + { + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY; - __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position + if (pending_state != MM_PLAYER_STATE_NONE) { + goto INVALID_STATE; + } else { + /* need ready state to realize */ + if (current_state == MM_PLAYER_STATE_READY) + goto NO_OP; - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("fail to get attributes.\n"); - return; + if (current_state != MM_PLAYER_STATE_NULL) + goto INVALID_STATE; + } } + break; - if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) { - mm_attrs_get_string_by_name(attrs, "profile_uri", &path); + case MMPLAYER_COMMAND_UNREALIZE: + { + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL; - if (stat(path, &sb) == 0) - data_size = (guint64)sb.st_size; - } else if (MMPLAYER_IS_HTTP_STREAMING(player)) - data_size = player->http_content_size; + if (current_state == MM_PLAYER_STATE_NULL) + goto NO_OP; + } + break; - __mm_player_streaming_buffering(player->streamer, - buffering_msg, - data_size, - player->last_position, - player->duration); + case MMPLAYER_COMMAND_START: + { + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING; - __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst); + if (pending_state == MM_PLAYER_STATE_NONE) { + if (current_state == MM_PLAYER_STATE_PLAYING) + goto NO_OP; + else if (current_state != MM_PLAYER_STATE_READY && + current_state != MM_PLAYER_STATE_PAUSED) + goto INVALID_STATE; + } else if (pending_state == MM_PLAYER_STATE_PLAYING) { + goto ALREADY_GOING; + } else if (pending_state == MM_PLAYER_STATE_PAUSED) { + LOGD("player is going to paused state, just change the pending state as playing"); + } else { + goto INVALID_STATE; + } + } + break; - return; -} + case MMPLAYER_COMMAND_STOP: + { + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY; -static int -__mmplayer_handle_buffering_message(mm_player_t* player) -{ - int ret = MM_ERROR_NONE; - MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE; - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - MMPlayerStateType target_state = MM_PLAYER_STATE_NONE; - MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE; + if (current_state == MM_PLAYER_STATE_READY) + goto NO_OP; - if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) { - LOGW("do nothing for buffering msg\n"); - ret = MM_ERROR_PLAYER_INVALID_STATE; - goto exit; + /* need playing/paused state to stop */ + if (current_state != MM_PLAYER_STATE_PLAYING && + current_state != MM_PLAYER_STATE_PAUSED) + goto INVALID_STATE; } + break; - prev_state = MMPLAYER_PREV_STATE(player); - current_state = MMPLAYER_CURRENT_STATE(player); - target_state = MMPLAYER_TARGET_STATE(player); - pending_state = MMPLAYER_PENDING_STATE(player); + case MMPLAYER_COMMAND_PAUSE: + { + if (MMPLAYER_IS_LIVE_STREAMING(player)) + goto NO_OP; - LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d", - MMPLAYER_STATE_GET_NAME(prev_state), - MMPLAYER_STATE_GET_NAME(current_state), - MMPLAYER_STATE_GET_NAME(pending_state), - MMPLAYER_STATE_GET_NAME(target_state), - player->streamer->is_buffering); - - if (!player->streamer->is_buffering) { - /* NOTE : if buffering has done, player has to go to target state. */ - switch (target_state) { - case MM_PLAYER_STATE_PAUSED: - { - switch (pending_state) { - case MM_PLAYER_STATE_PLAYING: - __gst_pause(player, TRUE); - break; - - case MM_PLAYER_STATE_PAUSED: - LOGD("player is already going to paused state, there is nothing to do.\n"); - break; - - case MM_PLAYER_STATE_NONE: - case MM_PLAYER_STATE_NULL: - case MM_PLAYER_STATE_READY: - default: - LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state)); - break; - } - } - break; + if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) + goto NOT_COMPLETED_SEEK; - case MM_PLAYER_STATE_PLAYING: - { - switch (pending_state) { - case MM_PLAYER_STATE_NONE: - { - if (current_state != MM_PLAYER_STATE_PLAYING) - __gst_resume(player, TRUE); - } - break; - - case MM_PLAYER_STATE_PAUSED: - /* NOTE: It should be worked as asynchronously. - * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly. - */ - if (current_state == MM_PLAYER_STATE_PLAYING) { - /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet. - * The current state should be changed to paused purposely to prevent state conflict. - */ - MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED); - } - __gst_resume(player, TRUE); - break; - - case MM_PLAYER_STATE_PLAYING: - LOGD("player is already going to playing state, there is nothing to do.\n"); - break; - - case MM_PLAYER_STATE_NULL: - case MM_PLAYER_STATE_READY: - default: - LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state)); - break; - } - } - break; + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED; - case MM_PLAYER_STATE_NULL: - case MM_PLAYER_STATE_READY: - case MM_PLAYER_STATE_NONE: - default: - LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state)); - break; + 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 + goto INVALID_STATE; + } else if (pending_state == MM_PLAYER_STATE_PAUSED) { + goto ALREADY_GOING; + } else if (pending_state == MM_PLAYER_STATE_PLAYING) { + if (current_state == MM_PLAYER_STATE_PAUSED) + LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED"); + else + goto INVALID_STATE; } - } else { - /* NOTE : during the buffering, pause the player for stopping pipeline clock. - * it's for stopping the pipeline clock to prevent dropping the data in sink element. - */ - switch (pending_state) { - case MM_PLAYER_STATE_NONE: - { - if (current_state != MM_PLAYER_STATE_PAUSED) { - /* rtsp streaming pause makes rtsp server stop sending data. */ - if (!MMPLAYER_IS_RTSP_STREAMING(player)) { - LOGD("set pause state during buffering\n"); - __gst_pause(player, TRUE); - } - } - } - break; + } + break; - case MM_PLAYER_STATE_PLAYING: - /* rtsp streaming pause makes rtsp server stop sending data. */ - if (!MMPLAYER_IS_RTSP_STREAMING(player)) - __gst_pause(player, TRUE); - break; + case MMPLAYER_COMMAND_RESUME: + { + if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) + goto NOT_COMPLETED_SEEK; - case MM_PLAYER_STATE_PAUSED: - break; + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING; - case MM_PLAYER_STATE_NULL: - case MM_PLAYER_STATE_READY: - default: - LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state)); - break; + if (pending_state == MM_PLAYER_STATE_NONE) { + if (current_state == MM_PLAYER_STATE_PLAYING) + goto NO_OP; + else if (current_state != MM_PLAYER_STATE_PAUSED) + goto INVALID_STATE; + } else if (pending_state == MM_PLAYER_STATE_PLAYING) { + goto ALREADY_GOING; + } else if (pending_state == MM_PLAYER_STATE_PAUSED) { + LOGD("player is going to paused state, just change the pending state as playing"); + } else { + goto INVALID_STATE; } } + break; -exit: - return ret; -} + default: + break; + } + player->cmd = command; -static void -__mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop) -{ - MMPlayerGstElement *textbin; - MMPLAYER_FENTER(); + return MM_ERROR_NONE; - MMPLAYER_RETURN_IF_FAIL(player && - player->pipeline && - player->pipeline->textbin); +INVALID_STATE: + LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)", + MMPLAYER_STATE_GET_NAME(current_state), command); + return MM_ERROR_PLAYER_INVALID_STATE; - MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst); +NOT_COMPLETED_SEEK: + LOGW("not completed seek"); + return MM_ERROR_PLAYER_DOING_SEEK; - textbin = player->pipeline->textbin; +NO_OP: + LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state)); + return MM_ERROR_PLAYER_NO_OP; - if (is_drop) { - LOGD("Drop subtitle text after getting EOS\n"); +ALREADY_GOING: + LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state)); + return MM_ERROR_PLAYER_NO_OP; +} - g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL); - g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL); +static gpointer +__mmplayer_gapless_play_thread(gpointer data) +{ + mmplayer_t *player = (mmplayer_t *)data; + mmplayer_gst_element_t *mainbin = NULL; - player->is_subtitle_force_drop = TRUE; - } else { - if (player->is_subtitle_force_drop == TRUE) { - LOGD("Enable subtitle data path without drop\n"); + MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL); - g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL); - g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL); + MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player); + while (!player->gapless_play_thread_exit) { + LOGD("gapless play thread started. waiting for signal."); + MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player); - LOGD("non-connected with external display"); + LOGD("reconfigure pipeline for gapless play."); - player->is_subtitle_force_drop = FALSE; + if (player->gapless_play_thread_exit) { + if (player->gapless.reconfigure) { + player->gapless.reconfigure = false; + MMPLAYER_PLAYBACK_UNLOCK(player); + } + LOGD("exiting gapless play thread"); + break; } + + mainbin = player->pipeline->mainbin; + + MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER); + MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX); + MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); + MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND); + MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC); + + __mmplayer_activate_next_source(player, GST_STATE_PLAYING); } + MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player); + + return NULL; } -static VariantData * -__mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data) +static void +__mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id) { - VariantData *var_info = NULL; - g_return_val_if_fail(self != NULL, NULL); + GSource *source = NULL; + + MMPLAYER_FENTER(); + + source = g_main_context_find_source_by_id(context, source_id); + if (source != NULL) { + LOGW("context: %p, source id: %d, source: %p", context, source_id, source); + g_source_destroy(source); + } - var_info = g_new0(VariantData, 1); - if (!var_info) return NULL; - var_info->bandwidth = self->bandwidth; - var_info->width = self->width; - var_info->height = self->height; - return var_info; + MMPLAYER_FLEAVE(); } -void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer) +void +__mmplayer_bus_msg_thread_destroy(MMHandleType hplayer) { - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; GstMessage *msg = NULL; GQueue *queue = NULL; MMPLAYER_FENTER(); MMPLAYER_RETURN_IF_FAIL(player); - player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT; + /* disconnecting bus watch */ + if (player->bus_watcher) + __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher); + player->bus_watcher = 0; /* destroy the gst bus msg thread */ if (player->bus_msg_thread) { @@ -991,6 +687,10 @@ void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer) queue = player->bus_msg_q; while (!g_queue_is_empty(queue)) { msg = (GstMessage *)g_queue_pop_head(queue); + if (!msg) { + LOGW("msg is null"); + continue; + } LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg)); gst_message_unref(msg); } @@ -999,7102 +699,3725 @@ void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer) MMPLAYER_FLEAVE(); } -gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data) +gboolean +__mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink) { - mm_player_t *player = (mm_player_t *) data; + GstElement *parent = NULL; - g_return_val_if_fail(player, FALSE); - g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE); - - gst_message_ref(msg); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE); + MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE); - g_mutex_lock(&player->bus_msg_q_lock); - g_queue_push_tail(player->bus_msg_q, msg); - g_mutex_unlock(&player->bus_msg_q_lock); + /* lock */ + MMPLAYER_FSINK_LOCK(player); - MMPLAYER_BUS_MSG_THREAD_LOCK(player); - MMPLAYER_BUS_MSG_THREAD_SIGNAL(player); - MMPLAYER_BUS_MSG_THREAD_UNLOCK(player); - return TRUE; -} + /* get parent of fakesink */ + parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst); + if (!parent) { + LOGD("fakesink already removed"); + goto ERROR; + } -static gpointer __mmplayer_gst_bus_msg_thread(gpointer data) -{ - mm_player_t *player = (mm_player_t*)(data); - GstMessage *msg = NULL; - GstBus *bus = NULL; + gst_element_set_locked_state(fakesink->gst, TRUE); - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player && - player->pipeline && - player->pipeline->mainbin && - player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, - NULL); + /* setting the state to NULL never returns async + * so no need to wait for completion of state transiton + */ + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL)) + LOGE("fakesink state change failure!"); + /* FIXIT : should I return here? or try to proceed to next? */ + /* return FALSE; */ - bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)); - if (!bus) { - LOGE("cannot get BUS from the pipeline"); - return NULL; - } + /* remove fakesink from it's parent */ + if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) { + LOGE("failed to remove fakesink"); - MMPLAYER_BUS_MSG_THREAD_LOCK(player); + gst_object_unref(parent); - LOGD("[handle: %p] gst bus msg thread will be started.", player); - while (!player->bus_msg_thread_exit) { - g_mutex_lock(&player->bus_msg_q_lock); - msg = g_queue_pop_head(player->bus_msg_q); - g_mutex_unlock(&player->bus_msg_q_lock); - if (msg == NULL) { - MMPLAYER_BUS_MSG_THREAD_WAIT(player); - continue; - } - MMPLAYER_BUS_MSG_THREAD_UNLOCK(player); - /* handle the gst msg */ - __mmplayer_gst_callback(msg, player); - MMPLAYER_BUS_MSG_THREAD_LOCK(player); - gst_message_unref(msg); + goto ERROR; } - MMPLAYER_BUS_MSG_THREAD_UNLOCK(player); - gst_object_unref(GST_OBJECT(bus)); - - MMPLAYER_FLEAVE(); - return NULL; -} + gst_object_unref(parent); -static void -__mmplayer_gst_callback(GstMessage *msg, gpointer data) -{ - mm_player_t* player = (mm_player_t*)(data); - static gboolean async_done = FALSE; + LOGD("state-holder removed"); - MMPLAYER_RETURN_IF_FAIL(player); - MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg)); + gst_element_set_locked_state(fakesink->gst, FALSE); - switch (GST_MESSAGE_TYPE(msg)) { - case GST_MESSAGE_UNKNOWN: - LOGD("unknown message received\n"); - break; + MMPLAYER_FSINK_UNLOCK(player); + return TRUE; - case GST_MESSAGE_EOS: - { - MMHandleType attrs = 0; - gint count = 0; +ERROR: + if (fakesink->gst) + gst_element_set_locked_state(fakesink->gst, FALSE); - LOGD("GST_MESSAGE_EOS received\n"); + MMPLAYER_FSINK_UNLOCK(player); + return FALSE; +} - /* NOTE : EOS event is comming multiple time. watch out it */ - /* check state. we only process EOS when pipeline state goes to PLAYING */ - if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) { - LOGD("EOS received on non-playing state. ignoring it\n"); - break; - } +static GstPadProbeReturn +__mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data) +{ + LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad)); + return GST_PAD_PROBE_OK; +} - if (player->pipeline) { - if (player->pipeline->textbin) - __mmplayer_drop_subtitle(player, TRUE); +static void +__mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type) +{ + gint64 stop_running_time = 0; + gint64 position_running_time = 0; + gint64 position = 0; + gint idx = 0; - if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) { - GstPad *pad = NULL; + 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); */ + continue; + } - pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink"); + if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) { + stop_running_time = + gst_segment_to_running_time(&player->gapless.segment[idx], + GST_FORMAT_TIME, player->gapless.segment[idx].stop); + } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) { + stop_running_time = + gst_segment_to_running_time(&player->gapless.segment[idx], + GST_FORMAT_TIME, player->gapless.segment[idx].duration); + } else { + LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration)); + stop_running_time = + gst_segment_to_running_time(&player->gapless.segment[idx], + GST_FORMAT_TIME, player->duration); + } - LOGD("release audio callback\n"); + position_running_time = + gst_segment_to_running_time(&player->gapless.segment[idx], + GST_FORMAT_TIME, player->gapless.segment[idx].position); - /* release audio callback */ - gst_pad_remove_probe(pad, player->audio_cb_probe_id); - player->audio_cb_probe_id = 0; - /* audio callback should be free because it can be called even though probe remove.*/ - player->audio_stream_cb = NULL; - player->audio_stream_cb_user_param = NULL; + LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %" + GST_TIME_FORMAT" , %" GST_TIME_FORMAT, + idx, + GST_TIME_ARGS(stop_running_time), + GST_TIME_ARGS(position_running_time), + GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx], + GST_FORMAT_TIME, player->gapless.segment[idx].start))); - } - } - if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync)) - __mmplayer_audio_stream_clear_buffer(player, TRUE); + position_running_time = MAX(position_running_time, stop_running_time); + position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx], + GST_FORMAT_TIME, player->gapless.segment[idx].start); + position_running_time = MAX(0, position_running_time); + position = MAX(position, position_running_time); + } - /* rewind if repeat count is greater then zero */ - /* get play count */ - attrs = MMPLAYER_GET_ATTRS(player); + if (position != 0) { + LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT, + stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]), + GST_TIME_ARGS(player->gapless.start_time[stream_type] + position)); - if (attrs) { - mm_attrs_get_int_by_name(attrs, "profile_play_count", &count); + player->gapless.start_time[stream_type] += position; + } - LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate); + return; +} - if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ { - if (player->playback_rate < 0.0) { - player->resumed_by_rewind = TRUE; - _mmplayer_set_mute((MMHandleType)player, 0); - MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL); - } +static GstPadProbeReturn +__mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data) +{ + GstPadProbeReturn ret = GST_PAD_PROBE_OK; + GstEvent *event = GST_PAD_PROBE_INFO_DATA(info); + mmplayer_t *player = (mmplayer_t *)data; + GstCaps *caps = NULL; + GstStructure *str = NULL; + const gchar *name = NULL; + 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) { + return ret; + } - __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat); + MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret); + if (!caps_ret) + goto ERROR; - /* initialize */ - player->sent_bos = FALSE; + if (strstr(name, "audio")) { + stream_type = MM_PLAYER_TRACK_TYPE_AUDIO; + } else if (strstr(name, "video")) { + stream_type = MM_PLAYER_TRACK_TYPE_VIDEO; + } else { + /* text track is not supportable */ + LOGE("invalid name %s", name); + goto ERROR; + } - /* not posting eos when repeating */ - break; - } + switch (GST_EVENT_TYPE(event)) { + case GST_EVENT_EOS: + { + /* in case of gapless, drop eos event not to send it to sink */ + if (player->gapless.reconfigure && !player->msg_posted) { + LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad)); + ret = GST_PAD_PROBE_DROP; } - - if (player->pipeline) - MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos"); - - /* post eos message to application */ - __mmplayer_handle_eos_delay(player, player->ini.eos_delay); - - /* reset last position */ - player->last_position = 0; + break; } - break; - - case GST_MESSAGE_ERROR: + case GST_EVENT_STREAM_START: { - GError *error = NULL; - gchar* debug = NULL; - - /* generating debug info before returning error */ - MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error"); - - /* get error code */ - gst_message_parse_error(msg, &error, &debug); - - if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) { - /* Note : the streaming error from the streaming source is handled - * using __mmplayer_handle_streaming_error. - */ - __mmplayer_handle_streaming_error(player, msg); - - /* dump state of all element */ - __mmplayer_dump_pipeline_state(player); - } else { - /* traslate gst error code to msl error code. then post it - * to application if needed - */ - __mmplayer_handle_gst_error(player, msg, error); + __mmplayer_gst_selector_update_start_time(player, stream_type); + break; + } + case GST_EVENT_FLUSH_STOP: + { + LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type); + gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED); + player->gapless.start_time[stream_type] = 0; + break; + } + case GST_EVENT_SEGMENT: + { + GstSegment segment; + GstEvent *tmpev; - if (debug) - LOGE("error debug : %s", debug); - } + LOGD("[%d] GST_EVENT_SEGMENT", stream_type); + gst_event_copy_segment(event, &segment); - if (MMPLAYER_IS_HTTP_PD(player)) - _mmplayer_unrealize_pd_downloader((MMHandleType)player); + if (segment.format != GST_FORMAT_TIME) + break; - MMPLAYER_FREEIF(debug); - g_error_free(error); - } - break; + LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT + ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT + ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT, + GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset), + GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop), + GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration)); - case GST_MESSAGE_WARNING: - { - char* debug = NULL; - GError* error = NULL; + /* keep the all the segment ev to cover the seeking */ + gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]); + player->gapless.update_segment[stream_type] = TRUE; - gst_message_parse_warning(msg, &error, &debug); + if (!player->gapless.running) + break; - LOGD("warning : %s\n", error->message); - LOGD("debug : %s\n", debug); + player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type]; - MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL); + LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base)); - MMPLAYER_FREEIF(debug); - g_error_free(error); - } - break; + tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]); + gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event)); + gst_event_unref(event); + GST_PAD_PROBE_INFO_DATA(info) = tmpev; - case GST_MESSAGE_TAG: - { - LOGD("GST_MESSAGE_TAG\n"); - if (!__mmplayer_gst_extract_tag_from_msg(player, msg)) - LOGW("failed to extract tags from gstmessage\n"); + break; } - break; - - case GST_MESSAGE_BUFFERING: + case GST_EVENT_QOS: { - MMMessageParamType msg_param = {0, }; - int bRet = MM_ERROR_NONE; + gdouble proportion = 0.0; + GstClockTimeDiff diff = 0; + GstClockTime timestamp = 0; + gint64 running_time_diff = -1; + GstQOSType type = 0; + GstEvent *tmpev = NULL; - if (!(player->pipeline && player->pipeline->mainbin)) { - LOGE("player pipeline handle is null"); - break; - } + running_time_diff = player->gapless.segment[stream_type].base; - if (!MMPLAYER_IS_STREAMING(player)) + if (running_time_diff <= 0) /* don't need to adjust */ break; - if (player->pd_mode == MM_PLAYER_PD_MODE_URI) { - if (!MMPLAYER_CMD_TRYLOCK(player)) { - /* skip the playback control by buffering msg while user request is handled. */ - gint per = 0; - - LOGW("[PD mode] can't get cmd lock, only post buffering msg"); - - gst_message_parse_buffering(msg, &per); - LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per); + gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp); + gst_event_unref(event); - msg_param.connection.buffering = per; - MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param); - break; - } - } else { - MMPLAYER_CMD_LOCK(player); + if (timestamp < running_time_diff) { + LOGW("QOS event from previous group"); + ret = GST_PAD_PROBE_DROP; + break; } - /* ignore the prev buffering message */ - if ((player->streamer) && (player->streamer->is_buffering == FALSE) - && (player->streamer->is_buffering_done == TRUE)) { - gint buffer_percent = 0; + 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)); - gst_message_parse_buffering(msg, &buffer_percent); + timestamp -= running_time_diff; - if (buffer_percent == MAX_BUFFER_PERCENT) { - LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent); - player->streamer->is_buffering_done = FALSE; - } - MMPLAYER_CMD_UNLOCK(player); + /* That case is invalid for QoS events */ + if (diff < 0 && -diff > timestamp) { + LOGW("QOS event from previous group"); + ret = GST_PAD_PROBE_DROP; break; } - __mmplayer_update_buffer_setting(player, msg); - - bRet = __mmplayer_handle_buffering_message(player); - - if (bRet == MM_ERROR_NONE) { - msg_param.connection.buffering = player->streamer->buffering_percent; - MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param); + tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp); + GST_PAD_PROBE_INFO_DATA(info) = tmpev; - if (MMPLAYER_IS_RTSP_STREAMING(player) && - player->pending_resume && - (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) { + break; + } + default: + break; + } - player->is_external_subtitle_added_now = FALSE; - player->pending_resume = FALSE; - _mmplayer_resume((MMHandleType)player); - } +ERROR: + if (caps) + gst_caps_unref(caps); + return ret; +} - if (MMPLAYER_IS_RTSP_STREAMING(player) && - (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) { +/* create fakesink for audio or video path witout audiobin or videobin */ +static void +__mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name) +{ + GstElement *pipeline = NULL; + GstElement *fakesink = NULL; + GstPad *sinkpad = NULL; - if (player->doing_seek) { - if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) { - player->doing_seek = FALSE; - MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); - } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) { - async_done = TRUE; - } - } - } - } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) { - if (!player->streamer) { - LOGW("player->streamer is NULL, so discarding the buffering percent update\n"); - MMPLAYER_CMD_UNLOCK(player); - break; - } + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); - if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) { + pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst; - LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n", - GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent); + /* fake sink */ + fakesink = gst_element_factory_make("fakesink", NULL); + if (fakesink == NULL) { + LOGE("failed to create fakesink"); + goto EXIT; + } - if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) { - msg_param.connection.buffering = player->streamer->buffering_percent; - MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param); - } else { - LOGD("Not updating Buffering Message for Live RTSP case !!!\n"); - } - } else { - msg_param.connection.buffering = player->streamer->buffering_percent; - MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param); - } - } - MMPLAYER_CMD_UNLOCK(player); - } - break; + /* store it as it's sink element */ + __mmplayer_add_sink(player, fakesink); - case GST_MESSAGE_STATE_CHANGED: - { - MMPlayerGstElement *mainbin; - const GValue *voldstate, *vnewstate, *vpending; - GstState oldstate = GST_STATE_NULL; - GstState newstate = GST_STATE_NULL; - GstState pending = GST_STATE_NULL; - - if (!(player->pipeline && player->pipeline->mainbin)) { - LOGE("player pipeline handle is null"); - break; - } + gst_bin_add(GST_BIN(pipeline), fakesink); - mainbin = player->pipeline->mainbin; + /* link */ + sinkpad = gst_element_get_static_pad(fakesink, "sink"); - /* we only handle messages from pipeline */ - if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst) - break; + LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad)); - /* get state info from msg */ - voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state"); - vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state"); - vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state"); + if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) { + LOGE("failed to link fakesink"); + gst_object_unref(GST_OBJECT(fakesink)); + goto EXIT; + } - if (!voldstate || !vnewstate) { - LOGE("received msg has wrong format."); - break; - } + if (strstr(name, "video")) { + if (player->v_stream_caps) { + gst_caps_unref(player->v_stream_caps); + player->v_stream_caps = NULL; + } + if (player->ini.set_dump_element_flag) + __mmplayer_add_dump_buffer_probe(player, fakesink); + } - oldstate = (GstState)voldstate->data[0].v_int; - newstate = (GstState)vnewstate->data[0].v_int; - if (vpending) - pending = (GstState)vpending->data[0].v_int; + g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL); + gst_element_set_state(fakesink, GST_STATE_PAUSED); - LOGD("state changed [%s] : %s ---> %s final : %s\n", - GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), - gst_element_state_get_name((GstState)oldstate), - gst_element_state_get_name((GstState)newstate), - gst_element_state_get_name((GstState)pending)); +EXIT: + if (sinkpad) + gst_object_unref(GST_OBJECT(sinkpad)); - if (newstate == GST_STATE_PLAYING) { - if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) { + MMPLAYER_FLEAVE(); + return; +} - int retVal = MM_ERROR_NONE; - LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos); +static GstElement * +__mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type) +{ + GstElement *pipeline = NULL; + GstElement *selector = NULL; + GstPad *srcpad = NULL; - retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE); + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL); - if (MM_ERROR_NONE != retVal) - LOGE("failed to seek pending postion. just keep staying current position.\n"); + selector = gst_element_factory_make("input-selector", NULL); + if (!selector) { + LOGE("failed to create input-selector"); + return NULL; + } + g_object_set(selector, "sync-streams", TRUE, NULL); - player->pending_seek.is_pending = FALSE; - } - } + player->pipeline->mainbin[elem_idx].id = elem_idx; + player->pipeline->mainbin[elem_idx].gst = selector; - if (oldstate == newstate) { - LOGD("pipeline reports state transition to old state"); - break; - } + /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */ - switch (newstate) { - case GST_STATE_VOID_PENDING: - break; + srcpad = gst_element_get_static_pad(selector, "src"); - case GST_STATE_NULL: - break; + 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, + __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, + __mmplayer_gst_selector_event_probe, player, NULL); - case GST_STATE_READY: - break; + gst_element_set_state(selector, GST_STATE_PAUSED); - case GST_STATE_PAUSED: - { - gboolean prepare_async = FALSE; - player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT; + pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst; + gst_bin_add(GST_BIN(pipeline), selector); - if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex) - __mmplayer_configure_audio_callback(player); + gst_object_unref(GST_OBJECT(srcpad)); - if (!player->sent_bos && oldstate == GST_STATE_READY) { - // managed prepare async case - mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async); - LOGD("checking prepare mode for async transition - %d", prepare_async); - } + MMPLAYER_FLEAVE(); + return selector; +} - if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) { - MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED); +void +__mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data) +{ + mmplayer_t *player = (mmplayer_t *)data; + GstElement *selector = NULL; + GstCaps *caps = NULL; + GstStructure *str = NULL; + const gchar *name = NULL; + GstPad *sinkpad = NULL; + gboolean first_track = FALSE; + gboolean caps_ret = TRUE; - if (MMPLAYER_IS_STREAMING(player) && (player->streamer)) - __mm_player_streaming_set_content_bitrate(player->streamer, - player->total_maximum_bitrate, player->total_bitrate); + main_element_id_e elem_idx = MMPLAYER_M_NUM; + mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO; - if (player->pending_seek.is_pending) { - LOGW("trying to do pending seek"); - MMPLAYER_CMD_LOCK(player); - __gst_pending_seek(player); - MMPLAYER_CMD_UNLOCK(player); - } - } - } - break; + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(elem && pad); + MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); - case GST_STATE_PLAYING: - { - player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT; + LOGD("pad-added signal handling"); - if (MMPLAYER_IS_STREAMING(player)) { - // managed prepare async case when buffering is completed - // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging. - if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) || - (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING)) - MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING); + /* get mimetype from caps */ + MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret); + if (!caps_ret) + goto ERROR; - if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) { + MMPLAYER_LOG_GST_CAPS_TYPE(caps); + /* LOGD("detected mimetype : %s", name); */ - LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent); - if (player->streamer->buffering_percent < 100) { + if (strstr(name, "video")) { + gint stype = 0; + gchar *caps_str = NULL; - MMMessageParamType msg_param = {0, }; - LOGW("Posting Buffering Completed Message to Application !!!"); + caps_str = gst_caps_to_string(caps); + if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") || + strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32"))) + player->set_mode.video_zc = true; - msg_param.connection.buffering = 100; - MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param); - } - } - } + MMPLAYER_FREEIF(caps_str); - if (player->gapless.stream_changed) { - _mmplayer_update_content_attrs(player, ATTR_ALL); - player->gapless.stream_changed = FALSE; - } + mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE); + mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype); - if (player->doing_seek && async_done) { - player->doing_seek = FALSE; - async_done = FALSE; - MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); - } - } - break; + LOGD("surface type : %d", stype); - default: - break; - } + if (MMPLAYER_IS_MS_BUFF_SRC(player)) { + __mmplayer_gst_create_sinkbin(elem, pad, player); + goto DONE; } - break; - case GST_MESSAGE_CLOCK_LOST: - { - GstClock *clock = NULL; - gboolean need_new_clock = FALSE; + /* in case of exporting video frame, it requires the 360 video filter. + * it will be handled in _no_more_pads(). */ + if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) { + __mmplayer_gst_make_fakesink(player, pad, name); + goto DONE; + } - gst_message_parse_clock_lost(msg, &clock); - LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL")); + LOGD("video selector is required"); + elem_idx = MMPLAYER_M_V_INPUT_SELECTOR; + stream_type = MM_PLAYER_TRACK_TYPE_VIDEO; + } else if (strstr(name, "audio")) { + gint samplerate = 0; + gint channels = 0; - if (!player->videodec_linked) - need_new_clock = TRUE; - else if (!player->ini.use_system_clock) - need_new_clock = TRUE; + 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); + goto DONE; + } - if (need_new_clock) { - LOGD("Provide clock is TRUE, do pause->resume\n"); - __gst_pause(player, FALSE); - __gst_resume(player, FALSE); - } - } - break; + gst_structure_get_int(str, "rate", &samplerate); + gst_structure_get_int(str, "channels", &channels); - case GST_MESSAGE_NEW_CLOCK: - { - GstClock *clock = NULL; - gst_message_parse_new_clock(msg, &clock); - LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL")); - } - break; + if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */ + __mmplayer_gst_make_fakesink(player, pad, name); + goto DONE; + } - case GST_MESSAGE_ELEMENT: - { - const gchar *structure_name; - gint count = 0, idx = 0; - MMHandleType attrs = 0; + LOGD("audio selector is required"); + elem_idx = MMPLAYER_M_A_INPUT_SELECTOR; + stream_type = MM_PLAYER_TRACK_TYPE_AUDIO; - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("cannot get content attribute"); - break; - } + } else if (strstr(name, "text")) { + LOGD("text selector is required"); + elem_idx = MMPLAYER_M_T_INPUT_SELECTOR; + stream_type = MM_PLAYER_TRACK_TYPE_TEXT; + } else { + LOGE("invalid caps info"); + goto ERROR; + } - if (gst_message_get_structure(msg) == NULL) - break; + /* 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) + goto ERROR; + first_track = TRUE; + } else { + LOGD("input-selector is already created."); + } - structure_name = gst_structure_get_name(gst_message_get_structure(msg)); - if (!structure_name) - break; + /* link */ + sinkpad = gst_element_get_request_pad(selector, "sink_%u"); - LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg))); + LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad)); - if (!strcmp(structure_name, "adaptive-streaming-variant")) { - const GValue *var_info = NULL; + if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) { + LOGE("failed to link selector"); + gst_object_unref(GST_OBJECT(selector)); + goto ERROR; + } - var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info"); - if (var_info != NULL) { - if (player->adaptive_info.var_list) - g_list_free_full(player->adaptive_info.var_list, g_free); + if (first_track) { + LOGD("this track will be activated"); + g_object_set(selector, "active-pad", sinkpad, NULL); + } - /* share addr or copy the list */ - player->adaptive_info.var_list = - g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL); + __mmplayer_track_update_selector_info(player, stream_type, sinkpad); - count = g_list_length(player->adaptive_info.var_list); - if (count > 0) { - VariantData *temp = NULL; +DONE: +ERROR: - /* print out for debug */ - LOGD("num of variant_info %d", count); - for (idx = 0; idx < count; idx++) { - temp = g_list_nth_data(player->adaptive_info.var_list, idx); - if (temp) - LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height); - } - } - } - } + if (caps) + gst_caps_unref(caps); - if (!strcmp(structure_name, "prepare-decode-buffers")) { - gint num_buffers = 0; - gint extra_num_buffers = 0; + if (sinkpad) { + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; + } - if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) { - player->video_num_buffers = num_buffers; - LOGD("video_num_buffers : %d", player->video_num_buffers); - } + return; +} - if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) { - player->video_extra_num_buffers = extra_num_buffers; - LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers); - } - break; - } +static gboolean +__mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type) +{ + GstPad *srcpad = NULL; - if (!strcmp(structure_name, "Language_list")) { - const GValue *lang_list = NULL; - lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list"); - if (lang_list != NULL) { - count = g_list_length((GList *)g_value_get_pointer(lang_list)); - if (count > 1) - LOGD("Total audio tracks(from parser) = %d \n", count); - } - } + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE); - if (!strcmp(structure_name, "Ext_Sub_Language_List")) { - const GValue *lang_list = NULL; - MMPlayerLangStruct *temp = NULL; - - lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list"); - if (lang_list != NULL) { - count = g_list_length((GList *)g_value_get_pointer(lang_list)); - if (count) { - MMPLAYER_SUBTITLE_INFO_LOCK(player); - player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list); - mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count); - if (mmf_attrs_commit(attrs)) - LOGE("failed to commit.\n"); - LOGD("Total subtitle tracks = %d \n", count); - - while (count) { - temp = g_list_nth_data(player->subtitle_language_list, count - 1); - if (temp) - LOGD("value of lang_key is %s and lang_code is %s", - temp->language_key, temp->language_code); - count--; - } - MMPLAYER_SUBTITLE_INFO_SIGNAL(player); - MMPLAYER_SUBTITLE_INFO_UNLOCK(player); - } - } - } + LOGD("type %d", type); - /* custom message */ - if (!strcmp(structure_name, "audio_codec_not_supported")) { - MMMessageParamType msg_param = {0,}; - msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; - MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); - } + if (!selector) { + LOGD("there is no %d track", type); + return TRUE; + } - /* custom message for RTSP attribute : - RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged. - sdp which has contents info is received when rtsp connection is opened. - extract duration ,codec info , resolution from sdp and get it by GstMessage */ - if (!strcmp(structure_name, "rtspsrc_properties")) { + srcpad = gst_element_get_static_pad(selector, "src"); + if (!srcpad) { + LOGE("failed to get srcpad from selector"); + return FALSE; + } - gchar *audio_codec = NULL; - gchar *video_codec = NULL; - gchar *video_frame_size = NULL; + LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad)); - gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL); - LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration)); - player->streaming_type = __mmplayer_get_stream_service_type(player); - mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration)); + __mmplayer_gst_create_sinkbin(selector, srcpad, player); - gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL); - LOGD("rtsp_audio_codec : %s", audio_codec); - if (audio_codec) - mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec); + 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; + } - gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL); - LOGD("rtsp_video_codec : %s", video_codec); - if (video_codec) - mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec); + if (srcpad) { + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + } - gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL); - LOGD("rtsp_video_frame_size : %s", video_frame_size); - if (video_frame_size) { + MMPLAYER_FLEAVE(); + return TRUE; +} - char *seperator = strchr(video_frame_size, '-'); - if (seperator) { +static void +__mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type) +{ + MMHandleType attrs = 0; + gint active_index = 0; - char video_width[10] = {0,}; - int frame_size_len = strlen(video_frame_size); - int separtor_len = strlen(seperator); + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player); - strncpy(video_width, video_frame_size, (frame_size_len - separtor_len)); - mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width)); + LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num); - seperator++; - mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator)); - } - } + /* change track to active pad */ + active_index = player->selector[type].active_pad_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; + return; + } - if (mmf_attrs_commit(attrs)) - LOGE("failed to commit.\n"); - } - } - break; + 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); - case GST_MESSAGE_DURATION_CHANGED: - { - LOGD("GST_MESSAGE_DURATION_CHANGED\n"); - if (!__mmplayer_gst_handle_duration(player, msg)) - LOGW("failed to update duration"); + if (mm_attrs_commit_all(attrs)) + LOGW("failed to commit attrs."); + } else { + LOGW("cannot get content attribute"); } + } - break; - - case GST_MESSAGE_ASYNC_START: - LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg))); - break; + MMPLAYER_FLEAVE(); + return; +} - case GST_MESSAGE_ASYNC_DONE: - { - LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg))); +static gboolean +__mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector) +{ + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE); - /* we only handle messages from pipeline */ - if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) - break; + if (!audio_selector) { + LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad); - if (player->doing_seek) { - if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) { - player->doing_seek = FALSE; - MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); - } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) { - if ((MMPLAYER_IS_HTTP_STREAMING(player)) && - (player->streamer) && - (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) && - (player->streamer->is_buffering == FALSE)) { - GstQuery *query = NULL; - gboolean busy = FALSE; - gint percent = 0; - - if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) { - query = gst_query_new_buffering(GST_FORMAT_PERCENT); - if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query)) - gst_query_parse_buffering_percent(query, &busy, &percent); - gst_query_unref(query); - - LOGD("buffered percent(%s): %d\n", - GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent); - } + /* in case the source is changed, output can be changed. */ + if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) { + LOGD("remove previous audiobin if it exist"); - if (percent >= 100) { - player->streamer->is_buffering = FALSE; - __mmplayer_handle_buffering_message(player); - } - } + __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN); + __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst); - async_done = TRUE; - } - } + MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN); + MMPLAYER_FREEIF(player->pipeline->audiobin); } - break; - #if 0 /* delete unnecessary logs */ - case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break; - case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break; - case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break; - case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break; - case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break; - case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break; - case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break; - case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break; - case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break; - case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break; - case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break; - case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break; - case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break; - case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break; - case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break; - #endif + if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */ + __mmplayer_pipeline_complete(NULL, player); - default: - break; + return TRUE; } - /* should not call 'gst_message_unref(msg)' */ - return; + /* apply the audio track information */ + __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)) { + LOGE("failed to create audio sink path"); + return FALSE; + } + + MMPLAYER_FLEAVE(); + return TRUE; } static gboolean -__mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg) +__mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector) { - gint64 bytes = 0; - MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE); + if (MMPLAYER_IS_MS_BUFF_SRC(player)) { + LOGD("text path is not supproted"); + return TRUE; + } - if ((MMPLAYER_IS_HTTP_STREAMING(player)) && - (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) { - LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src))); + /* apply the text track information */ + __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT); - if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) { - LOGD("data total size of http content: %lld", bytes); - player->http_content_size = (bytes > 0) ? (bytes) : (0); - } - } else - /* handling audio clip which has vbr. means duration is keep changing */ - _mmplayer_update_content_attrs(player, ATTR_DURATION); + if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0) + player->has_closed_caption = TRUE; - MMPLAYER_FLEAVE(); + /* create text decode path */ + player->no_more_pad = TRUE; - return TRUE; -} + if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) { + LOGE("failed to create text sink path"); + return FALSE; + } -static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, - mm_player_spherical_metadata_t *metadata) { - gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical); - gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched); - gst_tag_list_get_string(tags, "stitching_software", - &metadata->stitching_software); - gst_tag_list_get_string(tags, "projection_type", - &metadata->projection_type_string); - gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string); - gst_tag_list_get_int(tags, "source_count", &metadata->source_count); - gst_tag_list_get_int(tags, "init_view_heading", - &metadata->init_view_heading); - gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch); - gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll); - gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp); - gst_tag_list_get_int(tags, "full_pano_width_pixels", - &metadata->full_pano_width_pixels); - gst_tag_list_get_int(tags, "full_pano_height_pixels", - &metadata->full_pano_height_pixels); - gst_tag_list_get_int(tags, "cropped_area_image_width", - &metadata->cropped_area_image_width); - gst_tag_list_get_int(tags, "cropped_area_image_height", - &metadata->cropped_area_image_height); - gst_tag_list_get_int(tags, "cropped_area_left", - &metadata->cropped_area_left); - gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top); - gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type); - gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format); - gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order); + MMPLAYER_FLEAVE(); + return TRUE; } static gboolean -__mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) -{ - -/* macro for better code readability */ -#define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \ -if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\ - if (string != NULL) { \ - SECURE_LOGD("update tag string : %s\n", string); \ - if (strlen(string) > MM_MAX_STRING_LENGTH) { \ - char *new_string = malloc(MM_MAX_STRING_LENGTH); \ - strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \ - new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \ - mm_attrs_set_string_by_name(attribute, playertag, new_string); \ - g_free(new_string); \ - new_string = NULL; \ - } else { \ - mm_attrs_set_string_by_name(attribute, playertag, string); \ - } \ - g_free(string); \ - string = NULL; \ - } \ -} - -#define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \ -do { \ - GstSample *sample = NULL;\ - if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\ - GstMapInfo info = GST_MAP_INFO_INIT;\ - buffer = gst_sample_get_buffer(sample);\ - if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\ - LOGD("failed to get image data from tag");\ - gst_sample_unref(sample);\ - return FALSE;\ - } \ - SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\ - MMPLAYER_FREEIF(player->album_art);\ - player->album_art = (gchar *)g_malloc(info.size);\ - if (player->album_art) {\ - memcpy(player->album_art, info.data, info.size);\ - mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\ - if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\ - msg_param.data = (void *)player->album_art;\ - msg_param.size = info.size;\ - MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\ - SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\ - } \ - } \ - gst_buffer_unmap(buffer, &info);\ - gst_sample_unref(sample);\ - } \ -} while (0) - -#define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \ -do { \ - if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \ - if (v_uint) { \ - int i = 0; \ - gchar *tag_list_str = NULL; \ - MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \ - if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \ - track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \ - else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \ - track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \ - else \ - track_type = MM_PLAYER_TRACK_TYPE_TEXT; \ - if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \ - if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \ - mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \ - player->bitrate[track_type] = v_uint; \ - player->total_bitrate = 0; \ - for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \ - player->total_bitrate += player->bitrate[i]; \ - mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \ - SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \ - } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \ - player->maximum_bitrate[track_type] = v_uint; \ - player->total_maximum_bitrate = 0; \ - for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \ - player->total_maximum_bitrate += player->maximum_bitrate[i]; \ - mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\ - SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\ - } else { \ - mm_attrs_set_int_by_name(attribute, playertag, v_uint); \ - } \ - v_uint = 0;\ - g_free(tag_list_str); \ - } \ - } \ -} while (0) - -#define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \ -if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\ - if (date != NULL) {\ - string = g_strdup_printf("%d", g_date_get_year(date));\ - mm_attrs_set_string_by_name(attribute, playertag, string);\ - SECURE_LOGD("metainfo year : %s\n", string);\ - MMPLAYER_FREEIF(string);\ - g_date_free(date);\ - } \ -} - -#define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \ -if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\ - if (datetime != NULL) {\ - string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\ - mm_attrs_set_string_by_name(attribute, playertag, string);\ - SECURE_LOGD("metainfo year : %s\n", string);\ - MMPLAYER_FREEIF(string);\ - gst_date_time_unref(datetime);\ - } \ -} - -#define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \ -if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\ - if (v_uint64) {\ - /* FIXIT : don't know how to store date */\ - g_assert(1);\ - v_uint64 = 0;\ - } \ -} - -#define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \ -if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\ - if (v_double) {\ - /* FIXIT : don't know how to store date */\ - g_assert(1);\ - v_double = 0;\ - } \ -} - - /* function start */ - GstTagList* tag_list = NULL; +__mmplayer_gst_set_queue2_buffering(mmplayer_t *player) +{ + gint64 dur_bytes = 0L; - MMHandleType attrs = 0; + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && + player->pipeline->mainbin && player->streamer, FALSE); - char *string = NULL; - guint v_uint = 0; - GDate *date = NULL; - GstDateTime *datetime = NULL; - /* album cover */ - GstBuffer *buffer = NULL; - gint index = 0; - MMMessageParamType msg_param = {0, }; + if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) + LOGE("fail to get duration."); - /* currently not used. but those are needed for above macro */ - //guint64 v_uint64 = 0; - //gdouble v_double = 0; + /* 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, + player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, + TRUE, /* use_buffering */ + MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */ + ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0)); - MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE); + MMPLAYER_FLEAVE(); + return TRUE; +} - attrs = MMPLAYER_GET_ATTRS(player); +static void +__mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data) +{ + mmplayer_t *player = NULL; + GstElement *video_selector = NULL; + GstElement *audio_selector = NULL; + GstElement *text_selector = NULL; - MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE); - - /* get tag list from gst message */ - gst_message_parse_tag(msg, &tag_list); - - /* store tags to player attributes */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author"); - MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date"); - MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date"); - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */ - MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num"); - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec"); - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec"); - MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate"); - MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate"); - MMPLAYER_UPDATE_TAG_LOCK(player); - MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover"); - MMPLAYER_UPDATE_TAG_UNLOCK(player); - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation"); - - if (strstr(GST_OBJECT_NAME(msg->src), "demux")) { - if (player->video360_metadata.is_spherical == -1) { - __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata); - mm_attrs_set_int_by_name(attrs, "content_video_is_spherical", - player->video360_metadata.is_spherical); - if (player->video360_metadata.is_spherical == 1) { - LOGD("This is spherical content for 360 playback."); - player->is_content_spherical = TRUE; - } else { - LOGD("This is not spherical content"); - player->is_content_spherical = FALSE; - } + MMPLAYER_FENTER(); + player = (mmplayer_t *)data; - if (player->video360_metadata.projection_type_string) { - if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) { - player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR; - } else { - LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string); - player->is_content_spherical = player->is_video360_enabled = FALSE; - } - } + LOGD("no-more-pad signal handling"); - if (player->video360_metadata.stereo_mode_string) { - if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) { - player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC; - } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) { - player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT; - } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) { - player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM; - } else { - LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string); - player->is_content_spherical = player->is_video360_enabled = FALSE; - } - } + if ((player->cmd == MMPLAYER_COMMAND_DESTROY) || + (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) { + LOGW("player is shutting down"); + goto EXIT; + } + + if ((MMPLAYER_IS_HTTP_STREAMING(player)) && + (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) && + (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) { + if (!__mmplayer_gst_set_queue2_buffering(player)) { + LOGE("failed to set queue2 buffering"); + goto EXIT; } } - if (mmf_attrs_commit(attrs)) - LOGE("failed to commit.\n"); + video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst; + audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst; + text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst; - gst_tag_list_free(tag_list); + if (!video_selector && !audio_selector && !text_selector) { + LOGW("there is no selector"); + player->no_more_pad = TRUE; + goto EXIT; + } - return TRUE; -} + /* create video path followed by video-select */ + if (video_selector && !audio_selector && !text_selector) + player->no_more_pad = TRUE; -static void -__mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data) -{ - mm_player_t* player = (mm_player_t*) data; + if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO)) + goto EXIT; - MMPLAYER_FENTER(); + /* create audio path followed by audio-select */ + if (audio_selector && !text_selector) + player->no_more_pad = TRUE; - /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever - * we connect autoplugging element to the pad which is just added to rtspsrc, we increase - * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added. - * So we can say this. if num_dynamic_pad is zero, it must be one of followings - - * [1] audio and video will be dumped with filesink. - * [2] autoplugging is done by just using pad caps. - * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal - * and the video will be dumped via filesink. - */ - if (player->num_dynamic_pad == 0) { - LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n"); - - if (!__mmplayer_gst_remove_fakesink(player, - &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) - /* NOTE : __mmplayer_pipeline_complete() can be called several time. because - * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various - * source element are not same. To overcome this situation, this function will called - * several places and several times. Therefore, this is not an error case. - */ - return; - } + if (!__mmplayer_create_audio_sink_path(player, audio_selector)) + goto EXIT; - /* create dot before error-return. for debugging */ - MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad"); + /* create text path followed by text-select */ + __mmplayer_create_text_sink_path(player, text_selector); - player->no_more_pad = TRUE; +EXIT: + if (player->gapless.reconfigure) { + player->gapless.reconfigure = FALSE; + MMPLAYER_PLAYBACK_UNLOCK(player); + } MMPLAYER_FLEAVE(); } static gboolean -__mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) +__mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name) { - 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); + gboolean ret = FALSE; + GstElement *pipeline = NULL; + GstPad *sinkpad = NULL; - /* lock */ - MMPLAYER_FSINK_LOCK(player); + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE); - if (!fakesink->gst) - goto ERROR; + pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst; - /* get parent of fakesink */ - parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst); - if (!parent) { - LOGD("fakesink already removed\n"); - goto ERROR; + sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name); + if (!sinkpad) { + LOGE("failed to get pad from sinkbin"); + goto EXIT; } - 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 - */ - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL)) - LOGE("fakesink state change failure!\n"); - /* FIXIT : should I return here? or try to proceed to next? */ - /* return FALSE; */ + if (reusing) { + /* link only */ + if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) { + LOGE("failed to link sinkbin for reusing"); + goto EXIT; /* exit either pass or fail */ + } + } else { + /* warm up */ + if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) { + LOGE("failed to set state(READY) to sinkbin"); + goto EXIT; + } - /* remove fakesink from it's parent */ - if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) { - LOGE("failed to remove fakesink\n"); + /* add */ + if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) { + LOGE("failed to add sinkbin to pipeline"); + goto EXIT; + } - gst_object_unref(parent); + /* link */ + if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) { + LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad)); + goto EXIT; + } - goto ERROR; + /* run */ + if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { + LOGE("failed to set state(PAUSED) to sinkbin"); + goto EXIT; + } } - gst_object_unref(parent); - - LOGD("state-holder removed\n"); - - gst_element_set_locked_state(fakesink->gst, FALSE); + ret = TRUE; - MMPLAYER_FSINK_UNLOCK(player); - return TRUE; - -ERROR: - if (fakesink->gst) - gst_element_set_locked_state(fakesink->gst, FALSE); +EXIT: + if (sinkpad) + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; - MMPLAYER_FSINK_UNLOCK(player); - return FALSE; + MMPLAYER_FLEAVE(); + return ret; } - static void -__mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) +__mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data) { - GstPad *sinkpad = NULL; - GstCaps* caps = NULL; - GstElement* new_element = NULL; - GstStructure* str = NULL; - const gchar* name = NULL; + mmplayer_t *player = NULL; + GstCaps *caps = NULL; + gchar *caps_str = NULL; + GstStructure *str = NULL; + const gchar *name = NULL; + GstElement *sinkbin = NULL; + gboolean reusing = FALSE; + gboolean caps_ret = TRUE; + gchar *sink_pad_name = "sink"; - mm_player_t* player = (mm_player_t*) data; + /* check handles */ + player = (mmplayer_t *)data; MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(elem && pad); + MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player)); - MMPLAYER_RETURN_IF_FAIL(element && pad); - MMPLAYER_RETURN_IF_FAIL(player && - player->pipeline && - player->pipeline->mainbin); - - - /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation. - * num_dynamic_pad will decreased after creating a sinkbin. - */ - player->num_dynamic_pad++; - LOGD("stream count inc : %d\n", player->num_dynamic_pad); + MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret); + if (!caps_ret) + goto ERROR; - caps = gst_pad_query_caps(pad, NULL); + caps_str = gst_caps_to_string(caps); - MMPLAYER_CHECK_NULL(caps); + /* LOGD("detected mimetype : %s", name); */ + 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); + } - /* clear previous result*/ - player->have_dynamic_pad = FALSE; + if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) { + LOGE("failed to create audiobin. continuing without audio"); + goto ERROR; + } - str = gst_caps_get_structure(caps, 0); + sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst; + LOGD("creating audiobin success"); + } else { + reusing = TRUE; + sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst; + LOGD("reusing audiobin"); + __mmplayer_update_content_attrs(player, ATTR_AUDIO); + } + } else if (strstr(name, "video")) { + /* 1. zero copy is updated at _decode_pad_added() + * 2. NULL surface type is handled in _decode_pad_added() */ + LOGD("zero copy %d", player->set_mode.video_zc); + if (player->pipeline->videobin == NULL) { + int surface_type = 0; + mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type); + LOGD("display_surface_type (%d)", surface_type); - if (!str) { - LOGE("cannot get structure from caps.\n"); - goto ERROR; - } + 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; + } + } - name = gst_structure_get_name(str); - if (!name) { - LOGE("cannot get mimetype from structure.\n"); - goto ERROR; - } + player->interrupted_by_resource = FALSE; - if (strstr(name, "video")) { - gint stype = 0; - mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype); + if (mm_resource_manager_commit(player->resource_manager) != + MM_RESOURCE_MANAGER_ERROR_NONE) { + LOGE("could not acquire resources for video playing"); + goto ERROR; + } - if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) { - if (player->v_stream_caps) { - gst_caps_unref(player->v_stream_caps); - player->v_stream_caps = NULL; + if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) { + LOGE("failed to create videobin. continuing without video"); + goto ERROR; } - new_element = gst_element_factory_make("fakesink", NULL); - player->num_dynamic_pad--; - goto NEW_ELEMENT; + sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst; + LOGD("creating videosink bin success"); + } else { + reusing = TRUE; + sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst; + LOGD("re-using videobin"); + __mmplayer_update_content_attrs(player, ATTR_VIDEO); } - } - - /* clear previous result*/ - player->have_dynamic_pad = FALSE; + } else if (strstr(name, "text")) { + if (player->pipeline->textbin == NULL) { + if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) { + LOGE("failed to create text sink bin. continuing without text"); + goto ERROR; + } - if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) { - LOGE("failed to autoplug for caps"); + sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst; + player->textsink_linked = 1; + LOGD("creating textsink bin success"); + } else { + if (!player->textsink_linked) { + LOGD("re-using textbin"); + reusing = TRUE; + sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst; + 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"); + } + } + sink_pad_name = "text_sink"; + } else { + LOGW("unknown mime type %s, ignoring it", name); goto ERROR; } - /* check if there's dynamic pad*/ - if (player->have_dynamic_pad) { - LOGE("using pad caps assums there's no dynamic pad !\n"); + if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name)) goto ERROR; - } - gst_caps_unref(caps); - caps = NULL; + LOGD("[handle: %p] success to create and link sink bin", player); -NEW_ELEMENT: + /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in + * streaming task. if the task blocked, then buffer will not flow to the next element + *(autoplugging element). so this is special hack for streaming. please try to remove it + */ + /* dec stream count. we can remove fakesink if it's zero */ + if (player->num_dynamic_pad) + player->num_dynamic_pad--; - /* excute new_element if created*/ - if (new_element) { - LOGD("adding new element to pipeline\n"); + LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad); - /* set state to READY before add to bin */ - MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY); + if ((player->no_more_pad) && (player->num_dynamic_pad == 0)) + __mmplayer_pipeline_complete(NULL, player); - /* add new element to the pipeline */ - if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) { - LOGE("failed to add autoplug element to bin\n"); - goto ERROR; - } +ERROR: - /* get pad from element */ - sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink"); - if (!sinkpad) { - LOGE("failed to get sinkpad from autoplug element\n"); - goto ERROR; - } + MMPLAYER_FREEIF(caps_str); - /* link it */ - if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) { - LOGE("failed to link autoplug element\n"); - goto ERROR; - } + if (caps) + gst_caps_unref(caps); - gst_object_unref(sinkpad); - sinkpad = NULL; + return; +} - /* run. setting PLAYING here since streamming source is live source */ - MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING); - } +static gboolean +__mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value) +{ + int required_angle = 0; /* Angle required for straight view */ + int rotation_angle = 0; - if (caps) - gst_caps_unref(caps); + MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); + MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE); - MMPLAYER_FLEAVE(); + /* Counter clockwise */ + switch (orientation) { + case 0: + required_angle = 0; + break; + case 90: + required_angle = 270; + break; + case 180: + required_angle = 180; + break; + case 270: + required_angle = 90; + break; + } - return; + rotation_angle = display_angle + required_angle; + if (rotation_angle >= 360) + rotation_angle -= 360; -STATE_CHANGE_FAILED: -ERROR: - /* FIXIT : take care if new_element has already added to pipeline */ - if (new_element) - gst_object_unref(GST_OBJECT(new_element)); + /* chech if supported or not */ + if (rotation_angle % 90) { + LOGD("not supported rotation angle = %d", rotation_angle); + return FALSE; + } - if (sinkpad) - gst_object_unref(GST_OBJECT(sinkpad)); + switch (rotation_angle) { + case 0: + *value = MM_DISPLAY_ROTATION_NONE; + break; + case 90: + *value = MM_DISPLAY_ROTATION_90; + break; + case 180: + *value = MM_DISPLAY_ROTATION_180; + break; + case 270: + *value = MM_DISPLAY_ROTATION_270; + break; + } - if (caps) - gst_caps_unref(caps); + LOGD("setting rotation property value : %d", *value); - /* FIXIT : how to inform this error to MSL ????? */ - /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and - * then post an error to application - */ + return TRUE; } -static GstPadProbeReturn -__mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data) +int +__mmplayer_video_param_check_video_sink_bin(mmplayer_t *player) { - LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad)); - return GST_PAD_PROBE_OK; + /* 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; } -static GstPadProbeReturn -__mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data) +int +__mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation) { - GstPadProbeReturn ret = GST_PAD_PROBE_OK; - GstEvent *event = GST_PAD_PROBE_INFO_DATA(info); - mm_player_t* player = (mm_player_t*)data; - GstCaps* caps = NULL; - GstStructure* str = NULL; - const gchar* name = NULL; - MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO; - - - if (GST_EVENT_IS_DOWNSTREAM(event)) { - 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) - return ret; - } else if (GST_EVENT_IS_UPSTREAM(event)) { - if (GST_EVENT_TYPE(event) != GST_EVENT_QOS) - return ret; - } + int display_rotation = 0; + gchar *org_orient = NULL; + MMHandleType attrs = MMPLAYER_GET_ATTRS(player); - caps = gst_pad_query_caps(pad, NULL); - if (!caps) { - LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad)); - return ret; + if (!attrs) { + LOGE("cannot get content attribute"); + return MM_ERROR_PLAYER_INTERNAL; } - str = gst_caps_get_structure(caps, 0); - if (!str) { - LOGE("failed to get structure from caps"); - goto ERROR; - } + if (display_angle) { + /* update user roation */ + mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation); - name = gst_structure_get_name(str); - if (!name) { - LOGE("failed to get name from str"); - goto ERROR; + /* Counter clockwise */ + switch (display_rotation) { + case MM_DISPLAY_ROTATION_NONE: + *display_angle = 0; + break; + case MM_DISPLAY_ROTATION_90: + *display_angle = 90; + break; + case MM_DISPLAY_ROTATION_180: + *display_angle = 180; + break; + case MM_DISPLAY_ROTATION_270: + *display_angle = 270; + break; + default: + LOGW("wrong angle type : %d", display_rotation); + break; + } + LOGD("check user angle: %d", *display_angle); } - if (strstr(name, "audio")) { - stream_type = MM_PLAYER_TRACK_TYPE_AUDIO; - } else if (strstr(name, "video")) { - stream_type = MM_PLAYER_TRACK_TYPE_VIDEO; - } else { - /* text track is not supportable */ - LOGE("invalid name %s", name); - goto ERROR; - } + if (orientation) { + /* Counter clockwise */ + mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient); - switch (GST_EVENT_TYPE(event)) { - case GST_EVENT_EOS: - { - /* in case of gapless, drop eos event not to send it to sink */ - if (player->gapless.reconfigure && !player->msg_posted) { - LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad)); - ret = GST_PAD_PROBE_DROP; - } - break; + if (org_orient) { + if (!strcmp(org_orient, "rotate-90")) + *orientation = 90; + else if (!strcmp(org_orient, "rotate-180")) + *orientation = 180; + else if (!strcmp(org_orient, "rotate-270")) + *orientation = 270; + else + LOGD("original rotation is %s", org_orient); + } else { + LOGD("content_video_orientation get fail"); } - case GST_EVENT_STREAM_START: - { - gint64 stop_running_time = 0; - gint64 position_running_time = 0; - gint64 position = 0; - gint idx = 0; - - 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); */ - continue; - } - if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) { - stop_running_time = - gst_segment_to_running_time(&player->gapless.segment[idx], - GST_FORMAT_TIME, player->gapless.segment[idx].stop); - } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) { - stop_running_time = - gst_segment_to_running_time(&player->gapless.segment[idx], - GST_FORMAT_TIME, player->gapless.segment[idx].duration); - } else { - LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration)); - stop_running_time = - gst_segment_to_running_time(&player->gapless.segment[idx], - GST_FORMAT_TIME, player->duration); - } + LOGD("check orientation: %d", *orientation); + } - position_running_time = - gst_segment_to_running_time(&player->gapless.segment[idx], - GST_FORMAT_TIME, player->gapless.segment[idx].position); - - LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %" - GST_TIME_FORMAT" , %" GST_TIME_FORMAT, - idx, - GST_TIME_ARGS(stop_running_time), - GST_TIME_ARGS(position_running_time), - GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx], - GST_FORMAT_TIME, player->gapless.segment[idx].start))); - - position_running_time = MAX(position_running_time, stop_running_time); - position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx], - GST_FORMAT_TIME, player->gapless.segment[idx].start); - position_running_time = MAX(0, position_running_time); - position = MAX(position, position_running_time); - } + return MM_ERROR_NONE; +} - if (position != 0) { - LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT, - stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]), - GST_TIME_ARGS(player->gapless.start_time[stream_type] + position)); +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 + int display_angle = 0; + MMPLAYER_FENTER(); - player->gapless.start_time[stream_type] += position; - } - break; - } - case GST_EVENT_FLUSH_STOP: - { - LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type); - gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED); - player->gapless.start_time[stream_type] = 0; - break; - } - case GST_EVENT_SEGMENT: - { - GstSegment segment; - GstEvent *tmpev; + /* check video sinkbin is created */ + if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) + return; - LOGD("[%d] GST_EVENT_SEGMENT", stream_type); - gst_event_copy_segment(event, &segment); + __mmplayer_get_video_angle(player, &display_angle, &orientations); - if (segment.format == GST_FORMAT_TIME) { - LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT - ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT - ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT, - GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset), - GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop), - GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration)); + /* get rotation value to set */ + __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value); + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL); + LOGD("set video param : rotate %d", rotation_value); +} - /* keep the all the segment ev to cover the seeking */ - gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]); - player->gapless.update_segment[stream_type] = TRUE; +void +__mmplayer_video_param_set_display_visible(mmplayer_t *player) +{ + MMHandleType attrs = 0; + int visible = 0; + MMPLAYER_FENTER(); - if (!player->gapless.running) - break; + /* check video sinkbin is created */ + if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) + return; - player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type]; + attrs = MMPLAYER_GET_ATTRS(player); + MMPLAYER_RETURN_IF_FAIL(attrs); - LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base)); + mm_attrs_get_int_by_name(attrs, "display_visible", &visible); + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL); + LOGD("set video param : visible %d", visible); +} - tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]); - gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event)); - gst_event_unref(event); - GST_PAD_PROBE_INFO_DATA(info) = tmpev; - } - break; - } - case GST_EVENT_QOS: - { - gdouble proportion = 0.0; - GstClockTimeDiff diff = 0; - GstClockTime timestamp = 0; - gint64 running_time_diff = -1; - GstQOSType type = 0; - GstEvent *tmpev = NULL; - - running_time_diff = player->gapless.segment[stream_type].base; - - if (running_time_diff <= 0) /* don't need to adjust */ - break; - - gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp); - gst_event_unref(event); - - if (timestamp < running_time_diff) { - LOGW("QOS event from previous group"); - ret = GST_PAD_PROBE_DROP; - break; - } - - 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)); - - timestamp -= running_time_diff; - - /* That case is invalid for QoS events */ - if (diff < 0 && -diff > timestamp) { - LOGW("QOS event from previous group"); - ret = GST_PAD_PROBE_DROP; - break; - } - - tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp); - GST_PAD_PROBE_INFO_DATA(info) = tmpev; - - break; - } - default: - break; - } - -ERROR: - if (caps) - gst_caps_unref(caps); - return ret; -} - -static void -__mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data) -{ - mm_player_t* player = NULL; - GstElement* pipeline = NULL; - GstElement* selector = NULL; - GstElement* fakesink = NULL; - GstCaps* caps = NULL; - GstStructure* str = NULL; - const gchar* name = NULL; - GstPad* sinkpad = NULL; - GstPad* srcpad = NULL; - gboolean first_track = FALSE; - - enum MainElementID elemId = MMPLAYER_M_NUM; - MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO; - - /* check handles */ - player = (mm_player_t*)data; - - MMPLAYER_RETURN_IF_FAIL(elem && pad); - MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); - - //LOGD("pad-added signal handling\n"); - - pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst; - - /* get mimetype from caps */ - caps = gst_pad_query_caps(pad, NULL); - if (!caps) { - LOGE("cannot get caps from pad.\n"); - goto ERROR; - } - - str = gst_caps_get_structure(caps, 0); - if (!str) { - LOGE("cannot get structure from caps.\n"); - goto ERROR; - } - - name = gst_structure_get_name(str); - if (!name) { - LOGE("cannot get mimetype from structure.\n"); - goto ERROR; - } - - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - //LOGD("detected mimetype : %s\n", name); - - if (strstr(name, "video")) { - gint stype = 0; - - mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE); - mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype); - - /* don't make video because of not required, and not support multiple track */ - if (stype == MM_DISPLAY_SURFACE_NULL) { - LOGD("no video sink by null surface"); - - gchar *caps_str = gst_caps_to_string(caps); - if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") || - strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32"))) - player->set_mode.video_zc = TRUE; - - MMPLAYER_FREEIF(caps_str); - - if (player->v_stream_caps) { - gst_caps_unref(player->v_stream_caps); - player->v_stream_caps = NULL; - } - - LOGD("create fakesink instead of videobin"); - - /* fake sink */ - fakesink = gst_element_factory_make("fakesink", NULL); - if (fakesink == NULL) { - LOGE("ERROR : fakesink create error\n"); - goto ERROR; - } - - if (player->ini.set_dump_element_flag) - __mmplayer_add_dump_buffer_probe(player, fakesink); - - player->video_fakesink = fakesink; - - /* store it as it's sink element */ - __mmplayer_add_sink(player, player->video_fakesink); - - gst_bin_add(GST_BIN(pipeline), fakesink); - - // link - sinkpad = gst_element_get_static_pad(fakesink, "sink"); - - if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) { - LOGW("failed to link fakesink\n"); - gst_object_unref(GST_OBJECT(fakesink)); - goto ERROR; - } - - if (stype == MM_DISPLAY_SURFACE_REMOTE) { - MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, - "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player); - } - - if (player->set_mode.media_packet_video_stream) { - g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL); - - MMPLAYER_SIGNAL_CONNECT(player, - G_OBJECT(fakesink), - MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, - "handoff", - G_CALLBACK(__mmplayer_video_stream_decoded_render_cb), - (gpointer)player); - - MMPLAYER_SIGNAL_CONNECT(player, - G_OBJECT(fakesink), - MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, - "preroll-handoff", - G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb), - (gpointer)player); - } - - g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL); - gst_element_set_state(fakesink, GST_STATE_PAUSED); - goto DONE; - } - - if (MMPLAYER_IS_MS_BUFF_SRC(player)) { - __mmplayer_gst_decode_callback(elem, pad, player); - goto DONE; - } - - LOGD("video selector \n"); - elemId = MMPLAYER_M_V_INPUT_SELECTOR; - stream_type = MM_PLAYER_TRACK_TYPE_VIDEO; - } else { - if (strstr(name, "audio")) { - gint samplerate = 0; - gint channels = 0; - - if (MMPLAYER_IS_MS_BUFF_SRC(player)) { - __mmplayer_gst_decode_callback(elem, pad, player); - goto DONE; - } - - LOGD("audio selector \n"); - elemId = MMPLAYER_M_A_INPUT_SELECTOR; - stream_type = MM_PLAYER_TRACK_TYPE_AUDIO; - - gst_structure_get_int(str, "rate", &samplerate); - gst_structure_get_int(str, "channels", &channels); - - if ((channels > 0 && samplerate == 0)) {//exclude audio decoding - /* fake sink */ - fakesink = gst_element_factory_make("fakesink", NULL); - if (fakesink == NULL) { - LOGE("ERROR : fakesink create error\n"); - goto ERROR; - } - - gst_bin_add(GST_BIN(pipeline), fakesink); - - /* link */ - sinkpad = gst_element_get_static_pad(fakesink, "sink"); - - if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) { - LOGW("failed to link fakesink\n"); - gst_object_unref(GST_OBJECT(fakesink)); - goto ERROR; - } - - g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL); - g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL); - gst_element_set_state(fakesink, GST_STATE_PAUSED); - - goto DONE; - } - } else if (strstr(name, "text")) { - LOGD("text selector \n"); - elemId = MMPLAYER_M_T_INPUT_SELECTOR; - stream_type = MM_PLAYER_TRACK_TYPE_TEXT; - } else { - LOGE("wrong elem id \n"); - goto ERROR; - } - } - - selector = player->pipeline->mainbin[elemId].gst; - if (selector == NULL) { - selector = gst_element_factory_make("input-selector", NULL); - LOGD("Creating input-selector\n"); - if (selector == NULL) { - LOGE("ERROR : input-selector create error\n"); - goto ERROR; - } - g_object_set(selector, "sync-streams", TRUE, NULL); - - player->pipeline->mainbin[elemId].id = elemId; - player->pipeline->mainbin[elemId].gst = selector; - - first_track = TRUE; - // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default - - 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, - __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, - __mmplayer_gst_selector_event_probe, player, NULL); - - gst_element_set_state(selector, GST_STATE_PAUSED); - gst_bin_add(GST_BIN(pipeline), selector); - } else - LOGD("input-selector is already created.\n"); - - // link - LOGD("Calling request pad with selector %p \n", selector); - sinkpad = gst_element_get_request_pad(selector, "sink_%u"); - - LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad)); - - if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) { - LOGW("failed to link selector\n"); - gst_object_unref(GST_OBJECT(selector)); - goto ERROR; - } - - if (first_track) { - LOGD("this is first track --> active track \n"); - g_object_set(selector, "active-pad", sinkpad, NULL); - } - - _mmplayer_track_update_info(player, stream_type, sinkpad); - - -DONE: -ERROR: - - if (caps) - gst_caps_unref(caps); - - if (sinkpad) { - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; - } - - if (srcpad) { - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - } - - return; -} - -static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector) +void +__mmplayer_video_param_set_display_method(mmplayer_t *player) { - GstPad* srcpad = NULL; MMHandleType attrs = 0; - gint active_index = 0; + int display_method = 0; + MMPLAYER_FENTER(); - // [link] input-selector :: textbin - srcpad = gst_element_get_static_pad(text_selector, "src"); - if (!srcpad) { - LOGE("failed to get srcpad from selector\n"); + /* check video sinkbin is created */ + if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) return; - } - - LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad)); - - active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index; - if ((active_index != DEFAULT_TRACK) && - (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) { - LOGW("failed to change text track\n"); - player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK; - } - - player->no_more_pad = TRUE; - __mmplayer_gst_decode_callback(text_selector, srcpad, player); - - LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); - if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) { - gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id); - player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0; - } - - LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num); - - if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0) - player->has_closed_caption = TRUE; attrs = MMPLAYER_GET_ATTRS(player); - if (attrs) { - mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num); - if (mmf_attrs_commit(attrs)) - LOGE("failed to commit.\n"); - } else - LOGE("cannot get content attribute"); - - if (srcpad) { - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - } -} - -static void -__mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data) -{ - mm_player_t* player = (mm_player_t*)data; - GstElement* selector = NULL; - GstElement* queue = NULL; - - GstPad* srcpad = NULL; - GstPad* sinkpad = NULL; - GstCaps* caps = NULL; - gchar* caps_str = NULL; - - MMPLAYER_FENTER(); - MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); - - caps = gst_pad_get_current_caps(pad); - caps_str = gst_caps_to_string(caps); - LOGD("deinterleave new caps : %s\n", caps_str); - MMPLAYER_FREEIF(caps_str); - gst_caps_unref(caps); - - if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) { - LOGE("ERROR : queue create error\n"); - goto ERROR; - } - - g_object_set(G_OBJECT(queue), - "max-size-buffers", 10, - "max-size-bytes", 0, - "max-size-time", (guint64)0, - NULL); - - selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst; - - if (!selector) { - LOGE("there is no audio channel selector.\n"); - goto ERROR; - } - - srcpad = gst_element_get_static_pad(queue, "src"); - sinkpad = gst_element_get_request_pad(selector, "sink_%u"); - - LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); - - if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { - LOGW("failed to link deinterleave - selector\n"); - goto ERROR; - } - - gst_element_set_state(queue, GST_STATE_PAUSED); - player->audio_mode.total_track_num++; - -ERROR: - - if (srcpad) { - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - } - - if (sinkpad) { - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; - } - - MMPLAYER_FLEAVE(); - return; -} + MMPLAYER_RETURN_IF_FAIL(attrs); -static void -__mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data) -{ - mm_player_t* player = NULL; - GstElement* selector = NULL; - GstPad* sinkpad = NULL; - gint active_index = 0; - gchar* change_pad_name = NULL; - GstCaps* caps = NULL; // no need to unref - gint default_audio_ch = 0; - - MMPLAYER_FENTER(); - player = (mm_player_t*) data; - - selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst; - - if (!selector) { - LOGE("there is no audio channel selector.\n"); - goto ERROR; - } - - active_index = player->audio_mode.active_pad_index; - - if (active_index != default_audio_ch) { - gint audio_ch = default_audio_ch; - - /*To get the new pad from the selector*/ - change_pad_name = g_strdup_printf("sink%d", active_index); - if (change_pad_name != NULL) { - sinkpad = gst_element_get_static_pad(selector, change_pad_name); - if (sinkpad != NULL) { - LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad)); - g_object_set(selector, "active-pad", sinkpad, NULL); - - audio_ch = active_index; - - caps = gst_pad_get_current_caps(sinkpad); - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - - __mmplayer_set_audio_attrs(player, caps); - gst_caps_unref(caps); - } - MMPLAYER_FREEIF(change_pad_name); - } - - player->audio_mode.active_pad_index = audio_ch; - LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index); - } - -ERROR: - - if (sinkpad) - gst_object_unref(sinkpad); - - MMPLAYER_FLEAVE(); - return; -} - -static void -__mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data) -{ - mm_player_t* player = NULL; - MMPlayerGstElement *mainbin = NULL; - - GstElement* tee = NULL; - GstElement* stereo_queue = NULL; - GstElement* mono_queue = NULL; - GstElement* conv = NULL; - GstElement* filter = NULL; - GstElement* deinterleave = NULL; - GstElement* selector = NULL; - - GstPad* srcpad = NULL; - GstPad* selector_srcpad = NULL; - GstPad* sinkpad = NULL; - GstCaps* caps = NULL; - gulong block_id = 0; - - MMPLAYER_FENTER(); - - /* check handles */ - player = (mm_player_t*) data; - - MMPLAYER_RETURN_IF_FAIL(elem && pad); - MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); - - mainbin = player->pipeline->mainbin; - - /* tee */ - if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) { - LOGE("ERROR : tee create error\n"); - goto ERROR; - } - - mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE; - mainbin[MMPLAYER_M_A_TEE].gst = tee; - - gst_element_set_state(tee, GST_STATE_PAUSED); - - /* queue */ - srcpad = gst_element_get_request_pad(tee, "src_%u"); - if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) { - LOGE("ERROR : stereo queue create error\n"); - goto ERROR; - } - - g_object_set(G_OBJECT(stereo_queue), - "max-size-buffers", 10, - "max-size-bytes", 0, - "max-size-time", (guint64)0, - NULL); - - player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1; - player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue; - - if (srcpad) { - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - } - - srcpad = gst_element_get_request_pad(tee, "src_%u"); - - if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) { - LOGE("ERROR : mono queue create error\n"); - goto ERROR; - } - - g_object_set(G_OBJECT(mono_queue), - "max-size-buffers", 10, - "max-size-bytes", 0, - "max-size-time", (guint64)0, - NULL); - - player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2; - player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue; - - gst_element_set_state(stereo_queue, GST_STATE_PAUSED); - gst_element_set_state(mono_queue, GST_STATE_PAUSED); - - /* audioconvert */ - srcpad = gst_element_get_static_pad(mono_queue, "src"); - if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) { - LOGE("ERROR : audioconvert create error\n"); - goto ERROR; - } - - player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV; - player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv; - - /* caps filter */ - if (srcpad) { - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - } - srcpad = gst_element_get_static_pad(conv, "src"); - - if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) { - LOGE("ERROR : capsfilter create error\n"); - goto ERROR; - } - - player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER; - player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter; - - caps = gst_caps_from_string("audio/x-raw-int, " - "width = (int) 16, " - "depth = (int) 16, " - "channels = (int) 2"); - - g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL); - gst_caps_unref(caps); - - gst_element_set_state(conv, GST_STATE_PAUSED); - gst_element_set_state(filter, GST_STATE_PAUSED); - - /* deinterleave */ - if (srcpad) { - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - } - srcpad = gst_element_get_static_pad(filter, "src"); - - if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) { - LOGE("ERROR : deinterleave create error\n"); - goto ERROR; - } - - g_object_set(deinterleave, "keep-positions", TRUE, NULL); - - MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player); - - MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", - G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player); - - player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE; - player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave; - - /* selector */ - selector = gst_element_factory_make("input-selector", "audio-channel-selector"); - if (selector == NULL) { - LOGE("ERROR : audio-selector create error\n"); - goto ERROR; - } - - g_object_set(selector, "sync-streams", TRUE, NULL); - gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector); - - player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR; - player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector; - - selector_srcpad = gst_element_get_static_pad(selector, "src"); - - LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad)); - block_id = - gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, - __mmplayer_gst_selector_blocked, NULL, NULL); - - if (srcpad) { - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - } - - srcpad = gst_element_get_static_pad(stereo_queue, "src"); - sinkpad = gst_element_get_request_pad(selector, "sink_%u"); - - if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { - LOGW("failed to link queue_stereo - selector\n"); - goto ERROR; - } - - player->audio_mode.total_track_num++; - - g_object_set(selector, "active-pad", sinkpad, NULL); - gst_element_set_state(deinterleave, GST_STATE_PAUSED); - gst_element_set_state(selector, GST_STATE_PAUSED); - - __mmplayer_gst_decode_callback(selector, selector_srcpad, player); - -ERROR: - - LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad)); - if (block_id != 0) { - gst_pad_remove_probe(selector_srcpad, block_id); - block_id = 0; - } - - if (sinkpad) { - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; - } - - if (srcpad) { - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - } - - if (selector_srcpad) { - gst_object_unref(GST_OBJECT(selector_srcpad)); - selector_srcpad = NULL; - } - - MMPLAYER_FLEAVE(); - return; -} - -static void -__mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data) -{ - mm_player_t* player = NULL; - GstPad* srcpad = NULL; - GstElement* video_selector = NULL; - GstElement* audio_selector = NULL; - GstElement* text_selector = NULL; - MMHandleType attrs = 0; - gint active_index = 0; - gint64 dur_bytes = 0L; - - player = (mm_player_t*) data; - - LOGD("no-more-pad signal handling\n"); - - if ((player->cmd == MMPLAYER_COMMAND_DESTROY) || - (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) { - LOGW("no need to go more"); - - if (player->gapless.reconfigure) { - player->gapless.reconfigure = FALSE; - MMPLAYER_PLAYBACK_UNLOCK(player); - } - - return; - } - - if ((!MMPLAYER_IS_HTTP_PD(player)) && - (MMPLAYER_IS_HTTP_STREAMING(player)) && - (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) && - (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) { - #define ESTIMATED_BUFFER_UNIT (1*1024*1024) - - if (NULL == player->streamer) { - LOGW("invalid state for buffering"); - goto ERROR; - } - - gint init_buffering_time = player->streamer->buffering_req.prebuffer_time; - guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT; - - buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes); - LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes); - - init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time); - - if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) - LOGE("fail to get duration.\n"); - - // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming - // use file information was already set on Q2 when it was created. - __mm_player_streaming_set_queue2(player->streamer, - player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, - TRUE, // use_buffering - buffer_bytes, - init_buffering_time, - 1.0, // low percent - player->ini.http_buffering_limit, // high percent - MUXED_BUFFER_TYPE_MEM_QUEUE, - NULL, - ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0)); - } - - video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst; - audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst; - text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst; - if (video_selector) { - // [link] input-selector :: videobin - srcpad = gst_element_get_static_pad(video_selector, "src"); - if (!srcpad) { - LOGE("failed to get srcpad from video selector\n"); - goto ERROR; - } - - LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad)); - if (!text_selector && !audio_selector) - player->no_more_pad = TRUE; - - __mmplayer_gst_decode_callback(video_selector, srcpad, player); - - LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); - if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) { - gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id); - player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0; - } - } - - if (audio_selector) { - active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index; - if ((active_index != DEFAULT_TRACK) && - (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) { - LOGW("failed to change audio track\n"); - player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK; - } - - // [link] input-selector :: audiobin - srcpad = gst_element_get_static_pad(audio_selector, "src"); - if (!srcpad) { - LOGE("failed to get srcpad from selector\n"); - goto ERROR; - } - - LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad)); - if (!text_selector) - player->no_more_pad = TRUE; - - if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) { - LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); - if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) { - gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id); - player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0; - } - - __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player); - } else { - __mmplayer_gst_decode_callback(audio_selector, srcpad, player); - - LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); - if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) { - gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id); - player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0; - } - } - - LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num); - - attrs = MMPLAYER_GET_ATTRS(player); - if (attrs) { - mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num); - if (mmf_attrs_commit(attrs)) - LOGE("failed to commit.\n"); - } else - LOGE("cannot get content attribute"); - } else { - if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) { - LOGD("There is no audio track : remove audiobin"); - - __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN); - __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst); - - MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN); - MMPLAYER_FREEIF(player->pipeline->audiobin); - } - - if (player->num_dynamic_pad == 0) - __mmplayer_pipeline_complete(NULL, player); - } - - if (!MMPLAYER_IS_MS_BUFF_SRC(player)) { - if (text_selector) - __mmplayer_handle_text_decode_path(player, text_selector); - } - - MMPLAYER_FLEAVE(); - -ERROR: - if (srcpad) { - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - } - - if (player->gapless.reconfigure) { - player->gapless.reconfigure = FALSE; - MMPLAYER_PLAYBACK_UNLOCK(player); - } -} - -static void -__mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) -{ - mm_player_t* player = NULL; - MMHandleType attrs = 0; - GstElement* pipeline = NULL; - GstCaps* caps = NULL; - gchar* caps_str = NULL; - GstStructure* str = NULL; - const gchar* name = NULL; - GstPad* sinkpad = NULL; - GstElement* sinkbin = NULL; - gboolean reusing = FALSE; - GstElement *text_selector = NULL; - - /* check handles */ - player = (mm_player_t*) data; - - MMPLAYER_RETURN_IF_FAIL(elem && pad); - MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); - - pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst; - - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("cannot get content attribute\n"); - goto ERROR; - } - - /* get mimetype from caps */ - caps = gst_pad_query_caps(pad, NULL); - if (!caps) { - LOGE("cannot get caps from pad.\n"); - goto ERROR; - } - caps_str = gst_caps_to_string(caps); - - str = gst_caps_get_structure(caps, 0); - if (!str) { - LOGE("cannot get structure from caps.\n"); - goto ERROR; - } - - name = gst_structure_get_name(str); - if (!name) { - LOGE("cannot get mimetype from structure.\n"); - goto ERROR; - } - - //LOGD("detected mimetype : %s\n", name); - - if (strstr(name, "audio")) { - if (player->pipeline->audiobin == NULL) { - if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) { - LOGE("failed to create audiobin. continuing without audio\n"); - goto ERROR; - } - - sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst; - LOGD("creating audiosink bin success\n"); - } else { - reusing = TRUE; - sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst; - LOGD("reusing audiobin\n"); - _mmplayer_update_content_attrs(player, ATTR_AUDIO); - } - - if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks - mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1); - - player->audiosink_linked = 1; - - sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink"); - if (!sinkpad) { - LOGE("failed to get pad from sinkbin\n"); - goto ERROR; - } - } else if (strstr(name, "video")) { - if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") || - strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32"))) - player->set_mode.video_zc = TRUE; - - if (player->pipeline->videobin == NULL) { - /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */ - /* get video surface type */ - int surface_type = 0; - mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type); - LOGD("display_surface_type(%d)\n", surface_type); - - if (surface_type == MM_DISPLAY_SURFACE_NULL) { - LOGD("not make videobin because it dose not want\n"); - goto ERROR; - } - - if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) { - /* mark video overlay for acquire */ - if (player->video_overlay_resource == NULL) { - 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\n"); - goto ERROR; - } - } - } - - player->interrupted_by_resource = FALSE; - /* acquire resources for video overlay */ - if (mm_resource_manager_commit(player->resource_manager) != - MM_RESOURCE_MANAGER_ERROR_NONE) { - LOGE("could not acquire resources for video playing\n"); - goto ERROR; - } - - if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) { - LOGE("failed to create videobin. continuing without video\n"); - goto ERROR; - } - - sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst; - LOGD("creating videosink bin success\n"); - } else { - reusing = TRUE; - sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst; - LOGD("re-using videobin\n"); - _mmplayer_update_content_attrs(player, ATTR_VIDEO); - } - - player->videosink_linked = 1; - - sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink"); - if (!sinkpad) { - LOGE("failed to get pad from sinkbin\n"); - goto ERROR; - } - } else if (strstr(name, "text")) { - if (player->pipeline->textbin == NULL) { - MMPlayerGstElement* mainbin = NULL; - - if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) { - LOGE("failed to create text sink bin. continuing without text\n"); - goto ERROR; - } - - sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst; - LOGD("creating textsink bin success\n"); - - /* FIXIT : track number shouldn't be hardcoded */ - mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1); - - player->textsink_linked = 1; - LOGI("player->textsink_linked set to 1\n"); - - sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink"); - if (!sinkpad) { - LOGE("failed to get pad from sinkbin\n"); - goto ERROR; - } - - mainbin = player->pipeline->mainbin; - - if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) { - /* input selector */ - text_selector = gst_element_factory_make("input-selector", "subtitle_inselector"); - if (!text_selector) { - LOGE("failed to create subtitle input selector element\n"); - goto ERROR; - } - g_object_set(text_selector, "sync-streams", TRUE, NULL); - - mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR; - mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector; - - /* warm up */ - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) { - LOGE("failed to set state(READY) to sinkbin\n"); - goto ERROR; - } - - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) { - LOGW("failed to add subtitle input selector\n"); - goto ERROR; - } - - LOGD("created element input-selector"); - - } else { - LOGD("already having subtitle input selector"); - text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst; - } - } else { - if (!player->textsink_linked) { - LOGD("re-using textbin\n"); - - reusing = TRUE; - sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst; - - player->textsink_linked = 1; - LOGI("player->textsink_linked set to 1\n"); - } else - LOGD("ignoring internal subtutle since external subtitle is available"); - } - } else { - LOGW("unknown type of elementary stream!ignoring it...\n"); - goto ERROR; - } - - if (sinkbin) { - if (!reusing) { - /* warm up */ - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) { - LOGE("failed to set state(READY) to sinkbin\n"); - goto ERROR; - } - - /* Added for multi audio support to avoid adding audio bin again*/ - /* add */ - if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) { - LOGE("failed to add sinkbin to pipeline\n"); - goto ERROR; - } - } - - /* link */ - if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) { - LOGE("failed to get pad from sinkbin\n"); - goto ERROR; - } - - if (!reusing) { - /* run */ - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) { - LOGE("failed to set state(PAUSED) to sinkbin\n"); - goto ERROR; - } - - if (text_selector) { - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) { - LOGE("failed to set state(PAUSED) to sinkbin\n"); - goto ERROR; - } - } - } - - gst_object_unref(sinkpad); - sinkpad = NULL; - } - - LOGD("[handle: %p] linking sink bin success", player); - - /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in - * streaming task. if the task blocked, then buffer will not flow to the next element - *(autoplugging element). so this is special hack for streaming. please try to remove it - */ - /* dec stream count. we can remove fakesink if it's zero */ - if (player->num_dynamic_pad) - player->num_dynamic_pad--; - - LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad); - - if ((player->no_more_pad) && (player->num_dynamic_pad == 0)) - __mmplayer_pipeline_complete(NULL, player); - -ERROR: - - MMPLAYER_FREEIF(caps_str); - - if (caps) - gst_caps_unref(caps); - - if (sinkpad) - gst_object_unref(GST_OBJECT(sinkpad)); - - /* flusing out new attributes */ - if (mmf_attrs_commit(attrs)) - LOGE("failed to comit attributes\n"); - - return; -} - -static gboolean -__mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value) -{ - int pro_value = 0; // in the case of expection, default will be returned. - int dest_angle = rotation_angle; - int rotation_type = -1; - - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE); - - if (rotation_angle >= 360) - dest_angle = rotation_angle - 360; - - /* chech if supported or not */ - if (dest_angle % 90) { - LOGD("not supported rotation angle = %d", rotation_angle); - return FALSE; - } - - /* - * tizenwlsink (A) - * custom_convert - none (B) - * videoflip - none (C) - */ - if (player->set_mode.video_zc) { - if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B - rotation_type = ROTATION_USING_CUSTOM; - else // A - rotation_type = ROTATION_USING_SINK; - } else { - int surface_type = 0; - rotation_type = ROTATION_USING_FLIP; - - mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type); - LOGD("check display surface type attribute: %d", surface_type); - - if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) - rotation_type = ROTATION_USING_SINK; - else - rotation_type = ROTATION_USING_FLIP; //C - - LOGD("using %d type for rotation", rotation_type); - } - - /* get property value for setting */ - switch (rotation_type) { - case ROTATION_USING_SINK: // tizenwlsink - { - switch (dest_angle) { - case 0: - break; - case 90: - pro_value = 3; // clockwise 90 - break; - case 180: - pro_value = 2; - break; - case 270: - pro_value = 1; // counter-clockwise 90 - break; - } - } - break; - case ROTATION_USING_CUSTOM: - { - gchar *ename = NULL; - ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst)); - - if (g_strrstr(ename, "fimcconvert")) { - switch (dest_angle) { - case 0: - break; - case 90: - pro_value = 90; // clockwise 90 - break; - case 180: - pro_value = 180; - break; - case 270: - pro_value = 270; // counter-clockwise 90 - break; - } - } - } - break; - case ROTATION_USING_FLIP: // videoflip - { - switch (dest_angle) { - case 0: - break; - case 90: - pro_value = 1; // clockwise 90 - break; - case 180: - pro_value = 2; - break; - case 270: - pro_value = 3; // counter-clockwise 90 - break; - } - } - break; - } - - LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type); - - *value = pro_value; - - return TRUE; -} - -int -__mmplayer_video_param_check_video_sink_bin(mm_player_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; -} - -void -__mmplayer_video_param_set_display_rotation(mm_player_t* player) -{ - int rotation_value = 0; - int org_angle = 0; // current supported angle values are 0, 90, 180, 270 - int user_angle = 0; - MMPLAYER_FENTER(); - - /* check video sinkbin is created */ - if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) - return; - - __mmplayer_get_video_angle(player, &user_angle, &org_angle); - - /* get rotation value to set */ - __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL); - LOGD("set video param : rotate %d", rotation_value); -} - -void -__mmplayer_video_param_set_display_visible(mm_player_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)) - return; - - attrs = MMPLAYER_GET_ATTRS(player); - MMPLAYER_RETURN_IF_FAIL(attrs); - - mm_attrs_get_int_by_name(attrs, "display_visible", &visible); - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL); - LOGD("set video param : visible %d", visible); -} - -void -__mmplayer_video_param_set_display_method(mm_player_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)) - return; - - attrs = MMPLAYER_GET_ATTRS(player); - MMPLAYER_RETURN_IF_FAIL(attrs); - - mm_attrs_get_int_by_name(attrs, "display_method", &display_method); - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL); - LOGD("set video param : method %d", display_method); -} - -void -__mmplayer_video_param_set_render_rectangle(mm_player_t* player) -{ - MMHandleType attrs = 0; - void *handle = NULL; - /*set wl_display*/ - int wl_window_x = 0; - int wl_window_y = 0; - int wl_window_width = 0; - int wl_window_height = 0; - MMPLAYER_FENTER(); - - /* check video sinkbin is created */ - if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) - return; - - attrs = MMPLAYER_GET_ATTRS(player); - MMPLAYER_RETURN_IF_FAIL(attrs); - - mm_attrs_get_data_by_name(attrs, "display_overlay", &handle); - - if (handle) { - /*It should be set after setting window*/ - mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x); - mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y); - mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width); - mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height); - - /* After setting window handle, set render rectangle */ - gst_video_overlay_set_render_rectangle( - GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst), - wl_window_x, wl_window_y, wl_window_width, wl_window_height); - LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)", - wl_window_x, wl_window_y, wl_window_width, wl_window_height); - - } -} -void -__mmplayer_video_param_set_display_overlay(mm_player_t* player) -{ - MMHandleType attrs = 0; - void *handle = NULL; - - /* check video sinkbin is created */ - if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) - 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 %p", wl_surface_id, *(int*)handle); - 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."); -} - - -int -__mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name) -{ - bool update_all_param = FALSE; - 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; - - if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) { - LOGE("can not find tizenwlsink"); - return MM_ERROR_PLAYER_INTERNAL; - } - - LOGD("param_name : %s", param_name); - if (!g_strcmp0(param_name, "update_all_param")) - update_all_param = TRUE; - - if (update_all_param || !g_strcmp0(param_name, "display_overlay")) - __mmplayer_video_param_set_display_overlay(player); - if (update_all_param || !g_strcmp0(param_name, "display_method")) - __mmplayer_video_param_set_display_method(player); - if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x")) - __mmplayer_video_param_set_render_rectangle(player); - if (update_all_param || !g_strcmp0(param_name, "display_visible")) - __mmplayer_video_param_set_display_visible(player); - if (update_all_param || !g_strcmp0(param_name, "display_rotation")) - __mmplayer_video_param_set_display_rotation(player); - - return MM_ERROR_NONE; -} - -int -_mmplayer_update_video_param(mm_player_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) -{ - gboolean disable_overlay = FALSE; - mm_player_t* player = (mm_player_t*) hplayer; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin && - player->pipeline->videobin[MMPLAYER_V_SINK].gst, - MM_ERROR_PLAYER_NO_OP); /* invalid op */ - - if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) { - LOGW("Display control is not supported"); - return MM_ERROR_PLAYER_INTERNAL; - } - - g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL); - - if (audio_only == (bool)disable_overlay) { - LOGE("It's the same with current setting: (%d)", audio_only); - return MM_ERROR_NONE; - } - - if (audio_only) { - LOGE("disable overlay"); - 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)\n", 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)\n", ret); - 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\n"); - 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\n"); - goto ERROR; - } - - LOGD("enable overlay"); - __mmplayer_video_param_set_display_overlay(player); - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL); - } - -ERROR: - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; -} - -int -_mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only) -{ - mm_player_t* player = (mm_player_t*) hplayer; - gboolean disable_overlay = FALSE; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT); - MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin && - player->pipeline->videobin[MMPLAYER_V_SINK].gst, - MM_ERROR_PLAYER_NO_OP); /* invalid op */ - - if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) { - LOGW("Display control is not supported"); - return MM_ERROR_PLAYER_INTERNAL; - } - - g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL); - - *paudio_only = (bool)(disable_overlay); - - LOGD("audio_only : %d", *paudio_only); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -static int -__mmplayer_gst_element_link_bucket(GList* element_bucket) -{ - GList* bucket = element_bucket; - MMPlayerGstElement* element = NULL; - MMPlayerGstElement* prv_element = NULL; - gint successful_link_count = 0; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1); - - prv_element = (MMPlayerGstElement*)bucket->data; - bucket = bucket->next; - - for (; bucket; bucket = bucket->next) { - element = (MMPlayerGstElement*)bucket->data; - - if (element && element->gst) { - /* If next element is audio appsrc then make a separate audio pipeline */ - if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") || - !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) { - prv_element = element; - continue; - } - - if (prv_element && prv_element->gst) { - if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) { - LOGD("linking [%s] to [%s] success\n", - GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)), - GST_ELEMENT_NAME(GST_ELEMENT(element->gst))); - successful_link_count++; - } else { - LOGD("linking [%s] to [%s] failed\n", - GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)), - GST_ELEMENT_NAME(GST_ELEMENT(element->gst))); - return -1; - } - } - } - - prv_element = element; - } - - MMPLAYER_FLEAVE(); - - return successful_link_count; -} - -static int -__mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) -{ - GList* bucket = element_bucket; - MMPlayerGstElement* element = NULL; - int successful_add_count = 0; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0); - MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0); - - for (; bucket; bucket = bucket->next) { - element = (MMPlayerGstElement*)bucket->data; - - 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\n", - GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), - GST_ELEMENT_NAME(GST_ELEMENT(bin))); - return 0; - } - successful_add_count++; - } - } - - MMPLAYER_FLEAVE(); - - return successful_add_count; -} - -static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data) -{ - mm_player_t* player = (mm_player_t*) data; - GstCaps *caps = NULL; - GstStructure *str = NULL; - const char *name; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_IF_FAIL(pad) - MMPLAYER_RETURN_IF_FAIL(unused) - MMPLAYER_RETURN_IF_FAIL(data) - - caps = gst_pad_get_current_caps(pad); - if (!caps) - return; - - str = gst_caps_get_structure(caps, 0); - if (!str) - goto ERROR; - - name = gst_structure_get_name(str); - if (!name) - goto ERROR; - - LOGD("name = %s\n", name); - - if (strstr(name, "audio")) { - _mmplayer_update_content_attrs(player, ATTR_AUDIO); - - if (player->audio_stream_changed_cb) { - LOGE("call the audio stream changed cb\n"); - player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param); - } - } else if (strstr(name, "video")) { - 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\n"); - player->video_stream_changed_cb(player->video_stream_changed_cb_user_param); - } - } else - goto ERROR; - -ERROR: - - gst_caps_unref(caps); - - MMPLAYER_FLEAVE(); - - 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_pipeline - */ -/* 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 \n", 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); - -static void -__mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all) -{ - GList *l = NULL; - - MMPLAYER_FENTER(); - MMPLAYER_RETURN_IF_FAIL(player); - - if (player->audio_stream_buff_list) { - for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) { - mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data; - if (tmp) { - if (send_all) { - LOGD("[%lld] send remained data.", tmp->channel_mask); - __mmplayer_audio_stream_send_data(player, tmp); - } - if (tmp->pcm_data) - g_free(tmp->pcm_data); - g_free(tmp); - } - } - g_list_free(player->audio_stream_buff_list); - player->audio_stream_buff_list = NULL; - } - - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer) -{ - MMPlayerAudioStreamDataType audio_stream = { 0, }; - - MMPLAYER_FENTER(); - MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex); - - 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("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */ - player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param); - - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data) -{ - mm_player_t* player = (mm_player_t*) data; - - gint channel = 0; - gint rate = 0; - gint depth = 0; - gint endianness = 0; - guint64 channel_mask = 0; - void *a_data = NULL; - gint a_size = 0; - mm_player_audio_stream_buff_t *a_buffer = NULL; - GstMapInfo mapinfo = GST_MAP_INFO_INIT; - GList *l = NULL; - - MMPLAYER_FENTER(); - MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex); - - gst_buffer_map(buffer, &mapinfo, GST_MAP_READ); - a_data = mapinfo.data; - a_size = mapinfo.size; - - GstCaps *caps = gst_pad_get_current_caps(pad); - GstStructure *structure = gst_caps_get_structure(caps, 0); - - /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */ - 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)); - - /* In case of the sync is false, use buffer list. * - * The num of buffer list depends on the num of audio channels */ - if (player->audio_stream_buff_list) { - for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) { - mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data; - if (tmp) { - if (channel_mask == tmp->channel_mask) { - /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */ - 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; - } else { - /* send data to client */ - __mmplayer_audio_stream_send_data(player, tmp); - - if (a_size > tmp->buff_size) { - LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size); - tmp->pcm_data = g_realloc(tmp->pcm_data, a_size); - if (tmp->pcm_data == NULL) { - LOGE("failed to realloc data."); - goto DONE; - } - tmp->buff_size = a_size; - } - memset(tmp->pcm_data, 0x00, tmp->buff_size); - memcpy(tmp->pcm_data, a_data, a_size); - tmp->data_size = a_size; - } - goto DONE; - } - } else { - LOGE("data is empty in list."); - goto DONE; - } - } - } - - /* create new audio stream data */ - a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t)); - if (a_buffer == NULL) { - LOGE("failed to alloc data."); - goto DONE; - } - a_buffer->bitrate = rate; - a_buffer->channel = channel; - a_buffer->depth = depth; - a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0); - a_buffer->channel_mask = channel_mask; - a_buffer->data_size = a_size; - - if (!player->audio_stream_sink_sync) { - /* If sync is FALSE, use buffer list to reduce the IPC. */ - a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size); - a_buffer->pcm_data = g_malloc(a_buffer->buff_size); - if (a_buffer->pcm_data == NULL) { - LOGE("failed to alloc data."); - g_free(a_buffer); - goto DONE; - } - memcpy(a_buffer->pcm_data, a_data, a_size); - /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */ - player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer); - } else { - /* If sync is TRUE, send data directly. */ - a_buffer->pcm_data = a_data; - __mmplayer_audio_stream_send_data(player, a_buffer); - g_free(a_buffer); - } - -DONE: - gst_buffer_unmap(buffer, &mapinfo); - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data) -{ - mm_player_t* player = (mm_player_t*)data; - MMPlayerGstElement* audiobin = player->pipeline->audiobin; - GstPad* sinkpad = NULL; - GstElement *queue = NULL, *sink = NULL; - - MMPLAYER_FENTER(); - MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); - - queue = gst_element_factory_make("queue", NULL); - if (queue == NULL) { - LOGD("fail make queue\n"); - goto ERROR; - } - - sink = gst_element_factory_make("fakesink", NULL); - if (sink == NULL) { - LOGD("fail make fakesink\n"); - goto ERROR; - } - - gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL); - - if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) { - LOGW("failed to link queue & sink\n"); - goto ERROR; - } - - sinkpad = gst_element_get_static_pad(queue, "sink"); - - if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) { - LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad)); - goto ERROR; - } - - LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync); - - gst_object_unref(sinkpad); - g_object_set(sink, "sync", player->audio_stream_sink_sync, 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); - - MMPLAYER_SIGNAL_CONNECT(player, - G_OBJECT(sink), - MM_PLAYER_SIGNAL_TYPE_AUDIOBIN, - "handoff", - G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb), - (gpointer)player); - - MMPLAYER_FLEAVE(); - return; - -ERROR: - LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n"); - if (queue) { - gst_object_unref(GST_OBJECT(queue)); - queue = NULL; - } - if (sink) { - gst_object_unref(GST_OBJECT(sink)); - sink = NULL; - } - if (sinkpad) { - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; - } - - return; -} - -void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs) -{ - #define MAX_PROPS_LEN 128 - gint latency_mode = 0; - gchar *stream_type = NULL; - gchar *latency = NULL; - gint stream_id = 0; - gchar stream_props[MAX_PROPS_LEN] = {0,}; - GstStructure *props = NULL; - - /* set volume table - * It should be set after player creation through attribute. - * But, it can not be changed during playing. - */ - MMPLAYER_FENTER(); - mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id); - mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type); - - if (!stream_type) { - LOGE("stream_type is null.\n"); - } else { - if (player->sound.focus_id) - snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d", - stream_type, stream_id, player->sound.focus_id); - 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], focus_id[%d], result[%s].\n", - stream_type, stream_id, player->sound.focus_id, stream_props); - gst_structure_free(props); - } - - mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode); - - switch (latency_mode) { - case AUDIO_LATENCY_MODE_LOW: - latency = g_strndup("low", 3); - break; - case AUDIO_LATENCY_MODE_MID: - latency = g_strndup("mid", 3); - break; - case AUDIO_LATENCY_MODE_HIGH: - latency = g_strndup("high", 4); - break; - }; - - g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, - "latency", latency, - NULL); - - LOGD("audiosink property - latency=%s \n", latency); - - g_free(latency); - - MMPLAYER_FLEAVE(); -} - -static int -__mmplayer_gst_create_audio_pipeline(mm_player_t* player) -{ - MMPlayerGstElement* first_element = NULL; - MMPlayerGstElement* audiobin = NULL; - MMHandleType attrs = 0; - GstPad *pad = NULL; - GstPad *ghostpad = NULL; - GList* element_bucket = NULL; - gboolean link_audio_sink_now = TRUE; - int i = 0; - GstCaps *acaps; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* alloc handles */ - audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM); - if (!audiobin) { - LOGE("failed to allocate memory for audiobin\n"); - return MM_ERROR_PLAYER_NO_FREE_SPACE; - } - - attrs = MMPLAYER_GET_ATTRS(player); - - /* create bin */ - audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN; - audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin"); - if (!audiobin[MMPLAYER_A_BIN].gst) { - LOGE("failed to create audiobin\n"); - goto ERROR; - } - - /* take it */ - player->pipeline->audiobin = audiobin; - - player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player); - - /* Adding audiotp plugin for reverse trickplay feature */ -// MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player); - - /* converter */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player); - - /* replaygain volume */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, 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); - - if (player->set_mode.pcm_extraction) { - // pcm extraction only and no sound output - if (player->audio_stream_render_cb_ex) { - char *caps_str = NULL; - GstCaps* caps = NULL; - gchar *format = NULL; - - /* capsfilter */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player); - - mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format); - - LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel); - - caps = gst_caps_new_simple("audio/x-raw", - "format", G_TYPE_STRING, format, - "rate", G_TYPE_INT, player->pcm_samplerate, - "channels", G_TYPE_INT, player->pcm_channel, - NULL); - caps_str = gst_caps_to_string(caps); - LOGD("new caps : %s\n", caps_str); - - g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL); - - /* clean */ - gst_caps_unref(caps); - MMPLAYER_FREEIF(caps_str); - - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player); - - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL); - /* raw pad handling signal */ - MMPLAYER_SIGNAL_CONNECT(player, - (audiobin[MMPLAYER_A_DEINTERLEAVE].gst), - MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player); - } else { - int dst_samplerate = 0; - int dst_channels = 0; - int dst_depth = 0; - char *caps_str = NULL; - GstCaps* caps = NULL; - - /* get conf. values */ - mm_attrs_multiple_get(player->attrs, - NULL, - "pcm_extraction_samplerate", &dst_samplerate, - "pcm_extraction_channels", &dst_channels, - "pcm_extraction_depth", &dst_depth, - NULL); - - /* capsfilter */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player); - caps = gst_caps_new_simple("audio/x-raw", - "rate", G_TYPE_INT, dst_samplerate, - "channels", G_TYPE_INT, dst_channels, - "depth", G_TYPE_INT, dst_depth, - NULL); - caps_str = gst_caps_to_string(caps); - LOGD("new caps : %s\n", caps_str); - - g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL); - - /* clean */ - gst_caps_unref(caps); - MMPLAYER_FREEIF(caps_str); - - /* fake sink */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player); - - /* set sync */ - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL); - } - } else { - // normal playback - //GstCaps* caps = NULL; - gint channels = 0; - - /* 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 (player->sound.mute) { - LOGD("mute enabled\n"); - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL); - } - -#if 0 - /*capsfilter */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player); - caps = gst_caps_from_string("audio/x-raw-int, " - "endianness = (int) LITTLE_ENDIAN, " - "signed = (boolean) true, " - "width = (int) 16, " - "depth = (int) 16"); - g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL); - gst_caps_unref(caps); -#endif - - /* check if multi-channels */ - if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) { - GstPad *srcpad = NULL; - GstCaps *caps = NULL; - - if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) { - if ((caps = gst_pad_query_caps(srcpad, NULL))) { - //MMPLAYER_LOG_GST_CAPS_TYPE(caps); - GstStructure *str = gst_caps_get_structure(caps, 0); - if (str) - gst_structure_get_int(str, "channels", &channels); - gst_caps_unref(caps); - } - gst_object_unref(srcpad); - } - } - - /* 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); - - LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type); - - if ((!player->bypass_audio_effect) - && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) { - if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) { - if (!_mmplayer_audio_effect_custom_apply(player)) - LOGI("apply audio effect(custom) setting success\n"); - } - } - - 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); - } - - /* 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); - - /* 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) { - - strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1); - - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player); - - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, 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); - - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player); - 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); - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL); - - player->is_openal_plugin_used = TRUE; - - if (player->video360_yaw_radians <= M_PI && - player->video360_yaw_radians >= -M_PI && - player->video360_pitch_radians <= M_PI_2 && - player->video360_pitch_radians >= -M_PI_2) { - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), - "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI), - "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL); - } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) { - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), - "source-orientation-y", player->video360_metadata.init_view_heading, - "source-orientation-x", player->video360_metadata.init_view_pitch, NULL); - } - } 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.\n"); - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player); - } - - /* 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); - - - if ((MMPLAYER_IS_RTSP_STREAMING(player)) || - (player->videodec_linked && player->ini.use_system_clock)) { - LOGD("system clock will be used.\n"); - g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL); - } - - if (g_strrstr(player->ini.audiosink_element, "pulsesink")) - __mmplayer_gst_set_audiosink_property(player, attrs); - } - - if (audiobin[MMPLAYER_A_SINK].gst) { - GstPad *sink_pad = NULL; - sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink"); - MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN, - "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player); - gst_object_unref(GST_OBJECT(sink_pad)); - } - - __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst); - - /* adding created elements to bin */ - LOGD("adding created elements to bin\n"); - if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) { - LOGE("failed to add elements\n"); - goto ERROR; - } - - /* linking elements in the bucket by added order. */ - LOGD("Linking elements in the bucket by added order.\n"); - if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) { - LOGE("failed to link elements\n"); - goto ERROR; - } - - /* get first element's sinkpad for creating ghostpad */ - first_element = (MMPlayerGstElement *)element_bucket->data; - if (!first_element) { - LOGE("failed to get first elem\n"); - goto ERROR; - } - - pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); - if (!pad) { - LOGE("failed to get pad from first element of audiobin\n"); - goto ERROR; - } - - ghostpad = gst_ghost_pad_new("sink", pad); - if (!ghostpad) { - LOGE("failed to create ghostpad\n"); - goto ERROR; - } - - if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) { - LOGE("failed to add ghostpad to audiobin\n"); - goto ERROR; - } - - gst_object_unref(pad); - - g_list_free(element_bucket); - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; - -ERROR: - - LOGD("ERROR : releasing audiobin\n"); - - if (pad) - gst_object_unref(GST_OBJECT(pad)); - - if (ghostpad) - gst_object_unref(GST_OBJECT(ghostpad)); - - if (element_bucket) - g_list_free(element_bucket); - - /* release element which are not added to bin */ - for (i = 1; i < MMPLAYER_A_NUM; i++) { - /* NOTE : skip bin */ - if (audiobin[i].gst) { - GstObject* parent = NULL; - parent = gst_element_get_parent(audiobin[i].gst); - - if (!parent) { - gst_object_unref(GST_OBJECT(audiobin[i].gst)); - audiobin[i].gst = NULL; - } else - gst_object_unref(GST_OBJECT(parent)); - } - } - - /* release audiobin with it's childs */ - if (audiobin[MMPLAYER_A_BIN].gst) - gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst)); - - MMPLAYER_FREEIF(audiobin); - - player->pipeline->audiobin = NULL; - - return MM_ERROR_PLAYER_INTERNAL; -} - -static GstPadProbeReturn -__mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) -{ - mm_player_t* player = (mm_player_t*) u_data; - GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info); - GstMapInfo probe_info = GST_MAP_INFO_INIT; - - gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ); - - if (player->audio_stream_cb && probe_info.size && probe_info.data) - player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param); - - return GST_PAD_PROBE_OK; -} - -static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name) -{ - return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24); -} - -int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo) -{ - int ret = MM_ERROR_NONE; - GList *l = NULL; - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT); - - MMPLAYER_VIDEO_BO_LOCK(player); - - if (player->video_bo_list) { - for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) { - mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data; - if (tmp && tmp->bo == bo) { - tmp->using = FALSE; - LOGD("release bo %p", bo); - tbm_bo_unref(tmp->bo); - MMPLAYER_VIDEO_BO_UNLOCK(player); - MMPLAYER_VIDEO_BO_SIGNAL(player); - return ret; - } - } - } else { - /* hw codec is running or the list was reset for DRC. */ - LOGW("there is no bo list."); - } - MMPLAYER_VIDEO_BO_UNLOCK(player); - - LOGW("failed to find bo %p", bo); - return ret; -} - -static void -__mmplayer_video_stream_destroy_bo_list(mm_player_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)) { - mm_player_video_bo_info_t* tmp = (mm_player_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); - player->video_bo_list = NULL; - } - player->video_bo_size = 0; - MMPLAYER_VIDEO_BO_UNLOCK(player); - - MMPLAYER_FLEAVE(); - return; -} - -static void* -__mmplayer_video_stream_get_bo(mm_player_t* player, int size) -{ - GList *l = NULL; - MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL); - gboolean ret = TRUE; - - /* check DRC, if it is, destroy the prev bo list to create again */ - if (player->video_bo_size != size) { - LOGD("video size is changed: %d -> %d", player->video_bo_size, size); - __mmplayer_video_stream_destroy_bo_list(player); - player->video_bo_size = size; - } - - MMPLAYER_VIDEO_BO_LOCK(player); - - if ((!player->video_bo_list) || - (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) { - - /* create bo list */ - int idx = 0; - LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo); - - if (player->video_bo_list) { - /* if bo list did not created all, try it again. */ - idx = g_list_length(player->video_bo_list); - LOGD("bo list exist(len: %d)", idx); - } - - for (; idx < player->ini.num_of_video_bo; idx++) { - mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1); - if (!bo_info) { - LOGE("Fail to alloc bo_info."); - break; - } - bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT); - if (!bo_info->bo) { - LOGE("Fail to tbm_bo_alloc."); - g_free(bo_info); - break; - } - bo_info->using = FALSE; - player->video_bo_list = g_list_append(player->video_bo_list, bo_info); - } - - /* 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; + mm_attrs_get_int_by_name(attrs, "display_method", &display_method); + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL); + LOGD("set video param : method %d", display_method); +} - if (idx == 0) { - MMPLAYER_VIDEO_BO_UNLOCK(player); - return NULL; - } +void +__mmplayer_video_param_set_video_roi_area(mmplayer_t *player) +{ + MMHandleType attrs = 0; + void *handle = NULL; + MMPLAYER_FENTER(); - LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers); + /* check video sinkbin is created */ + if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) { + LOGW("There is no video sink"); + return; } - while (TRUE) { - /* get bo from list*/ - for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) { - mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data; - if (tmp && (tmp->using == FALSE)) { - LOGD("found bo %p to use", tmp->bo); - tmp->using = TRUE; - MMPLAYER_VIDEO_BO_UNLOCK(player); - return tbm_bo_ref(tmp->bo); - } - } - if (!ret) { - LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout); - MMPLAYER_VIDEO_BO_UNLOCK(player); - return NULL; - } - - if (player->ini.video_bo_timeout <= 0) { - MMPLAYER_VIDEO_BO_WAIT(player); - } else { - gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND; - ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout); - } - continue; + 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); } } -static void -__mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data) +void +__mmplayer_video_param_set_roi_area(mmplayer_t *player) { - mm_player_t* player = (mm_player_t*)data; + MMHandleType attrs = 0; + void *handle = NULL; + /*set wl_display*/ + int win_roi_x = 0; + int win_roi_y = 0; + int win_roi_width = 0; + int win_roi_height = 0; MMPLAYER_FENTER(); - MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb); - /* send prerolled pkt */ - player->video_stream_prerolled = FALSE; + /* check video sinkbin is created */ + if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) { + LOGW("There is no video sink"); + return; + } - __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data); + attrs = MMPLAYER_GET_ATTRS(player); + MMPLAYER_RETURN_IF_FAIL(attrs); - /* not to send prerolled pkt again */ - player->video_stream_prerolled = TRUE; + mm_attrs_get_data_by_name(attrs, "display_overlay", &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); + + /* 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); + } } -static void -__mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data) +void +__mmplayer_video_param_set_display_overlay(mmplayer_t *player) { - mm_player_t* player = (mm_player_t*)data; - GstCaps *caps = NULL; - MMPlayerVideoStreamDataType *stream = NULL; - MMVideoBuffer *video_buffer = NULL; - GstMemory *dataBlock = NULL; - GstMemory *metaBlock = NULL; - GstMapInfo mapinfo = GST_MAP_INFO_INIT; - GstStructure *structure = NULL; - const gchar *string_format = NULL; - unsigned int fourcc = 0; - - MMPLAYER_FENTER(); - MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb); + MMHandleType attrs = 0; + void *handle = NULL; - if (player->video_stream_prerolled) { - player->video_stream_prerolled = FALSE; - LOGD("skip the prerolled pkt not to send it again"); + /* check video sinkbin is created */ + if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) return; - } - caps = gst_pad_get_current_caps(pad); - if (caps == NULL) { - LOGE("Caps is NULL."); - 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."); } +} - /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */ +int +__mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name) +{ + gboolean update_all_param = FALSE; + MMPLAYER_FENTER(); - /* clear stream data structure */ - stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType)); - if (!stream) { - LOGE("failed to alloc mem for video data"); - return; + /* check video sinkbin is created */ + if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player)) + return MM_ERROR_PLAYER_NOT_INITIALIZED; + + if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) { + LOGE("can not find tizenwlsink"); + return MM_ERROR_PLAYER_INTERNAL; } - structure = gst_caps_get_structure(caps, 0); - gst_structure_get_int(structure, "width", &(stream->width)); - gst_structure_get_int(structure, "height", &(stream->height)); - string_format = gst_structure_get_string(structure, "format"); - if (string_format) - fourcc = _mmplayer_convert_fourcc_string_to_value(string_format); - stream->format = util_get_pixtype(fourcc); - gst_caps_unref(caps); - caps = NULL; + LOGD("param_name : %s", param_name); + if (!g_strcmp0(param_name, "update_all_param")) + update_all_param = TRUE; - __mmplayer_get_video_angle(player, NULL, &stream->orientation); + if (update_all_param || !g_strcmp0(param_name, "display_overlay")) + __mmplayer_video_param_set_display_overlay(player); + if (update_all_param || !g_strcmp0(param_name, "display_method")) + __mmplayer_video_param_set_display_method(player); + if (update_all_param || !g_strcmp0(param_name, "display_visible")) + __mmplayer_video_param_set_display_visible(player); + if (update_all_param || !g_strcmp0(param_name, "display_rotation")) + __mmplayer_video_param_set_display_rotation(player); + if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x")) + __mmplayer_video_param_set_roi_area(player); + if (update_all_param) + __mmplayer_video_param_set_video_roi_area(player); - /* - LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]", - GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format); - */ + return MM_ERROR_NONE; +} - if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) { - LOGE("Wrong condition!!"); - goto ERROR; +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); - /* set size and timestamp */ - dataBlock = gst_buffer_peek_memory(buffer, 0); - stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL); - stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */ + /* update display surface */ + mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type); + LOGD("check display surface type attribute: %d", surface_type); - /* check zero-copy */ - if (player->set_mode.video_zc && - player->set_mode.media_packet_video_stream && - gst_buffer_n_memory(buffer) > 1) { - metaBlock = gst_buffer_peek_memory(buffer, 1); - gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ); - video_buffer = (MMVideoBuffer *)mapinfo.data; - } - - if (video_buffer) { /* hw codec */ - /* set tbm bo */ - if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) { - int i = 0; - - /* copy pointer of tbm bo, stride, elevation */ - while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) { - stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]); - i++; - } - } else { - LOGE("Not support video buffer format"); - goto ERROR; + /* 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; } - memcpy(stream->stride, video_buffer->stride_width, - sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX); - memcpy(stream->elevation, video_buffer->stride_height, - sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX); + break; + } - /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */ - stream->internal_buffer = gst_buffer_ref(buffer); - } else { /* sw codec */ - int i = 0; - int j = 0; - int k = 0; - int ret = TBM_SURFACE_ERROR_NONE; - int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, }; - int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, }; - int size = 0; - unsigned char *src = NULL; - unsigned char *dest = NULL; - tbm_bo_handle thandle; - tbm_surface_h surface; - tbm_surface_info_s info; - gboolean gst_ret; + MMPLAYER_FLEAVE(); - gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE); - if (!gst_ret) { - LOGE("fail to gst_memory_map"); - goto ERROR; - } + return MM_ERROR_NONE; +} + +int +_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); + MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin && + player->pipeline->videobin[MMPLAYER_V_SINK].gst, + MM_ERROR_PLAYER_NO_OP); /* invalid op */ + + if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) { + LOGW("Display control is not supported"); + return MM_ERROR_PLAYER_INTERNAL; + } + g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL); - if (stream->format == MM_PIXEL_FORMAT_I420) { - surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420); + if (audio_only == (bool)disable_overlay) { + LOGE("It's the same with current setting: (%d)", audio_only); + return MM_ERROR_NONE; + } - ret = tbm_surface_get_info(surface, &info); + if (audio_only) { + LOGE("disable overlay"); + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL); - if (ret != TBM_SURFACE_ERROR_NONE) { - tbm_surface_destroy(surface); + /* 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; } - tbm_surface_destroy(surface); - - src_stride[0] = GST_ROUND_UP_4(stream->width); - src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1); - src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height); - src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1)); - stream->stride[0] = info.planes[0].stride; - stream->elevation[0] = info.planes[0].size / info.planes[0].stride; - stream->stride[1] = info.planes[1].stride; - stream->elevation[1] = info.planes[1].size / info.planes[1].stride; - stream->stride[2] = info.planes[2].stride; - stream->elevation[2] = info.planes[2].size / info.planes[2].stride; - size = info.planes[0].size + info.planes[1].size + info.planes[2].size; - } else if (stream->format == MM_PIXEL_FORMAT_RGBA) { - stream->stride[0] = stream->width * 4; - stream->elevation[0] = stream->height; - size = stream->stride[0] * stream->height; - } else { - LOGE("Not support format %d", stream->format); - goto ERROR; + player->video_overlay_resource = NULL; } - stream->bo[0] = __mmplayer_video_stream_get_bo(player, size); - if (!stream->bo[0]) { - LOGE("Fail to tbm_bo_alloc!!"); + 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); goto ERROR; } - - thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE); - if (thandle.ptr && mapinfo.data) { - if (stream->format == MM_PIXEL_FORMAT_I420) { - for (i = 0; i < 3; i++) { - src = mapinfo.data + src_offset[i]; - dest = thandle.ptr + info.planes[i].offset; - - if (i > 0) k = 1; - for (j = 0; j < stream->height>>k; j++) { - memcpy(dest, src, stream->width>>k); - src += src_stride[i]; - dest += stream->stride[i]; - } - } - } else if (stream->format == MM_PIXEL_FORMAT_RGBA) { - memcpy(thandle.ptr, mapinfo.data, size); - } else { - LOGE("Not support format %d", stream->format); + } 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; } - } else { - LOGE("data pointer is wrong. dest : %p, src : %p", - thandle.ptr, mapinfo.data); - goto ERROR; } - tbm_bo_unmap(stream->bo[0]); - } - if (player->video_stream_cb) { /* This has been already checked at the entry */ - if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) { - LOGE("failed to send video stream data."); + 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"); goto ERROR; } - } - - if (metaBlock) - gst_memory_unmap(metaBlock, &mapinfo); - else - gst_memory_unmap(dataBlock, &mapinfo); - - return; - -ERROR: - LOGE("release video stream resource."); - if (metaBlock) { - int i = 0; - for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) { - if (stream->bo[i]) - tbm_bo_unref(stream->bo[i]); - } - gst_memory_unmap(metaBlock, &mapinfo); - /* unref gst buffer */ - if (stream->internal_buffer) - gst_buffer_unref(stream->internal_buffer); - } else if (dataBlock) { - if (stream->bo[0]) - _mmplayer_video_stream_release_bo(player, stream->bo[0]); - gst_memory_unmap(dataBlock, &mapinfo); + LOGD("enable overlay"); + __mmplayer_video_param_set_display_overlay(player); + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL); } - g_free(stream); - return; +ERROR: + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; } -static int -__mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket) +int +_mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only) { - gchar* video_csc = "videoconvert"; /* default colorspace converter */ - GList* element_bucket = NULL; - - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED); + mmplayer_t *player = (mmplayer_t *)hplayer; + gboolean disable_overlay = FALSE; MMPLAYER_FENTER(); - if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) { - LOGD("do not need to add video filters."); - return MM_ERROR_NONE; - } + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT); + MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin && + player->pipeline->videobin[MMPLAYER_V_SINK].gst, + MM_ERROR_PLAYER_NO_OP); /* invalid op */ - /* in case of sw codec except 360 playback, - * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */ - MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player); - LOGD("using video converter: %s", video_csc); + if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) { + LOGW("Display control is not supported"); + return MM_ERROR_PLAYER_INTERNAL; + } - /* set video rotator */ - MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player); + g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL); - *bucket = element_bucket; - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; + *paudio_only = (bool)disable_overlay; -ERROR: /* refer MMPLAYER_CREATE_ELEMENT */ - g_list_free(element_bucket); + LOGD("audio_only : %d", *paudio_only); - *bucket = NULL; MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; + + return MM_ERROR_NONE; } -/** - * This function is to create video pipeline. - * - * @param player [in] handle of player - * caps [in] src caps of decoder - * surface_type [in] surface type for video rendering - * - * @return This function returns zero on success. - * @remark - * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline - */ -/** - * VIDEO PIPELINE - * - video overlay surface(arm/x86) : tizenwlsink - */ -static int -__mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type) +int +__mmplayer_gst_element_link_bucket(GList *element_bucket) { - GstPad *pad = NULL; - MMHandleType attrs; - GList*element_bucket = NULL; - MMPlayerGstElement* first_element = NULL; - MMPlayerGstElement* videobin = NULL; - gchar *videosink_element = NULL; + 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(); - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1); - /* alloc handles */ - videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM); - if (!videobin) - return MM_ERROR_PLAYER_NO_FREE_SPACE; + prv_element = (mmplayer_gst_element_t *)bucket->data; + bucket = bucket->next; - player->pipeline->videobin = videobin; + for (; bucket; bucket = bucket->next) { + element = (mmplayer_gst_element_t *)bucket->data; - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("cannot get content attribute"); - return MM_ERROR_PLAYER_INTERNAL; - } + 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)), + GST_ELEMENT_NAME(GST_ELEMENT(element->gst))); + return -1; + } + } + } - /* create bin */ - videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN; - videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin"); - if (!videobin[MMPLAYER_V_BIN].gst) { - LOGE("failed to create videobin"); - goto ERROR; + prv_element = element; } - int enable_video_decoded_cb = 0; - mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb); + MMPLAYER_FLEAVE(); - if (player->is_360_feature_enabled && player->is_content_spherical) { - LOGD("video360 elem will be added."); + return successful_link_count; +} - MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360", - "video-360", TRUE, player); +int +__mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket) +{ + GList *bucket = element_bucket; + mmplayer_gst_element_t *element = NULL; + int successful_add_count = 0; - /* Set spatial media metadata and/or user settings to the element. - * */ - g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), - "projection-type", player->video360_metadata.projection_type, NULL); + MMPLAYER_FENTER(); - g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), - "stereo-mode", player->video360_metadata.stereo_mode, NULL); - - if (player->video360_metadata.full_pano_width_pixels && - player->video360_metadata.full_pano_height_pixels && - player->video360_metadata.cropped_area_image_width && - player->video360_metadata.cropped_area_image_height) { - g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), - "projection-bounds-top", player->video360_metadata.cropped_area_top, - "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels - - player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height, - "projection-bounds-left", player->video360_metadata.cropped_area_left, - "projection-bounds-right", player->video360_metadata.full_pano_width_pixels - - player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width, - NULL); - } + MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0); + MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0); - if (player->video360_horizontal_fov && player->video360_vertical_fov) { - g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), - "horizontal-fov", player->video360_horizontal_fov, - "vertical-fov", player->video360_vertical_fov, NULL); - } + for (; bucket; bucket = bucket->next) { + element = (mmplayer_gst_element_t *)bucket->data; - if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) { - g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), - "zoom", 1.0f / player->video360_zoom, NULL); + 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", + GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), + GST_ELEMENT_NAME(GST_ELEMENT(bin))); + return 0; + } + successful_add_count++; } + } - if (player->video360_yaw_radians <= M_PI && - player->video360_yaw_radians >= -M_PI && - player->video360_pitch_radians <= M_PI_2 && - player->video360_pitch_radians >= -M_PI_2) { - g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), - "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI), - "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL); - } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) { - g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), - "pose-yaw", player->video360_metadata.init_view_heading, - "pose-pitch", player->video360_metadata.init_view_pitch, NULL); - } + MMPLAYER_FLEAVE(); - g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), - "passthrough", !player->is_video360_enabled, NULL); - } + return successful_add_count; +} - /* set video sink */ - switch (surface_type) { - case MM_DISPLAY_SURFACE_OVERLAY: - if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE) - goto ERROR; - if (strlen(player->ini.videosink_element_overlay) > 0) - videosink_element = player->ini.videosink_element_overlay; - else - goto ERROR; - break; - case MM_DISPLAY_SURFACE_NULL: - if (strlen(player->ini.videosink_element_fake) > 0) - videosink_element = player->ini.videosink_element_fake; - else - goto ERROR; - break; - case MM_DISPLAY_SURFACE_REMOTE: - if (strlen(player->ini.videosink_element_fake) > 0) - videosink_element = player->ini.videosink_element_fake; - else - goto ERROR; - break; - default: - LOGE("unidentified surface type"); - goto ERROR; - } - LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element); +static void +__mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data) +{ + mmplayer_t *player = (mmplayer_t *)data; + GstCaps *caps = NULL; + GstStructure *str = NULL; + const char *name; + gboolean caps_ret = TRUE; - MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player); + MMPLAYER_FENTER(); - /* additional setting for sink plug-in */ - switch (surface_type) { - case MM_DISPLAY_SURFACE_OVERLAY: - { - bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)); - if (!use_tbm) { - LOGD("selected videosink name: %s", videosink_element); + MMPLAYER_RETURN_IF_FAIL(pad); + MMPLAYER_RETURN_IF_FAIL(unused); + MMPLAYER_RETURN_IF_FAIL(data); - /* support shard memory with S/W codec on HawkP */ - if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) { - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, - "use-tbm", use_tbm, NULL); - } - } else { - if (attrs) { - int gapless = 0; + caps = gst_pad_get_current_caps(pad); + if (!caps) + return; + + MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret); + if (!caps_ret) + goto ERROR; - mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless); + LOGD("name = %s", name); - if (gapless > 0) { - LOGD("disable last-sample"); - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL); - } - } - } - if (player->set_mode.media_packet_video_stream) { - int enable = 0; - mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable); - if (enable) - g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL); - - MMPLAYER_SIGNAL_CONNECT(player, - G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), - MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, - "handoff", - G_CALLBACK(__mmplayer_video_stream_decoded_render_cb), - (gpointer)player); - - MMPLAYER_SIGNAL_CONNECT(player, - G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), - MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, - "preroll-handoff", - G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb), - (gpointer)player); + if (strstr(name, "audio")) { + __mmplayer_update_content_attrs(player, ATTR_AUDIO); + + if (player->audio_stream_changed_cb) { + LOGE("call the audio stream changed cb"); + player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param); } - break; - } - case MM_DISPLAY_SURFACE_REMOTE: - { - if (player->set_mode.media_packet_video_stream) { - LOGE("add data probe at videosink"); - g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), - "sync", TRUE, "signal-handoffs", TRUE, NULL); - - MMPLAYER_SIGNAL_CONNECT(player, - G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), - MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, - "handoff", - G_CALLBACK(__mmplayer_video_stream_decoded_render_cb), - (gpointer)player); - - MMPLAYER_SIGNAL_CONNECT(player, - G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), - MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, - "preroll-handoff", - G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb), - (gpointer)player); - if (attrs) { - int gapless = 0; + } else if (strstr(name, "video")) { + if ((name = gst_structure_get_string(str, "format"))) + player->set_mode.video_zc = name[0] == 'S'; - mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless); + __mmplayer_update_content_attrs(player, ATTR_VIDEO); - if (gapless > 0) { - LOGD("disable last-sample"); - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL); - } - } + 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); } - break; - } - default: - break; + } else { + LOGW("invalid caps info"); } - if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE) - goto ERROR; +ERROR: + if (caps) + gst_caps_unref(caps); - 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_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, - "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player); - gst_object_unref(GST_OBJECT(sink_pad)); - } else - LOGW("failed to get sink pad from videosink\n"); - } + MMPLAYER_FLEAVE(); - /* store it as it's sink element */ - __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst); + return; +} - /* adding created elements to bin */ - if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) { - LOGE("failed to add elements\n"); - goto ERROR; - } +void +__mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all) +{ + GList *l = NULL; - /* Linking elements in the bucket by added order */ - if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) { - LOGE("failed to link elements\n"); - goto ERROR; - } + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player); - /* get first element's sinkpad for creating ghostpad */ - if (element_bucket) - first_element = (MMPlayerGstElement *)element_bucket->data; - if (!first_element) { - LOGE("failed to get first element from bucket\n"); - goto ERROR; + if (player->audio_stream_buff_list) { + for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) { + mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data; + if (tmp) { + if (send_all) { + LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask); + __mmplayer_audio_stream_send_data(player, tmp); + } + MMPLAYER_FREEIF(tmp->pcm_data); + MMPLAYER_FREEIF(tmp); + } + } + g_list_free(player->audio_stream_buff_list); + player->audio_stream_buff_list = NULL; } - pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); - if (!pad) { - LOGE("failed to get pad from first element\n"); - goto ERROR; - } + MMPLAYER_FLEAVE(); +} - /* create ghostpad */ - player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad); - if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) { - LOGE("failed to add ghostpad to videobin\n"); - goto ERROR; - } - gst_object_unref(pad); +static void +__mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer) +{ + mmplayer_audio_decoded_data_info_t audio_stream = { 0, }; - /* done. free allocated variables */ - if (element_bucket) - g_list_free(element_bucket); + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb); + + 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; + audio_stream.pcm_format = a_buffer->pcm_format; + + /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */ + player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param); MMPLAYER_FLEAVE(); +} + +static void +__mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data) +{ + mmplayer_t *player = (mmplayer_t *)data; + 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; + mmplayer_audio_stream_buff_t *a_buffer = NULL; + GstMapInfo mapinfo = GST_MAP_INFO_INIT; + GList *l = NULL; - return MM_ERROR_NONE; + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb); -ERROR: - LOGE("ERROR : releasing videobin\n"); + gst_buffer_map(buffer, &mapinfo, GST_MAP_READ); + a_data = mapinfo.data; + a_size = mapinfo.size; - g_list_free(element_bucket); + GstCaps *caps = gst_pad_get_current_caps(pad); + GstStructure *structure = gst_caps_get_structure(caps, 0); - if (pad) - gst_object_unref(GST_OBJECT(pad)); + /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */ + 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)); - /* release videobin with it's childs */ - if (videobin[MMPLAYER_V_BIN].gst) - gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst)); + /* In case of the sync is false, use buffer list. * + * The num of buffer list depends on the num of audio channels */ + if (player->audio_stream_buff_list) { + for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) { + 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); */ + 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; + } else { + /* send data to client */ + __mmplayer_audio_stream_send_data(player, tmp); + if (a_size > tmp->buff_size) { + LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size); + tmp->pcm_data = g_realloc(tmp->pcm_data, a_size); + if (tmp->pcm_data == NULL) { + LOGE("failed to realloc data."); + goto DONE; + } + tmp->buff_size = a_size; + } + memset(tmp->pcm_data, 0x00, tmp->buff_size); + memcpy(tmp->pcm_data, a_data, a_size); + tmp->data_size = a_size; + } + goto DONE; + } + } else { + LOGE("data is empty in list."); + goto DONE; + } + } + } - MMPLAYER_FREEIF(videobin); + /* 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."); + goto DONE; + } + 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); - player->pipeline->videobin = NULL; + if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) { + /* If sync is FALSE, use buffer list to reduce the IPC. */ + a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size); + a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size); + if (a_buffer->pcm_data == NULL) { + LOGE("failed to alloc data."); + MMPLAYER_FREEIF(a_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); */ + player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer); + } else { + /* If sync is TRUE, send data directly. */ + a_buffer->pcm_data = a_data; + __mmplayer_audio_stream_send_data(player, a_buffer); + MMPLAYER_FREEIF(a_buffer); + } - return MM_ERROR_PLAYER_INTERNAL; +DONE: + gst_buffer_unmap(buffer, &mapinfo); + MMPLAYER_FLEAVE(); } -static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player) +static void +__mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data) { - GList *element_bucket = NULL; - MMPlayerGstElement *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); - g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst), - "signal-handoffs", FALSE, - NULL); + mmplayer_t *player = (mmplayer_t *)data; + mmplayer_gst_element_t *audiobin = player->pipeline->audiobin; + GstPad *sinkpad = NULL; + GstElement *queue = NULL, *sink = NULL; - MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player); - MMPLAYER_SIGNAL_CONNECT(player, - G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), - MM_PLAYER_SIGNAL_TYPE_TEXTBIN, - "handoff", - G_CALLBACK(__mmplayer_update_subtitle), - (gpointer)player); + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); - g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL); - g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL); - g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL); + queue = gst_element_factory_make("queue", NULL); + if (queue == NULL) { + LOGD("fail make queue"); + goto ERROR; + } - if (!player->play_subtitle) { - LOGD("add textbin sink as sink element of whole pipeline.\n"); - __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst)); + sink = gst_element_factory_make("fakesink", NULL); + if (sink == NULL) { + LOGD("fail make fakesink"); + goto ERROR; } - /* adding created elements to bin */ - LOGD("adding created elements to bin\n"); - if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) { - LOGE("failed to add elements\n"); + gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL); + + if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) { + LOGW("failed to link queue & sink"); goto ERROR; } - /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */ - GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK); - GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK); + sinkpad = gst_element_get_static_pad(queue, "sink"); - /* linking elements in the bucket by added order. */ - LOGD("Linking elements in the bucket by added order.\n"); - if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) { - LOGE("failed to link elements\n"); + if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) { + LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad)); goto ERROR; } - /* done. free allocated variables */ - g_list_free(element_bucket); + LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt); - if (textbin[MMPLAYER_T_QUEUE].gst) { - GstPad *pad = NULL; - GstPad *ghostpad = NULL; + gst_object_unref(sinkpad); + if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK)) + g_object_set(sink, "sync", TRUE, NULL); + g_object_set(sink, "signal-handoffs", TRUE, NULL); - pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink"); - if (!pad) { - LOGE("failed to get sink pad of text queue"); - goto ERROR; - } + /* 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; + } - ghostpad = gst_ghost_pad_new("text_sink", pad); - gst_object_unref(pad); + gst_element_set_state(sink, GST_STATE_PAUSED); + gst_element_set_state(queue, GST_STATE_PAUSED); - if (!ghostpad) { - LOGE("failed to create ghostpad of textbin\n"); - goto ERROR; - } + __mmplayer_add_signal_connection(player, + G_OBJECT(sink), + MM_PLAYER_SIGNAL_TYPE_AUDIOBIN, + "handoff", + G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb), + (gpointer)player); - if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) { - LOGE("failed to add ghostpad to textbin\n"); - gst_object_unref(ghostpad); - goto ERROR; - } - } + __mmplayer_add_sink(player, sink); - return MM_ERROR_NONE; + MMPLAYER_FLEAVE(); + return; ERROR: - g_list_free(element_bucket); - - if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) { - LOGE("remove textbin sink from sink list"); - __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst); + LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR"); + if (queue) { + gst_object_unref(GST_OBJECT(queue)); + queue = NULL; + } + if (sink) { + gst_object_unref(GST_OBJECT(sink)); + sink = NULL; + } + if (sinkpad) { + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; } - /* release element at __mmplayer_gst_create_text_sink_bin */ - return MM_ERROR_PLAYER_INTERNAL; + return; } -static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player) +void +__mmplayer_gst_set_pulsesink_property(mmplayer_t *player) { - MMPlayerGstElement *textbin = NULL; - GList *element_bucket = NULL; - int surface_type = 0; - gint i = 0; + #define MAX_PROPS_LEN 128 + gint latency_mode = 0; + gchar *stream_type = NULL; + gchar *latency = NULL; + gint stream_id = 0; + gchar stream_props[MAX_PROPS_LEN] = {0,}; + GstStructure *props = NULL; + /* set volume table + * It should be set after player creation through attribute. + * But, it can not be changed during playing. + */ MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin); - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* alloc handles */ - textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM); - if (!textbin) { - LOGE("failed to allocate memory for textbin\n"); - return MM_ERROR_PLAYER_NO_FREE_SPACE; - } + 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); - /* create bin */ - textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN; - textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin"); - if (!textbin[MMPLAYER_T_BIN].gst) { - LOGE("failed to create textbin\n"); - goto ERROR; + 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); } - /* take it */ - player->pipeline->textbin = textbin; + mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode); - /* fakesink */ - mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type); - LOGD("surface type for subtitle : %d", surface_type); - switch (surface_type) { - case MM_DISPLAY_SURFACE_OVERLAY: - case MM_DISPLAY_SURFACE_NULL: - case MM_DISPLAY_SURFACE_REMOTE: - if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) { - LOGE("failed to make plain text elements\n"); - goto ERROR; - } + switch (latency_mode) { + case AUDIO_LATENCY_MODE_LOW: + latency = g_strndup("low", 3); break; - default: - goto ERROR; + case AUDIO_LATENCY_MODE_MID: + latency = g_strndup("mid", 3); break; - } - - MMPLAYER_FLEAVE(); + case AUDIO_LATENCY_MODE_HIGH: + latency = g_strndup("high", 4); + break; + }; - return MM_ERROR_NONE; + g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, + "latency", latency, + NULL); -ERROR: + LOGD("audiosink property - latency=%s", latency); - LOGD("ERROR : releasing textbin\n"); + MMPLAYER_FREEIF(latency); - g_list_free(element_bucket); + MMPLAYER_FLEAVE(); +} - /* release signal */ - __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN); +void +__mmplayer_gst_set_openalsink_property(mmplayer_t *player) +{ + mmplayer_gst_element_t *audiobin = NULL; - /* release element which are not added to bin */ - for (i = 1; i < MMPLAYER_T_NUM; i++) { - /* NOTE : skip bin */ - if (textbin[i].gst) { - GstObject* parent = NULL; - parent = gst_element_get_parent(textbin[i].gst); + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin); - if (!parent) { - gst_object_unref(GST_OBJECT(textbin[i].gst)); - textbin[i].gst = NULL; - } else { - gst_object_unref(GST_OBJECT(parent)); - } - } - } + audiobin = player->pipeline->audiobin; - /* release textbin with it's childs */ - if (textbin[MMPLAYER_T_BIN].gst) - gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst)); + 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); + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL); - MMPLAYER_FREEIF(player->pipeline->textbin); - player->pipeline->textbin = NULL; + if (player->video360_yaw_radians <= M_PI && + player->video360_yaw_radians >= -M_PI && + player->video360_pitch_radians <= M_PI_2 && + player->video360_pitch_radians >= -M_PI_2) { + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), + "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI), + "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL); + } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) { + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), + "source-orientation-y", player->video360_metadata.init_view_heading, + "source-orientation-x", player->video360_metadata.init_view_pitch, NULL); + } MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; } - static int -__mmplayer_gst_create_text_pipeline(mm_player_t* player) +__mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket) { - MMPlayerGstElement* mainbin = NULL; - MMPlayerGstElement* textbin = NULL; - MMHandleType attrs = 0; - GstElement *subsrc = NULL; - GstElement *subparse = NULL; - gchar *subtitle_uri = NULL; - const gchar *charset = NULL; - GstPad *pad = NULL; + mmplayer_gst_element_t *audiobin = NULL; + GstPad *sink_pad = NULL; + GstCaps *acaps = NULL; + gint channels = 0; + int pitch_control = 0; + double pitch_value = 1.0; MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && + player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED); - /* get mainbin */ - MMPLAYER_RETURN_VAL_IF_FAIL(player && - player->pipeline && - player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); - - mainbin = player->pipeline->mainbin; + audiobin = player->pipeline->audiobin; - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("cannot get content attribute\n"); - return MM_ERROR_PLAYER_INTERNAL; - } + LOGD("make element for normal audio playback"); - mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri); - if (!subtitle_uri || strlen(subtitle_uri) < 1) { - LOGE("subtitle uri is not proper filepath.\n"); - return MM_ERROR_PLAYER_INVALID_URI; - } + /* audio bin structure for playback. {} means optional. + optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content - if (!util_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; - } + * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume - + {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink} + */ - SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri); + /* for pitch control */ + mm_attrs_multiple_get(player->attrs, NULL, + MM_PLAYER_PITCH_CONTROL, &pitch_control, + MM_PLAYER_PITCH_VALUE, &pitch_value, + NULL); - MMPLAYER_SUBTITLE_INFO_LOCK(player); - player->subtitle_language_list = NULL; - MMPLAYER_SUBTITLE_INFO_UNLOCK(player); + LOGD("pitch %d / %1.3f", pitch_control, pitch_value); + if (pitch_control && (player->videodec_linked == 0)) { + GstElementFactory *factory; - /* create the subtitle source */ - subsrc = gst_element_factory_make("filesrc", "subtitle_source"); - if (!subsrc) { - LOGE("failed to create filesrc element\n"); - goto ERROR; - } - g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL); + factory = gst_element_factory_find("pitch"); + if (factory) { + gst_object_unref(factory); - mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC; - mainbin[MMPLAYER_M_SUBSRC].gst = subsrc; + /* converter */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player); - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) { - LOGW("failed to add queue\n"); - gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst); - mainbin[MMPLAYER_M_SUBSRC].gst = NULL; - mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM; - goto ERROR; + /* pitch */ + 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"); + } } - /* subparse */ - subparse = gst_element_factory_make("subparse", "subtitle_parser"); - if (!subparse) { - LOGE("failed to create subparse element\n"); - goto ERROR; - } + /* converter */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player); - charset = util_get_charset(subtitle_uri); - if (charset) { - LOGD("detected charset is %s\n", charset); - g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL); - } + /* replaygain volume */ + 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); - mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE; - mainbin[MMPLAYER_M_SUBPARSE].gst = subparse; + /* resampler */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player); - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) { - LOGW("failed to add subparse\n"); - gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst); - mainbin[MMPLAYER_M_SUBPARSE].gst = NULL; - mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM; - goto ERROR; - } + /* for logical volume control */ + 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); - if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) { - LOGW("failed to link subsrc and subparse\n"); - goto ERROR; + if (player->sound.mute) { + LOGD("mute enabled"); + g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL); } - player->play_subtitle = TRUE; - player->adjust_subtitle_pos = 0; + mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels); - LOGD("play subtitle using subtitle file\n"); + /* 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); - if (player->pipeline->textbin == NULL) { - if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) { - LOGE("failed to create text sink bin. continuing without text\n"); - goto ERROR; + LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type); + + 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"); + } } - textbin = player->pipeline->textbin; + 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); + } + } - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) { - LOGW("failed to add textbin\n"); + /* 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); - /* release signal */ - __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN); + /* 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) { - /* release textbin with it's childs */ - gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst)); - MMPLAYER_FREEIF(player->pipeline->textbin); - player->pipeline->textbin = textbin = NULL; - goto ERROR; - } + strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1); - LOGD("link text input selector and textbin ghost pad"); + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player); - player->textsink_linked = 1; - player->external_text_idx = 0; - LOGI("player->textsink_linked set to 1\n"); + 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); + + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player); + + player->is_openal_plugin_used = TRUE; } else { - textbin = player->pipeline->textbin; - LOGD("text bin has been created. reuse it."); - player->external_text_idx = 1; + 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); } - if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) { - LOGW("failed to link subparse and textbin\n"); - goto ERROR; + 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); } - pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink"); - if (!pad) { - LOGE("failed to get sink pad from textsink to probe data"); - goto ERROR; - } + if (g_strrstr(player->ini.audiosink_element, "pulsesink")) + __mmplayer_gst_set_pulsesink_property(player); + else if (g_strrstr(player->ini.audiosink_element, "openalsink")) + __mmplayer_gst_set_openalsink_property(player); - gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, - __mmplayer_subtitle_adjust_position_probe, player, NULL); + /* 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); - gst_object_unref(pad); - pad = 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)); - /* create dot. for debugging */ - MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle"); - MMPLAYER_FLEAVE(); + __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst); + MMPLAYER_FLEAVE(); return MM_ERROR_NONE; -ERROR: - /* release text pipeline resource */ - player->textsink_linked = 0; - - /* release signal */ - __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN); - - if (player->pipeline->textbin) { - LOGE("remove textbin"); - - /* release textbin with it's childs */ - MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN); - MMPLAYER_FREEIF(player->pipeline->textbin); - player->pipeline->textbin = NULL; - - } - - /* release subtitle elem */ - MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC); - MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE); - +ERROR: /* MMPLAYER_CREATE_ELEMENT */ + MMPLAYER_FLEAVE(); return MM_ERROR_PLAYER_INTERNAL; } -gboolean -__mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data) +static int +__mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket) { - mm_player_t* player = (mm_player_t*) data; - MMMessageParamType msg = {0, }; - GstClockTime duration = 0; - gpointer text = NULL; - guint text_size = 0; - gboolean ret = TRUE; - GstMapInfo mapinfo = GST_MAP_INFO_INIT; + mmplayer_gst_element_t *audiobin = NULL; + enum audio_element_id extract_sink_id = MMPLAYER_A_SINK; - MMPLAYER_FENTER(); + gchar *dst_format = NULL; + int dst_len = 0; + int dst_samplerate = 0; + int dst_channels = 0; + GstCaps *caps = NULL; + char *caps_str = NULL; - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE); + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && + player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED); - if (player->is_subtitle_force_drop) { - LOGW("subtitle is dropped forcedly."); - return ret; - } + audiobin = player->pipeline->audiobin; - gst_buffer_map(buffer, &mapinfo, GST_MAP_READ); - text = mapinfo.data; - text_size = mapinfo.size; - duration = GST_BUFFER_DURATION(buffer); + LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt); - if (player->set_mode.subtitle_off) { - LOGD("subtitle is OFF.\n"); - return TRUE; - } + /* audio bin structure according to the mmplayer_audio_extract_opt_e. - if (!text || (text_size == 0)) { - LOGD("There is no subtitle to be displayed.\n"); - return TRUE; - } + [case 1] extract interleave audio pcm without playback + : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync) + MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync) - msg.data = (void *) text; - msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration); + * src - ... - aconv - resample - capsfilter - fakesink (sync or not) - LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data); + [case 2] deinterleave for each channel without playback + : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync) + MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync) - MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg); - gst_buffer_unmap(buffer, &mapinfo); + * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not) + - fakesink (sync or not) + - ... (sync or not) - MMPLAYER_FLEAVE(); + [case 3] [case 1(sync only)] + playback + : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK - return ret; -} + * src - ... - tee - queue1 - playback path + - queue2 - [case1 pipeline with sync] -static GstPadProbeReturn -__mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) -{ - mm_player_t *player = (mm_player_t *) u_data; - GstClockTime cur_timestamp = 0; - gint64 adjusted_timestamp = 0; - GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); + [case 4] [case 2(sync only)] + playback + : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); + * src - ... - tee - queue1 - playback path + - queue2 - [case2 pipeline with sync] - if (player->set_mode.subtitle_off) { - LOGD("subtitle is OFF.\n"); - return TRUE; - } + */ - if (player->adjust_subtitle_pos == 0) { - LOGD("nothing to do"); - return TRUE; - } + /* 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); - cur_timestamp = GST_BUFFER_TIMESTAMP(buffer); - adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000)); + /* 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); - if (adjusted_timestamp < 0) { - LOGD("adjusted_timestamp under zero"); - MMPLAYER_FLEAVE(); - return FALSE; + /* 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 */ } - GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp; - LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "", - GST_TIME_ARGS(cur_timestamp), - GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); + /* 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); - return GST_PAD_PROBE_OK; -} -static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position) -{ - MMPLAYER_FENTER(); + /* resampler */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player); - /* check player and subtitlebin are created */ - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API); + /* 2. decide the extract pcm format */ + 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 (position == 0) { - LOGD("nothing to do\n"); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - } + LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d", + dst_format, dst_len, dst_samplerate, dst_channels); - switch (format) { - case MM_PLAYER_POS_FORMAT_TIME: - { - /* check current postion */ - player->adjust_subtitle_pos = position; + 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); - LOGD("save adjust_subtitle_pos in player") ; - } - break; + LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d", + dst_format, dst_len, dst_samplerate, dst_channels); - default: - { - LOGW("invalid format.\n"); - MMPLAYER_FLEAVE(); - return MM_ERROR_INVALID_ARGUMENT; + /* 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 (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE; + if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL; } - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} -static int __gst_adjust_video_position(mm_player_t* player, int offset) -{ - MMPLAYER_FENTER(); - LOGD("adjusting video_pos in player") ; - int current_pos = 0; - /* check player and videobin are created */ - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - if (!player->pipeline->videobin || - !player->pipeline->videobin[MMPLAYER_V_SINK].gst) { - LOGD("no video pipeline or sink is there"); - return MM_ERROR_PLAYER_INVALID_STATE ; - } - if (offset == 0) { - LOGD("nothing to do\n"); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - } - if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) { - LOGD("failed to get current position"); - return MM_ERROR_PLAYER_INTERNAL; - } - if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) { - LOGD("enter video delay is valid"); - } else { - LOGD("enter video delay is crossing content boundary"); - return MM_ERROR_INVALID_ARGUMENT ; - } - g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL); - LOGD("video delay has been done"); - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -static void -__gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) -{ - GstElement *appsrc = element; - MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data; - GstBuffer *buffer = NULL; - GstFlowReturn ret = GST_FLOW_OK; - gint len = size; - - MMPLAYER_RETURN_IF_FAIL(element); - MMPLAYER_RETURN_IF_FAIL(buf); - - buffer = gst_buffer_new(); + /* 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); - if (buf->offset >= buf->len) { - LOGD("call eos appsrc\n"); - g_signal_emit_by_name(appsrc, "end-of-stream", &ret); - return; - } + caps_str = gst_caps_to_string(caps); + LOGD("new caps : %s", caps_str); - if (buf->len - buf->offset < size) - len = buf->len - buf->offset; + g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL); - gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL)); - GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset; - GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len); + /* clean */ + gst_caps_unref(caps); + MMPLAYER_FREEIF(caps_str); - //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len); - g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret); + /* 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); - buf->offset += len; -} + /* 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); + } 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); -static gboolean -__gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) -{ - MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data; + __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_RETURN_VAL_IF_FAIL(buf, FALSE); + __mmplayer_add_sink(player, audiobin[extract_sink_id].gst); + } - buf->offset = (int)size; + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; - return TRUE; +ERROR: /* MMPLAYER_CREATE_ELEMENT */ + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; } -static GstBusSyncReply -__mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data) +static int +__mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket) { - mm_player_t *player = (mm_player_t *)data; - GstBusSyncReply reply = GST_BUS_DROP; + int ret = MM_ERROR_NONE; + mmplayer_gst_element_t *audiobin = NULL; + GList *element_bucket = NULL; - if (!(player->pipeline && player->pipeline->mainbin)) { - LOGE("player pipeline handle is null"); - return GST_BUS_PASS; - } + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && + player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED); - if (!__mmplayer_check_useful_message(player, message)) { - gst_message_unref(message); - return GST_BUS_DROP; - } + audiobin = player->pipeline->audiobin; - switch (GST_MESSAGE_TYPE(message)) { - case GST_MESSAGE_STATE_CHANGED: - /* post directly for fast launch */ - if (player->sync_handler) { - __mmplayer_gst_callback(message, player); - reply = GST_BUS_DROP; - } else - reply = GST_BUS_PASS; - break; - case GST_MESSAGE_TAG: - __mmplayer_gst_extract_tag_from_msg(player, message); + if (player->build_audio_offload) { /* skip all the audio filters */ + LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element); - #if 0 // debug - { - GstTagList *tags = NULL; + 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); - gst_message_parse_tag(message, &tags); - if (tags) { - LOGE("TAGS received from element \"%s\".\n", - GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message)))); + __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst); + goto DONE; + } - gst_tag_list_foreach(tags, print_tag, NULL); - gst_tag_list_free(tags); - tags = NULL; - } - break; - } - #endif - break; + /* 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); - case GST_MESSAGE_DURATION_CHANGED: - __mmplayer_gst_handle_duration(player, message); - break; - case GST_MESSAGE_ASYNC_DONE: - /* NOTE:Don't call gst_callback directly - * because previous frame can be showed even though this message is received for seek. - */ - default: - reply = GST_BUS_PASS; - break; - } + if (ret != MM_ERROR_NONE) + goto ERROR; +DONE: + LOGD("success to make audio bin element"); + *bucket = element_bucket; - if (reply == GST_BUS_DROP) - gst_message_unref(message); + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; + +ERROR: + LOGE("failed to make audio bin element"); + g_list_free(element_bucket); - return reply; + *bucket = NULL; + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; } -static gboolean -__mmplayer_gst_create_decoder(mm_player_t *player, - MMPlayerTrackType track, - GstPad* srcpad, - enum MainElementID elemId, - const gchar* name) +static int +__mmplayer_gst_create_audio_sink_bin(mmplayer_t *player) { - gboolean ret = TRUE; - GstPad *sinkpad = NULL; + mmplayer_gst_element_t *first_element = NULL; + mmplayer_gst_element_t *audiobin = NULL; + GstPad *pad = NULL; + GstPad *ghostpad = NULL; + GList *element_bucket = NULL; + int i = 0; MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(player && - player->pipeline && - player->pipeline->mainbin, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE); - - GstElement *decodebin = NULL; - GstCaps *dec_caps = NULL; - - /* create decodebin */ - decodebin = gst_element_factory_make("decodebin", name); + /* alloc handles */ + audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM); + if (!audiobin) { + LOGE("failed to allocate memory for audiobin"); + return MM_ERROR_PLAYER_NO_FREE_SPACE; + } - if (!decodebin) { - LOGE("error : fail to create decodebin for %d decoder\n", track); - ret = FALSE; + /* create bin */ + audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN; + audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin"); + if (!audiobin[MMPLAYER_A_BIN].gst) { + LOGE("failed to create audiobin"); goto ERROR; } - /* raw pad handling signal */ - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK(__mmplayer_gst_decode_pad_added), player); + /* take it */ + player->pipeline->audiobin = audiobin; - /* This signal is emitted whenever decodebin finds a new stream. It is emitted - before looking for any elements that can handle that stream.*/ - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", - G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player); + /* create audio filters and audiosink */ + if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE) + goto ERROR; - /* This signal is emitted when a element is added to the bin.*/ - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added", - G_CALLBACK(__mmplayer_gst_element_added), player); + /* 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)) + goto ERROR; - if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) { - LOGE("failed to add new decodebin\n"); - ret = FALSE; + /* 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) goto ERROR; - } - dec_caps = gst_pad_query_caps(srcpad, NULL); - if (dec_caps) { - //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps); - g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL); - gst_caps_unref(dec_caps); + /* get first element's sinkpad for creating ghostpad */ + first_element = (mmplayer_gst_element_t *)element_bucket->data; + if (!first_element) { + LOGE("failed to get first elem"); + goto ERROR; } - player->pipeline->mainbin[elemId].id = elemId; - player->pipeline->mainbin[elemId].gst = decodebin; + pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); + if (!pad) { + LOGE("failed to get pad from first element of audiobin"); + goto ERROR; + } - sinkpad = gst_element_get_static_pad(decodebin, "sink"); + ghostpad = gst_ghost_pad_new("sink", pad); + if (!ghostpad) { + LOGE("failed to create ghostpad"); + goto ERROR; + } - if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { - LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad)); - gst_object_unref(GST_OBJECT(decodebin)); + if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) { + LOGE("failed to add ghostpad to audiobin"); + goto ERROR; } - if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) - LOGE("failed to sync second level decodebin state with parent\n"); + gst_object_unref(pad); + + g_list_free(element_bucket); + MMPLAYER_FLEAVE(); - LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num); + return MM_ERROR_NONE; ERROR: - if (sinkpad) { - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; + LOGD("ERROR : releasing audiobin"); + + if (pad) + gst_object_unref(GST_OBJECT(pad)); + + if (ghostpad) + gst_object_unref(GST_OBJECT(ghostpad)); + + if (element_bucket) + g_list_free(element_bucket); + + /* release element which are not added to bin */ + for (i = 1; i < MMPLAYER_A_NUM; i++) { + /* NOTE : skip bin */ + if (audiobin[i].gst) { + GstObject *parent = NULL; + parent = gst_element_get_parent(audiobin[i].gst); + + if (!parent) { + gst_object_unref(GST_OBJECT(audiobin[i].gst)); + audiobin[i].gst = NULL; + } else + gst_object_unref(GST_OBJECT(parent)); + } } - MMPLAYER_FLEAVE(); - return ret; + /* release audiobin with it's childs */ + if (audiobin[MMPLAYER_A_BIN].gst) + gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst)); + + MMPLAYER_FREEIF(audiobin); + + player->pipeline->audiobin = NULL; + + return MM_ERROR_PLAYER_INTERNAL; } -/** - * This function is to create audio or video pipeline for playing. - * - * @param player [in] handle of player - * - * @return This function returns zero on success. - * @remark - * @see - */ -static int -__mmplayer_gst_create_pipeline(mm_player_t* player) +static guint32 +_mmplayer_convert_fourcc_string_to_value(const gchar *format_name) { - GstBus *bus = NULL; - MMPlayerGstElement *mainbin = NULL; - MMHandleType attrs = 0; - GstElement* element = NULL; - GstElement* elem_src_audio = NULL; - GstElement* elem_src_subtitle = NULL; - GstElement* es_video_queue = NULL; - GstElement* es_audio_queue = NULL; - GstElement* es_subtitle_queue = NULL; - GList* element_bucket = NULL; - gboolean need_state_holder = TRUE; - gint i = 0; -#ifdef SW_CODEC_ONLY - int surface_type = 0; -#endif - MMPLAYER_FENTER(); + return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24); +} +int +_mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo) +{ + int ret = MM_ERROR_NONE; + GList *l = NULL; MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT); - /* get profile attribute */ - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("cannot get content attribute\n"); - goto INIT_ERROR; - } + MMPLAYER_VIDEO_BO_LOCK(player); - /* create pipeline handles */ - if (player->pipeline) { - LOGW("pipeline should be released before create new one\n"); - goto INIT_ERROR; + if (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 && tmp->bo == bo) { + tmp->used = FALSE; + LOGD("release bo %p", bo); + tbm_bo_unref(tmp->bo); + MMPLAYER_VIDEO_BO_UNLOCK(player); + MMPLAYER_VIDEO_BO_SIGNAL(player); + return ret; + } + } + } else { + /* hw codec is running or the list was reset for DRC. */ + LOGW("there is no bo list."); } + MMPLAYER_VIDEO_BO_UNLOCK(player); - player->video360_metadata.is_spherical = -1; - player->is_openal_plugin_used = FALSE; + LOGW("failed to find bo %p", bo); + return ret; +} - player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo)); - if (player->pipeline == NULL) - goto INIT_ERROR; +static void +__mmplayer_video_stream_destroy_bo_list(mmplayer_t *player) +{ + GList *l = NULL; - memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */ + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player); - /* create mainbin */ - mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); - if (mainbin == NULL) - goto INIT_ERROR; + 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); + player->video_bo_list = NULL; + } + player->video_bo_size = 0; + MMPLAYER_VIDEO_BO_UNLOCK(player); + + MMPLAYER_FLEAVE(); + return; +} - memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */ +static void * +__mmplayer_video_stream_get_bo(mmplayer_t *player, int size) +{ + GList *l = NULL; + MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL); + gboolean ret = TRUE; - /* create pipeline */ - mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE; - mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player"); - if (!mainbin[MMPLAYER_M_PIPE].gst) { - LOGE("failed to create pipeline\n"); - goto INIT_ERROR; + /* check DRC, if it is, destroy the prev bo list to create again */ + if (player->video_bo_size != size) { + LOGD("video size is changed: %d -> %d", player->video_bo_size, size); + __mmplayer_video_stream_destroy_bo_list(player); + player->video_bo_size = size; } - player->demux_pad_index = 0; - player->subtitle_language_list = NULL; - player->is_subtitle_force_drop = FALSE; - player->last_multiwin_status = FALSE; + MMPLAYER_VIDEO_BO_LOCK(player); - _mmplayer_track_initialize(player); - __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX); + if ((!player->video_bo_list) || + (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) { - /* create source element */ - switch (player->profile.uri_type) { - /* rtsp streamming */ - case MM_PLAYER_URI_TYPE_URL_RTSP: - { - gchar *user_agent; + /* create bo list */ + int idx = 0; + LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo); - element = gst_element_factory_make("rtspsrc", "rtsp source"); + if (player->video_bo_list) { + /* if bo list did not created all, try it again. */ + idx = g_list_length(player->video_bo_list); + LOGD("bo list exist(len: %d)", idx); + } - if (!element) { - LOGE("failed to create streaming source element\n"); + for (; idx < player->ini.num_of_video_bo; idx++) { + mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1); + if (!bo_info) { + LOGE("Fail to alloc bo_info."); break; } + bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT); + if (!bo_info->bo) { + LOGE("Fail to tbm_bo_alloc."); + MMPLAYER_FREEIF(bo_info); + break; + } + bo_info->used = FALSE; + player->video_bo_list = g_list_append(player->video_bo_list, bo_info); + } - /* make it zero */ - user_agent = NULL; - - /* get attribute */ - mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent); + /* 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; - SECURE_LOGD("user_agent : %s\n", user_agent); + if (idx == 0) { + MMPLAYER_VIDEO_BO_UNLOCK(player); + return NULL; + } - /* setting property to streaming source */ - g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); - if (user_agent) - g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL); + LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers); + } - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player); - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", - G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player); + while (TRUE) { + /* get bo from 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 && (tmp->used == FALSE)) { + LOGD("found bo %p to use", tmp->bo); + tmp->used = TRUE; + MMPLAYER_VIDEO_BO_UNLOCK(player); + return tbm_bo_ref(tmp->bo); + } + } + if (!ret) { + LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout); + MMPLAYER_VIDEO_BO_UNLOCK(player); + return NULL; } - break; - /* http streaming*/ - case MM_PLAYER_URI_TYPE_URL_HTTP: - { - gchar *user_agent, *cookies, **cookie_list; - gint http_timeout = DEFAULT_HTTP_TIMEOUT; - user_agent = cookies = NULL; - cookie_list = NULL; - gint mode = MM_PLAYER_PD_MODE_NONE; + if (player->ini.video_bo_timeout <= 0) { + MMPLAYER_VIDEO_BO_WAIT(player); + } else { + gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND; + ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout); + } + continue; + } +} - mm_attrs_get_int_by_name(attrs, "pd_mode", &mode); +static void +__mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data) +{ + mmplayer_t *player = (mmplayer_t *)data; + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb); - player->pd_mode = mode; + /* send prerolled pkt */ + player->video_stream_prerolled = false; - LOGD("http playback, PD mode : %d\n", player->pd_mode); + __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data); - if (!MMPLAYER_IS_HTTP_PD(player)) { - element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source"); - if (!element) { - LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element); - break; - } - LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element); + /* not to send prerolled pkt again */ + player->video_stream_prerolled = true; +} - /* get attribute */ - mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies); - mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent); +static void +__mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data) +{ + mmplayer_t *player = (mmplayer_t *)data; + mmplayer_video_decoded_data_info_t *stream = NULL; + GstMemory *mem = NULL; - if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) { - LOGD("get timeout from ini\n"); - http_timeout = player->ini.http_timeout; - } + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player); + MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb); - /* get attribute */ - SECURE_LOGD("location : %s\n", player->profile.uri); - SECURE_LOGD("cookies : %s\n", cookies); - SECURE_LOGD("user_agent : %s\n", user_agent); - LOGD("timeout : %d\n", http_timeout); - - /* setting property to streaming source */ - g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); - g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL); - g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL); - - /* parsing cookies */ - if ((cookie_list = util_get_cookie_list((const char*)cookies))) { - g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL); - g_strfreev(cookie_list); - } - if (user_agent) - g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL); + if (player->video_stream_prerolled) { + player->video_stream_prerolled = false; + LOGD("skip the prerolled pkt not to send it again"); + return; + } - if (MMPLAYER_URL_HAS_DASH_SUFFIX(player)) - LOGW("it's dash. and it's still experimental feature."); - } else { - // progressive download - gchar* location = NULL; + /* clear stream data structure */ + stream = __mmplayer_create_stream_from_pad(pad); + if (!stream) { + LOGE("failed to alloc stream"); + return; + } - if (player->pd_mode == MM_PLAYER_PD_MODE_URI) { - gchar *path = NULL; + __mmplayer_get_video_angle(player, NULL, &stream->orientation); - mm_attrs_get_string_by_name(attrs, "pd_location", &path); + /* 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 */ - MMPLAYER_FREEIF(player->pd_file_save_path); + /* check zero-copy */ + if (player->set_mode.video_zc && + player->set_mode.video_export && + gst_is_tizen_memory(mem)) { + __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem); + stream->internal_buffer = gst_buffer_ref(buffer); + } else { /* sw codec */ + if (!__mmplayer_swcodec_set_stride_elevation(stream)) + goto ERROR; - LOGD("PD Location : %s\n", path); + if (!__mmplayer_swcodec_set_bo(player, stream, mem)) + goto ERROR; + } - if (path) { - if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) { - LOGE("failed to get storage info"); - break; - } - player->pd_file_save_path = g_strdup(path); - } else { - LOGE("can't find pd location so, it should be set \n"); - break; - } - } + if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) { + LOGE("failed to send video decoded data."); + goto ERROR; + } - element = gst_element_factory_make("pdpushsrc", "PD pushsrc"); - if (!element) { - LOGE("failed to create PD push source element[%s].\n", "pdpushsrc"); - break; - } + return; - if (player->pd_mode == MM_PLAYER_PD_MODE_URI) - g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL); - else - g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); - g_object_get(element, "location", &location, NULL); - LOGD("PD_LOCATION [%s].\n", location); - if (location) - g_free(location); - } +ERROR: + LOGE("release video stream resource."); + if (gst_is_tizen_memory(mem)) { + int i = 0; + for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) { + if (stream->bo[i]) + tbm_bo_unref(stream->bo[i]); } - break; - /* file source */ - case MM_PLAYER_URI_TYPE_FILE: - { - LOGD("using filesrc for 'file://' handler.\n"); - if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) { - LOGE("failed to get storage info"); - break; - } + /* unref gst buffer */ + if (stream->internal_buffer) + gst_buffer_unref(stream->internal_buffer); + } else { + if (stream->bo[0]) + _mmplayer_video_stream_release_bo(player, stream->bo[0]); + } + MMPLAYER_FREEIF(stream); + return; +} - element = gst_element_factory_make("filesrc", "source"); - if (!element) { - LOGE("failed to create filesrc\n"); - break; - } +static void +__mmplayer_gst_set_video360_property(mmplayer_t *player) +{ + mmplayer_gst_element_t *videobin = NULL; - g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */ - } - break; + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin); - case MM_PLAYER_URI_TYPE_SS: - { - gint http_timeout = DEFAULT_HTTP_TIMEOUT; - element = gst_element_factory_make("souphttpsrc", "http streaming source"); - if (!element) { - LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element); - break; - } + videobin = player->pipeline->videobin; - if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) { - LOGD("get timeout from ini\n"); - http_timeout = player->ini.http_timeout; - } + /* Set spatial media metadata and/or user settings to the element. + * */ + g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), + "projection-type", player->video360_metadata.projection_type, NULL); - /* setting property to streaming source */ - g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); - g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL); - } - break; - case MM_PLAYER_URI_TYPE_MS_BUFF: - { - LOGD("MS buff src is selected\n"); + g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), + "stereo-mode", player->video360_metadata.stereo_mode, NULL); - if (player->v_stream_caps) { - element = gst_element_factory_make("appsrc", "video_appsrc"); - if (!element) { - LOGF("failed to create video app source element[appsrc].\n"); - break; - } + if (player->video360_metadata.full_pano_width_pixels && + player->video360_metadata.full_pano_height_pixels && + player->video360_metadata.cropped_area_image_width && + player->video360_metadata.cropped_area_image_height) { + g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), + "projection-bounds-top", player->video360_metadata.cropped_area_top, + "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels - + player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height, + "projection-bounds-left", player->video360_metadata.cropped_area_left, + "projection-bounds-right", player->video360_metadata.full_pano_width_pixels - + player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width, + NULL); + } - if (player->a_stream_caps) { - elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc"); - if (!elem_src_audio) { - LOGF("failed to create audio app source element[appsrc].\n"); - break; - } - } - } else if (player->a_stream_caps) { - /* no video, only audio pipeline*/ - element = gst_element_factory_make("appsrc", "audio_appsrc"); - if (!element) { - LOGF("failed to create audio app source element[appsrc].\n"); - break; - } - } + if (player->video360_horizontal_fov && player->video360_vertical_fov) { + g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), + "horizontal-fov", player->video360_horizontal_fov, + "vertical-fov", player->video360_vertical_fov, NULL); + } - if (player->s_stream_caps) { - elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc"); - if (!elem_src_subtitle) { - LOGF("failed to create subtitle app source element[appsrc].\n"); - break; - } - } + if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) { + g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), + "zoom", 1.0f / player->video360_zoom, NULL); + } - LOGD("setting app sources properties.\n"); - LOGD("location : %s\n", player->profile.uri); - - if (player->v_stream_caps && element) { - g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME, - "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */ - "caps", player->v_stream_caps, NULL); - - if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0) - g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL); - if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0) - g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL); - - /*Fix Seek External Demuxer: set audio and video appsrc as seekable */ - gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE); - MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", - G_CALLBACK(__gst_seek_video_data), player); - - if (player->a_stream_caps && elem_src_audio) { - g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME, - "caps", player->a_stream_caps, NULL); - - if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) - g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); - if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) - g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); - - /*Fix Seek External Demuxer: set audio and video appsrc as seekable */ - gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE); - MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", - G_CALLBACK(__gst_seek_audio_data), player); - } - } else if (player->a_stream_caps && element) { - g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME, - "caps", player->a_stream_caps, NULL); - - if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) - g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); - if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) - g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); - - /*Fix Seek External Demuxer: set audio and video appsrc as seekable */ - gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE); - MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", - G_CALLBACK(__gst_seek_audio_data), player); - } + if (player->video360_yaw_radians <= M_PI && + player->video360_yaw_radians >= -M_PI && + player->video360_pitch_radians <= M_PI_2 && + player->video360_pitch_radians >= -M_PI_2) { + g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), + "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI), + "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL); + } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) { + g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), + "pose-yaw", player->video360_metadata.init_view_heading, + "pose-pitch", player->video360_metadata.init_view_pitch, NULL); + } - if (player->s_stream_caps && elem_src_subtitle) { - g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME, - "caps", player->s_stream_caps, NULL); + g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst), + "passthrough", !player->is_video360_enabled, NULL); - if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0) - g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL); - if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0) - g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL); - gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE); + MMPLAYER_FLEAVE(); +} - MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", - G_CALLBACK(__gst_seek_subtitle_data), player); - } +static int +__mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket) +{ + gchar *video_csc = "videoconvert"; /* default colorspace converter */ + GList *element_bucket = NULL; - if (player->v_stream_caps && element) { - MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", - G_CALLBACK(__gst_appsrc_feed_video_data), player); - MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", - G_CALLBACK(__gst_appsrc_enough_video_data), player); - - if (player->a_stream_caps && elem_src_audio) { - MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", - G_CALLBACK(__gst_appsrc_feed_audio_data), player); - MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", - G_CALLBACK(__gst_appsrc_enough_audio_data), player); - } - } else if (player->a_stream_caps && element) { - MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", - G_CALLBACK(__gst_appsrc_feed_audio_data), player); - MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", - G_CALLBACK(__gst_appsrc_enough_audio_data), player); - } + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED); - if (player->s_stream_caps && elem_src_subtitle) - MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", - G_CALLBACK(__gst_appsrc_feed_subtitle_data), player); + /* 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", element_bucket, player); + __mmplayer_gst_set_video360_property(player); + goto EXIT; + } - need_state_holder = FALSE; + if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) { + LOGD("skip creating the videoconv and rotator"); + return MM_ERROR_NONE; + } - mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE); - if (mmf_attrs_commit(attrs)) /* return -1 if error */ - LOGE("failed to commit\n"); - } - break; - /* appsrc */ - case MM_PLAYER_URI_TYPE_MEM: - { - guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS; + /* 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", element_bucket, player); - LOGD("mem src is selected\n"); +EXIT: + *bucket = element_bucket; + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; - element = gst_element_factory_make("appsrc", "mem-source"); - if (!element) { - LOGE("failed to create appsrc element\n"); - break; - } +ERROR: /* refer MMPLAYER_CREATE_ELEMENT */ + g_list_free(element_bucket); - g_object_set(element, "stream-type", stream_type, NULL); - g_object_set(element, "size", player->profile.input_mem.len, NULL); - g_object_set(element, "blocksize", (guint64)20480, NULL); + *bucket = NULL; + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; +} - MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", - G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem); - MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", - G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem); - } - break; - case MM_PLAYER_URI_TYPE_URL: - break; +static gchar * +__mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type) +{ + gchar *factory_name = NULL; - case MM_PLAYER_URI_TYPE_TEMP: + switch (surface_type) { + case MM_DISPLAY_SURFACE_OVERLAY: + if (strlen(player->ini.videosink_element_overlay) > 0) + factory_name = player->ini.videosink_element_overlay; + break; + case MM_DISPLAY_SURFACE_REMOTE: + case MM_DISPLAY_SURFACE_NULL: + if (strlen(player->ini.videosink_element_fake) > 0) + factory_name = player->ini.videosink_element_fake; break; - - case MM_PLAYER_URI_TYPE_NONE: default: + LOGE("unidentified surface type"); break; } - /* check source element is OK */ - if (!element) { - LOGE("no source element was created.\n"); - goto INIT_ERROR; - } - - /* take source element */ - mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC; - mainbin[MMPLAYER_M_SRC].gst = element; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]); - - if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) { - player->streamer = __mm_player_streaming_create(); - __mm_player_streaming_initialize(player->streamer); - } - - if (MMPLAYER_IS_HTTP_PD(player)) { - gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time; - - LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time); - element = gst_element_factory_make("queue2", "queue2"); - if (!element) { - LOGE("failed to create http streaming buffer element\n"); - goto INIT_ERROR; - } + LOGD("surface_type %d, videosink is %s", surface_type, factory_name); + return factory_name; +} - /* take it */ - mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER; - mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]); +static int +__mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type) +{ + gchar *factory_name = NULL; + mmplayer_gst_element_t *videobin = NULL; + MMHandleType attrs; + int gapless = 0; - pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time); + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED); - player->streamer->is_pd_mode = TRUE; + videobin = player->pipeline->videobin; + factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst)); - __mm_player_streaming_set_queue2(player->streamer, - element, - TRUE, - player->ini.http_max_size_bytes + PLAYER_PD_EXT_MAX_SIZE_BYTE, - pre_buffering_time, - 1.0, - player->ini.http_buffering_limit, - MUXED_BUFFER_TYPE_MEM_QUEUE, - NULL, - 0); + attrs = MMPLAYER_GET_ATTRS(player); + if (!attrs) { + LOGE("cannot get content attribute"); + return MM_ERROR_PLAYER_INTERNAL; } - if (MMPLAYER_IS_MS_BUFF_SRC(player)) { - if (player->v_stream_caps) { - es_video_queue = gst_element_factory_make("queue2", "video_queue"); - if (!es_video_queue) { - LOGE("create es_video_queue for es player failed\n"); - goto INIT_ERROR; - } - g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL); - mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER; - mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]); - - /* Adding audio appsrc to bucket */ - if (player->a_stream_caps && elem_src_audio) { - mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC; - mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]); - - es_audio_queue = gst_element_factory_make("queue2", "audio_queue"); - if (!es_audio_queue) { - LOGE("create es_audio_queue for es player failed\n"); - goto INIT_ERROR; - } - g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL); - - mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER; - mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]); - } - } else if (player->a_stream_caps) { - /* Only audio stream, no video */ - es_audio_queue = gst_element_factory_make("queue2", "audio_queue"); - if (!es_audio_queue) { - LOGE("create es_audio_queue for es player failed\n"); - goto INIT_ERROR; - } - mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER; - mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]); - } - if (player->s_stream_caps && elem_src_subtitle) { - mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC; - mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]); - - es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue"); - if (!es_subtitle_queue) { - LOGE("create es_subtitle_queue for es player failed\n"); - goto INIT_ERROR; + 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); } - mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER; - mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]); } + } else { + g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), + "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL); } - /* create autoplugging element if src element is not a rtsp src */ - if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) && - (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) { - element = NULL; - enum MainElementID elemId = MMPLAYER_M_NUM; - - if (((MMPLAYER_IS_HTTP_PD(player)) || - (!MMPLAYER_IS_HTTP_STREAMING(player)))) { - elemId = MMPLAYER_M_AUTOPLUG; - element = __mmplayer_create_decodebin(player); - if (element) { - /* default size of mq in decodebin is 2M - * but it can cause blocking issue during seeking depends on content. */ - g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL); - } - need_state_holder = FALSE; - } else { - elemId = MMPLAYER_M_TYPEFIND; - element = gst_element_factory_make("typefind", "typefinder"); - MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", - G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player); - } - - - /* check autoplug element is OK */ - if (!element) { - LOGE("can not create element(%d)\n", elemId); - goto INIT_ERROR; - } + mm_attrs_get_int_by_name(attrs, "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); + } - mainbin[elemId].id = elemId; - mainbin[elemId].gst = element; + if (player->set_mode.video_export) { + int enable = 0; + mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable); + 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); - element_bucket = g_list_append(element_bucket, &mainbin[elemId]); - } + __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); - /* add elements to pipeline */ - if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) { - LOGE("Failed to add elements to pipeline\n"); - goto INIT_ERROR; + __mmplayer_add_signal_connection(player, + G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), + MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, + "preroll-handoff", + G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb), + (gpointer)player); } + if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE) + return MM_ERROR_PLAYER_INTERNAL; - /* linking elements in the bucket by added order. */ - if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) { - LOGE("Failed to link some elements\n"); - goto INIT_ERROR; + 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, + "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player); + gst_object_unref(GST_OBJECT(sink_pad)); + } else { + LOGE("failed to get sink pad from videosink"); + } } + return MM_ERROR_NONE; +} - /* create fakesink element for keeping the pipeline state PAUSED. if needed */ - if (need_state_holder) { - /* create */ - mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK; - mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder"); - - if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) { - LOGE("fakesink element could not be created\n"); - goto INIT_ERROR; - } - GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK); +/** + * VIDEO BIN + * - video overlay surface(arm/x86) : tizenwlsink + */ +static int +__mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type) +{ + GstPad *pad = NULL; + GList *element_bucket = NULL; + mmplayer_gst_element_t *first_element = NULL; + mmplayer_gst_element_t *videobin = NULL; + gchar *videosink_factory_name = NULL; - /* take ownership of fakesink. we are reusing it */ - gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst); + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - /* add */ - if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), - mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) { - LOGE("failed to add fakesink to bin\n"); - goto INIT_ERROR; - } - } + /* alloc handles */ + videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM); + if (!videobin) + return MM_ERROR_PLAYER_NO_FREE_SPACE; - /* now we have completed mainbin. take it */ - player->pipeline->mainbin = mainbin; + player->pipeline->videobin = videobin; - if (MMPLAYER_IS_MS_BUFF_SRC(player)) { - GstPad *srcpad = NULL; - - if (mainbin[MMPLAYER_M_V_BUFFER].gst) { - srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src"); - if (srcpad) { - __mmplayer_gst_create_decoder(player, - MM_PLAYER_TRACK_TYPE_VIDEO, - srcpad, - MMPLAYER_M_AUTOPLUG_V_DEC, - "video_decodebin"); - - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - } - } + /* create bin */ + videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN; + videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin"); + if (!videobin[MMPLAYER_V_BIN].gst) { + LOGE("failed to create videobin"); + goto ERROR; + } - if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) { - srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src"); - if (srcpad) { - __mmplayer_gst_create_decoder(player, - MM_PLAYER_TRACK_TYPE_AUDIO, - srcpad, - MMPLAYER_M_AUTOPLUG_A_DEC, - "audio_decodebin"); + if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE) + goto ERROR; - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - } // else error - } // else error + videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type); + MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player); - if (mainbin[MMPLAYER_M_S_BUFFER].gst) - __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps); + /* additional setting for sink plug-in */ + if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) { + LOGE("failed to set video property"); + goto ERROR; } - /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */ - if (__mmplayer_check_subtitle(player)) { - if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) - LOGE("fail to create text pipeline"); - } + /* store it as it's sink element */ + __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst); - /* connect bus callback */ - bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst)); - if (!bus) { - LOGE("cannot get bus from pipeline.\n"); - goto INIT_ERROR; + /* adding created elements to bin */ + if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) { + LOGE("failed to add elements"); + goto ERROR; } - player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player); + /* Linking elements in the bucket by added order */ + if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) { + LOGE("failed to link elements"); + goto ERROR; + } - player->context.thread_default = g_main_context_get_thread_default(); + /* get first element's sinkpad for creating ghostpad */ + first_element = (mmplayer_gst_element_t *)element_bucket->data; + if (!first_element) { + LOGE("failed to get first element from bucket"); + goto ERROR; + } - if (player->context.thread_default == NULL) { - player->context.thread_default = g_main_context_default(); - LOGD("thread-default context is the global default context"); + pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); + if (!pad) { + LOGE("failed to get pad from first element"); + goto ERROR; } - LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher); - /* set sync handler to get tag synchronously */ - gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL); + /* create ghostpad */ + player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad); + if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) { + LOGE("failed to add ghostpad to videobin"); + goto ERROR; + } + gst_object_unref(pad); - /* finished */ - gst_object_unref(GST_OBJECT(bus)); + /* done. free allocated variables */ g_list_free(element_bucket); - /* create gst bus_msb_cb thread */ - g_mutex_init(&player->bus_msg_thread_mutex); - g_cond_init(&player->bus_msg_thread_cond); - player->bus_msg_thread_exit = FALSE; - player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT; - player->bus_msg_thread = - g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL); - if (!player->bus_msg_thread) { - LOGE("failed to create gst BUS msg thread"); - g_mutex_clear(&player->bus_msg_thread_mutex); - g_cond_clear(&player->bus_msg_thread_cond); - goto INIT_ERROR; - } - MMPLAYER_FLEAVE(); return MM_ERROR_NONE; -INIT_ERROR: - __mmplayer_gst_destroy_pipeline(player); +ERROR: + LOGE("ERROR : releasing videobin"); g_list_free(element_bucket); - if (mainbin) { - /* release element which are not added to bin */ - for (i = 1; i < MMPLAYER_M_NUM; i++) { - /* NOTE : skip pipeline */ - if (mainbin[i].gst) { - GstObject* parent = NULL; - parent = gst_element_get_parent(mainbin[i].gst); - - if (!parent) { - gst_object_unref(GST_OBJECT(mainbin[i].gst)); - mainbin[i].gst = NULL; - } else - gst_object_unref(GST_OBJECT(parent)); - } - } + if (pad) + gst_object_unref(GST_OBJECT(pad)); - /* release pipeline with it's childs */ - if (mainbin[MMPLAYER_M_PIPE].gst) - gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst)); + /* release videobin with it's childs */ + if (videobin[MMPLAYER_V_BIN].gst) + gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst)); - MMPLAYER_FREEIF(mainbin); - } + MMPLAYER_FREEIF(videobin); + player->pipeline->videobin = NULL; - MMPLAYER_FREEIF(player->pipeline); return MM_ERROR_PLAYER_INTERNAL; } -static void -__mmplayer_reset_gapless_state(mm_player_t* player) -{ - MMPLAYER_FENTER(); - MMPLAYER_RETURN_IF_FAIL(player - && player->pipeline - && player->pipeline->audiobin - && player->pipeline->audiobin[MMPLAYER_A_BIN].gst); - - memset(&player->gapless, 0, sizeof(mm_player_gapless_t)); - - MMPLAYER_FLEAVE(); - return; -} - static int -__mmplayer_gst_destroy_pipeline(mm_player_t* player) +__mmplayer_gst_create_plain_text_elements(mmplayer_t *player) { - gint timeout = 0; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE); + GList *element_bucket = NULL; + mmplayer_gst_element_t *textbin = player->pipeline->textbin; - /* cleanup stuffs */ - MMPLAYER_FREEIF(player->type); - player->have_dynamic_pad = FALSE; - player->no_more_pad = FALSE; - player->num_dynamic_pad = 0; - player->demux_pad_index = 0; - player->use_deinterleave = FALSE; - player->max_audio_channels = 0; - player->video_share_api_delta = 0; - player->video_share_clock_delta = 0; - player->video_hub_download_mode = 0; + 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_SUBTITLE_INFO_LOCK(player); - player->subtitle_language_list = NULL; - MMPLAYER_SUBTITLE_INFO_UNLOCK(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", + G_CALLBACK(__mmplayer_update_subtitle), + (gpointer)player); - __mmplayer_reset_gapless_state(player); + g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, + "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL); - if (player->streamer) { - __mm_player_streaming_deinitialize(player->streamer); - __mm_player_streaming_destroy(player->streamer); - player->streamer = NULL; + 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)); } - /* cleanup unlinked mime type */ - MMPLAYER_FREEIF(player->unlinked_audio_mime); - MMPLAYER_FREEIF(player->unlinked_video_mime); - MMPLAYER_FREEIF(player->unlinked_demuxer_mime); - - /* cleanup running stuffs */ - __mmplayer_cancel_eos_timer(player); - - /* cleanup gst stuffs */ - if (player->pipeline) { - MMPlayerGstElement* mainbin = player->pipeline->mainbin; - GstTagList* tag_list = player->pipeline->tag_list; - - /* first we need to disconnect all signal hander */ - __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL); - - if (player->bus_watcher) - __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher); - player->bus_watcher = 0; - - if (mainbin) { - MMPlayerGstElement* audiobin = player->pipeline->audiobin; - MMPlayerGstElement* videobin = player->pipeline->videobin; - MMPlayerGstElement* textbin = player->pipeline->textbin; - GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst)); - gst_bus_set_sync_handler(bus, NULL, NULL, NULL); - gst_object_unref(bus); + /* adding created elements to bin */ + LOGD("adding created elements to bin"); + if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) { + LOGE("failed to add elements"); + goto ERROR; + } - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); - 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\n"); - return MM_ERROR_PLAYER_INTERNAL; - } + /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */ + GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK); + GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK); - LOGW("succeeded in chaning state to NULL\n"); + /* 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) { + LOGE("failed to link elements"); + goto ERROR; + } - gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst)); + /* done. free allocated variables */ + g_list_free(element_bucket); - /* free fakesink */ - if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst) - gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst)); + if (textbin[MMPLAYER_T_QUEUE].gst) { + GstPad *pad = NULL; + GstPad *ghostpad = NULL; - /* free avsysaudiosink - avsysaudiosink should be unref when destory pipeline just after start play with BT. - Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed. - */ - MMPLAYER_FREEIF(audiobin); - MMPLAYER_FREEIF(videobin); - MMPLAYER_FREEIF(textbin); - MMPLAYER_FREEIF(mainbin); + pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink"); + if (!pad) { + LOGE("failed to get sink pad of text queue"); + goto ERROR; } - if (tag_list) - gst_tag_list_free(tag_list); + ghostpad = gst_ghost_pad_new("text_sink", pad); + gst_object_unref(pad); - MMPLAYER_FREEIF(player->pipeline); - } - MMPLAYER_FREEIF(player->album_art); + if (!ghostpad) { + LOGE("failed to create ghostpad of textbin"); + goto ERROR; + } - if (player->v_stream_caps) { - gst_caps_unref(player->v_stream_caps); - player->v_stream_caps = NULL; - } - if (player->a_stream_caps) { - gst_caps_unref(player->a_stream_caps); - player->a_stream_caps = NULL; + if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) { + LOGE("failed to add ghostpad to textbin"); + gst_object_unref(ghostpad); + goto ERROR; + } } - if (player->s_stream_caps) { - gst_caps_unref(player->s_stream_caps); - player->s_stream_caps = NULL; - } - _mmplayer_track_destroy(player); + return MM_ERROR_NONE; - if (player->sink_elements) - g_list_free(player->sink_elements); - player->sink_elements = NULL; +ERROR: + g_list_free(element_bucket); - if (player->bufmgr) { - tbm_bufmgr_deinit(player->bufmgr); - player->bufmgr = NULL; + if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) { + LOGE("remove textbin sink from sink list"); + __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst); } - LOGW("finished destroy pipeline\n"); - - MMPLAYER_FLEAVE(); - - return ret; + /* release element at __mmplayer_gst_create_text_sink_bin */ + return MM_ERROR_PLAYER_INTERNAL; } -static int __gst_realize(mm_player_t* player) +static int +__mmplayer_gst_create_text_sink_bin(mmplayer_t *player) { - gint timeout = 0; - int ret = MM_ERROR_NONE; + mmplayer_gst_element_t *textbin = NULL; + GList *element_bucket = NULL; + int surface_type = 0; + gint i = 0; MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY; + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - ret = __mmplayer_gst_create_pipeline(player); - if (ret) { - LOGE("failed to create pipeline\n"); - return ret; + /* alloc handles */ + textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM); + if (!textbin) { + LOGE("failed to allocate memory for textbin"); + return MM_ERROR_PLAYER_NO_FREE_SPACE; } - /* 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, - player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout); - - if (ret != MM_ERROR_NONE) { - /* return error if failed to set state */ - LOGE("failed to set READY state"); - return ret; + /* create bin */ + textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN; + textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin"); + if (!textbin[MMPLAYER_T_BIN].gst) { + LOGE("failed to create textbin"); + goto ERROR; } - MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY); - - /* create dot before error-return. for debugging */ - MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize"); - - MMPLAYER_FLEAVE(); - - return ret; -} - -static int __gst_unrealize(mm_player_t* player) -{ - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL; - MMPLAYER_PRINT_STATE(player); - - /* release miscellaneous information */ - __mmplayer_release_misc(player); + /* take it */ + player->pipeline->textbin = textbin; - /* destroy pipeline */ - ret = __mmplayer_gst_destroy_pipeline(player); - if (ret != MM_ERROR_NONE) { - LOGE("failed to destory pipeline\n"); - return ret; + /* fakesink */ + mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type); + LOGD("surface type for subtitle : %d", surface_type); + switch (surface_type) { + case MM_DISPLAY_SURFACE_OVERLAY: + case MM_DISPLAY_SURFACE_NULL: + case MM_DISPLAY_SURFACE_REMOTE: + if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) { + LOGE("failed to make plain text elements"); + goto ERROR; + } + break; + default: + goto ERROR; + break; } - /* release miscellaneous information. - these info needs to be released after pipeline is destroyed. */ - __mmplayer_release_misc_post(player); - - MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL); - MMPLAYER_FLEAVE(); - return ret; -} + return MM_ERROR_NONE; -static int __gst_pending_seek(mm_player_t* player) -{ - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - int ret = MM_ERROR_NONE; +ERROR: - MMPLAYER_FENTER(); + LOGD("ERROR : releasing textbin"); - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + g_list_free(element_bucket); - if (!player->pending_seek.is_pending) { - LOGD("pending seek is not reserved. nothing to do.\n"); - return ret; - } + /* release signal */ + __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN); - /* check player state if player could pending seek or not. */ - current_state = MMPLAYER_CURRENT_STATE(player); + /* release element which are not added to bin */ + for (i = 1; i < MMPLAYER_T_NUM; i++) { + /* NOTE : skip bin */ + if (textbin[i].gst) { + GstObject *parent = NULL; + parent = gst_element_get_parent(textbin[i].gst); - if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) { - LOGW("try to pending seek in %s state, try next time. \n", - MMPLAYER_STATE_GET_NAME(current_state)); - return ret; + if (!parent) { + gst_object_unref(GST_OBJECT(textbin[i].gst)); + textbin[i].gst = NULL; + } else { + gst_object_unref(GST_OBJECT(parent)); + } + } } - LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos); - - ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE); - - if (MM_ERROR_NONE != ret) - LOGE("failed to seek pending postion. just keep staying current position.\n"); + /* release textbin with it's childs */ + if (textbin[MMPLAYER_T_BIN].gst) + gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst)); - player->pending_seek.is_pending = FALSE; + MMPLAYER_FREEIF(player->pipeline->textbin); + player->pipeline->textbin = NULL; MMPLAYER_FLEAVE(); - - return ret; + return MM_ERROR_PLAYER_INTERNAL; } -static int __gst_start(mm_player_t* player) +static int +__mmplayer_gst_create_text_pipeline(mmplayer_t *player) { - gboolean sound_extraction = 0; - int ret = MM_ERROR_NONE; - gboolean async = FALSE; + mmplayer_gst_element_t *mainbin = NULL; + mmplayer_gst_element_t *textbin = NULL; + MMHandleType attrs = 0; + GstElement *subsrc = NULL; + GstElement *subparse = NULL; + gchar *subtitle_uri = NULL; + const gchar *charset = NULL; + GstPad *pad = NULL; MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* get sound_extraction property */ - mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction); + /* get mainbin */ + MMPLAYER_RETURN_VAL_IF_FAIL(player && + player->pipeline && + player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); - /* NOTE : if SetPosition was called before Start. do it now */ - /* streaming doesn't support it. so it should be always sync */ - /* !!create one more api to check if there is pending seek rather than checking variables */ - if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) { - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED; - ret = __gst_pause(player, FALSE); - if (ret != MM_ERROR_NONE) { - LOGE("failed to set state to PAUSED for pending seek\n"); - return ret; - } + mainbin = player->pipeline->mainbin; - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING; + attrs = MMPLAYER_GET_ATTRS(player); + if (!attrs) { + LOGE("cannot get content attribute"); + return MM_ERROR_PLAYER_INTERNAL; + } - if (sound_extraction) { - LOGD("setting pcm extraction\n"); + mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri); + if (!subtitle_uri || strlen(subtitle_uri) < 1) { + LOGE("subtitle uri is not proper filepath."); + return MM_ERROR_PLAYER_INVALID_URI; + } - ret = __mmplayer_set_pcm_extraction(player); - if (MM_ERROR_NONE != ret) { - LOGW("failed to set pcm extraction\n"); - return ret; - } - } else { - if (MM_ERROR_NONE != __gst_pending_seek(player)) - LOGW("failed to seek pending postion. starting from the begin of content.\n"); - } + if (!util_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; } - LOGD("current state before doing transition"); - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING; - MMPLAYER_PRINT_STATE(player); + SECURE_LOGD("subtitle file path is [%s].", subtitle_uri); - /* set pipeline state to PLAYING */ - if (player->es_player_push_mode) - async = TRUE; - /* set pipeline state to PLAYING */ - ret = __mmplayer_gst_set_state(player, - player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player)); + MMPLAYER_SUBTITLE_INFO_LOCK(player); + player->subtitle_language_list = NULL; + MMPLAYER_SUBTITLE_INFO_UNLOCK(player); - if (ret == MM_ERROR_NONE) { - MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING); - } else { - LOGE("failed to set state to PLAYING"); - return ret; + /* create the subtitle source */ + subsrc = gst_element_factory_make("filesrc", "subtitle_source"); + if (!subsrc) { + LOGE("failed to create filesrc element"); + goto ERROR; } + g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL); - /* generating debug info before returning error */ - MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start"); - - MMPLAYER_FLEAVE(); + mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC; + mainbin[MMPLAYER_M_SUBSRC].gst = subsrc; - return ret; -} + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) { + LOGW("failed to add queue"); + gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst); + mainbin[MMPLAYER_M_SUBSRC].gst = NULL; + mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM; + goto ERROR; + } -static int __gst_stop(mm_player_t* player) -{ - GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS; - MMHandleType attrs = 0; - gboolean rewind = FALSE; - gint timeout = 0; - int ret = MM_ERROR_NONE; - gboolean async = FALSE; + /* subparse */ + subparse = gst_element_factory_make("subparse", "subtitle_parser"); + if (!subparse) { + LOGE("failed to create subparse element"); + goto ERROR; + } - MMPLAYER_FENTER(); + charset = util_get_charset(subtitle_uri); + if (charset) { + LOGD("detected charset is %s", charset); + g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL); + } - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); + mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE; + mainbin[MMPLAYER_M_SUBPARSE].gst = subparse; - LOGD("current state before doing transition"); - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY; - MMPLAYER_PRINT_STATE(player); + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) { + LOGW("failed to add subparse"); + gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst); + mainbin[MMPLAYER_M_SUBPARSE].gst = NULL; + mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM; + goto ERROR; + } - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("cannot get content attribute\n"); - return MM_ERROR_PLAYER_INTERNAL; + if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) { + LOGW("failed to link subsrc and subparse"); + goto ERROR; } - /* Just set state to PAUESED and the rewind. it's usual player behavior. */ - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); + player->play_subtitle = TRUE; + player->adjust_subtitle_pos = 0; - if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) || - (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked)) - rewind = TRUE; + LOGD("play subtitle using subtitle file"); - if (player->es_player_push_mode) - async = TRUE; - /* set gst state */ - ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout); + if (player->pipeline->textbin == NULL) { + if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) { + LOGE("failed to create text sink bin. continuing without text"); + goto ERROR; + } - /* return if set_state has failed */ - if (ret != MM_ERROR_NONE) { - LOGE("failed to set state.\n"); - return ret; - } + textbin = player->pipeline->textbin; - /* rewind */ - if (rewind) { - if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, - GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, - GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { - LOGW("failed to rewind\n"); - ret = MM_ERROR_PLAYER_SEEK; - } - } + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) { + LOGW("failed to add textbin"); - /* initialize */ - player->sent_bos = FALSE; + /* release signal */ + __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN); + + /* release textbin with it's childs */ + gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst)); + MMPLAYER_FREEIF(player->pipeline->textbin); + player->pipeline->textbin = textbin = NULL; + goto ERROR; + } - if (player->es_player_push_mode) //for cloudgame - timeout = 0; + LOGD("link text input selector and textbin ghost pad"); - /* wait for seek to complete */ - change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND); - if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) { - MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY); + player->textsink_linked = 1; + player->external_text_idx = 0; + LOGI("textsink is linked"); } else { - LOGE("fail to stop player.\n"); - ret = MM_ERROR_PLAYER_INTERNAL; - __mmplayer_dump_pipeline_state(player); + textbin = player->pipeline->textbin; + LOGD("text bin has been created. reuse it."); + player->external_text_idx = 1; } - /* generate dot file if enabled */ - MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop"); - - MMPLAYER_FLEAVE(); + if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) { + LOGW("failed to link subparse and textbin"); + goto ERROR; + } - return ret; -} + pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink"); + if (!pad) { + LOGE("failed to get sink pad from textsink to probe data"); + goto ERROR; + } -int __gst_pause(mm_player_t* player, gboolean async) -{ - int ret = MM_ERROR_NONE; + gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, + __mmplayer_subtitle_adjust_position_probe, player, NULL); - MMPLAYER_FENTER(); + gst_object_unref(pad); + pad = NULL; - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); + /* create dot. for debugging */ + MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle"); + MMPLAYER_FLEAVE(); - LOGD("current state before doing transition"); - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED; - MMPLAYER_PRINT_STATE(player); + return MM_ERROR_NONE; - /* set pipeline status to PAUSED */ - ret = __mmplayer_gst_set_state(player, - player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player)); +ERROR: + /* release text pipeline resource */ + player->textsink_linked = 0; - if (FALSE == async) { - if (ret != MM_ERROR_NONE) { - GstMessage *msg = NULL; - GTimer *timer = NULL; - gdouble MAX_TIMEOUT_SEC = 3; + /* release signal */ + __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN); - LOGE("failed to set state to PAUSED"); + if (player->pipeline->textbin) { + LOGE("remove textbin"); - if (player->msg_posted) { - LOGE("error msg is already posted."); - return ret; - } + /* release textbin with it's childs */ + MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN); + MMPLAYER_FREEIF(player->pipeline->textbin); + player->pipeline->textbin = NULL; - timer = g_timer_new(); - g_timer_start(timer); + } - GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)); + /* release subtitle elem */ + MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC); + MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE); - do { - msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND); - if (msg) { - if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) { - GError *error = NULL; + return MM_ERROR_PLAYER_INTERNAL; +} - /* parse error code */ - gst_message_parse_error(msg, &error, NULL); +gboolean +__mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data) +{ + mmplayer_t *player = (mmplayer_t *)data; + MMMessageParamType msg = {0, }; + GstClockTime duration = 0; + gpointer text = NULL; + guint text_size = 0; + gboolean ret = TRUE; + GstMapInfo mapinfo = GST_MAP_INFO_INIT; - if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) { - /* Note : the streaming error from the streaming source is handled - * using __mmplayer_handle_streaming_error. - */ - __mmplayer_handle_streaming_error(player, msg); + MMPLAYER_FENTER(); - } else if (error) { - LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code); + MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); + MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE); - if (error->domain == GST_STREAM_ERROR) - ret = __gst_handle_stream_error(player, error, msg); - else if (error->domain == GST_RESOURCE_ERROR) - ret = __gst_handle_resource_error(player, error->code, NULL); - else if (error->domain == GST_LIBRARY_ERROR) - ret = __gst_handle_library_error(player, error->code); - else if (error->domain == GST_CORE_ERROR) - ret = __gst_handle_core_error(player, error->code); + if (player->is_subtitle_force_drop) { + LOGW("subtitle is dropped forcedly."); + return ret; + } - g_error_free(error); - } - player->msg_posted = TRUE; - } - gst_message_unref(msg); - } - } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC)); - /* clean */ - gst_object_unref(bus); - g_timer_stop(timer); - g_timer_destroy(timer); + gst_buffer_map(buffer, &mapinfo, GST_MAP_READ); + text = mapinfo.data; + text_size = mapinfo.size; - return ret; + if (player->set_mode.subtitle_off) { + LOGD("subtitle is OFF."); + return TRUE; + } - } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) && - (!player->pipeline->videobin) && (!player->pipeline->audiobin)) { + if (!text || (text_size == 0)) { + LOGD("There is no subtitle to be displayed."); + return TRUE; + } - return MM_ERROR_PLAYER_CODEC_NOT_FOUND; + msg.data = (void *)text; - } else if (ret == MM_ERROR_NONE) { + duration = GST_BUFFER_DURATION(buffer); - MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED); - } + if (!GST_CLOCK_TIME_IS_VALID(duration)) { + if (player->duration > GST_BUFFER_PTS(buffer)) + duration = player->duration - GST_BUFFER_PTS(buffer); + else + duration = 0; + LOGI("subtitle duration is invalid, subtitle duration change " + "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration)); } + msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration); - /* generate dot file before returning error */ - MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause"); + LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data); + + MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg); + gst_buffer_unmap(buffer, &mapinfo); MMPLAYER_FLEAVE(); return ret; } -int __gst_resume(mm_player_t* player, gboolean async) +static GstPadProbeReturn +__mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) { - int ret = MM_ERROR_NONE; - gint timeout = 0; + mmplayer_t *player = (mmplayer_t *)u_data; + GstClockTime cur_timestamp = 0; + gint64 adjusted_timestamp = 0; + GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); - MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, - MM_ERROR_PLAYER_NOT_INITIALIZED); + if (player->set_mode.subtitle_off) { + LOGD("subtitle is OFF."); + return TRUE; + } - LOGD("current state before doing transition"); - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING; - MMPLAYER_PRINT_STATE(player); + if (player->adjust_subtitle_pos == 0) { + LOGD("nothing to do"); + return TRUE; + } - /* generate dot file before returning error */ - MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume"); + cur_timestamp = GST_BUFFER_TIMESTAMP(buffer); + adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000)); - if (async) - LOGD("do async state transition to PLAYING.\n"); + if (adjusted_timestamp < 0) { + LOGD("adjusted_timestamp under zero"); + MMPLAYER_FLEAVE(); + return FALSE; + } - /* set pipeline state to PLAYING */ - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); + GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp; + LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "", + GST_TIME_ARGS(cur_timestamp), + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); - ret = __mmplayer_gst_set_state(player, - player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout); - if (ret != MM_ERROR_NONE) { - LOGE("failed to set state to PLAYING\n"); - return ret; - } else { - if (async == FALSE) { - // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING); - LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING); - ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING); - } + return GST_PAD_PROBE_OK; +} + +static int +__mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position) +{ + MMPLAYER_FENTER(); + + /* check player and subtitlebin are created */ + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API); + + if (position == 0) { + LOGD("nothing to do"); + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; } - /* generate dot file before returning error */ - MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume"); + /* check current postion */ + player->adjust_subtitle_pos = position; + + LOGD("save adjust_subtitle_pos in player"); MMPLAYER_FLEAVE(); - return ret; + return MM_ERROR_NONE; } +/** + * This function is to create audio or video pipeline for playing. + * + * @param player [in] handle of player + * + * @return This function returns zero on success. + * @remark + * @see + */ static int -__gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) +__mmplayer_gst_create_pipeline(mmplayer_t *player) { - unsigned long dur_msec = 0; - gint64 dur_nsec = 0; - gint64 pos_nsec = 0; - gboolean ret = TRUE; - gboolean accurated = FALSE; - GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH; + int ret = MM_ERROR_NONE; + mmplayer_gst_element_t *mainbin = NULL; + MMHandleType attrs = 0; MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP); - - if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING - && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED) - goto PENDING; + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - if (!MMPLAYER_IS_MS_BUFF_SRC(player)) { - /* check duration */ - /* NOTE : duration cannot be zero except live streaming. - * Since some element could have some timing problemn with quering duration, try again. - */ - if (!player->duration) { - if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) { - /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly. - * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */ - if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) { - player->pending_seek.is_pending = TRUE; - player->pending_seek.format = format; - player->pending_seek.pos = position; - player->doing_seek = FALSE; - MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); - return MM_ERROR_NONE; - } else { - goto SEEK_ERROR; - } - } - player->duration = dur_nsec; - } + /* get profile attribute */ + attrs = MMPLAYER_GET_ATTRS(player); + if (!attrs) { + LOGE("failed to get content attribute"); + goto INIT_ERROR; + } - if (player->duration) { - dur_msec = GST_TIME_AS_MSECONDS(player->duration); - } else { - LOGE("could not get the duration. fail to seek.\n"); - goto SEEK_ERROR; - } + /* create pipeline handles */ + if (player->pipeline) { + LOGE("pipeline should be released before create new one"); + goto INIT_ERROR; } - LOGD("playback rate: %f\n", player->playback_rate); - mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated); - if (accurated) - seek_flags |= GST_SEEK_FLAG_ACCURATE; - else - seek_flags |= GST_SEEK_FLAG_KEY_UNIT; + player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t)); + if (player->pipeline == NULL) + goto INIT_ERROR; - /* do seek */ - switch (format) { - case MM_PLAYER_POS_FORMAT_TIME: - { - if (!MMPLAYER_IS_MS_BUFF_SRC(player)) { - GstQuery *query = NULL; - gboolean seekable = FALSE; - - /* check position is valid or not */ - if (position > dur_msec) - goto INVALID_ARGS; - - query = gst_query_new_seeking(GST_FORMAT_TIME); - if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) { - gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL); - gst_query_unref(query); - - if (!seekable) { - LOGW("non-seekable content"); - player->doing_seek = FALSE; - return MM_ERROR_PLAYER_NO_OP; - } - } else { - LOGW("failed to get seeking query"); - gst_query_unref(query); /* keep seeking operation */ - } + /* create mainbin */ + mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM); + if (mainbin == NULL) + goto INIT_ERROR; - LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec); + /* create pipeline */ + mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE; + mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player"); + if (!mainbin[MMPLAYER_M_PIPE].gst) { + LOGE("failed to create pipeline"); + g_free(mainbin); + goto INIT_ERROR; + } - /* For rtspsrc stack , npt-start value coming from server is used for finding the current position. - But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing. - This causes problem is position calculation during normal pause resume scenarios also. - Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */ - if ((MMPLAYER_IS_RTSP_STREAMING(player)) && - (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) { - if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) - LOGW("getting current position failed in seek\n"); + player->pipeline->mainbin = mainbin; - player->last_position = pos_nsec; - g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL); - } + /* 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 (player->doing_seek) { - LOGD("not completed seek"); - return MM_ERROR_PLAYER_DOING_SEEK; - } - } + if (ret != MM_ERROR_NONE) { + LOGE("failed to create some elements"); + goto INIT_ERROR; + } - if (!internal_called) - player->doing_seek = TRUE; + /* Note : check whether subtitle atrribute 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"); - pos_nsec = position * G_GINT64_CONSTANT(1000000); + /* add bus watch */ + ret = __mmplayer_gst_add_bus_watch(player); + if (ret != MM_ERROR_NONE) { + LOGE("failed to add bus watch"); + goto INIT_ERROR; + } - if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) { - gint64 cur_time = 0; + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; - /* get current position */ - gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time); +INIT_ERROR: + __mmplayer_gst_destroy_pipeline(player); + return MM_ERROR_PLAYER_INTERNAL; +} - /* flush */ - GstEvent *event = gst_event_new_seek(1.0, - GST_FORMAT_TIME, - (GstSeekFlags)GST_SEEK_FLAG_FLUSH, - GST_SEEK_TYPE_SET, cur_time, - GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); - if (event) - __gst_send_event_to_sink(player, event); +static void +__mmplayer_reset_gapless_state(mmplayer_t *player) +{ + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player + && player->pipeline + && player->pipeline->audiobin + && player->pipeline->audiobin[MMPLAYER_A_BIN].gst); - if (!MMPLAYER_IS_RTSP_STREAMING(player)) - __gst_pause(player, FALSE); - } + memset(&player->gapless, 0, sizeof(mmplayer_gapless_t)); - /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change). - that's why set position through property. */ - if ((MMPLAYER_IS_RTSP_STREAMING(player)) && - (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) && - (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) && - (!player->videodec_linked) && (!player->audiodec_linked)) { + MMPLAYER_FLEAVE(); + return; +} - g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL); - LOGD("[%s] set position =%"GST_TIME_FORMAT, - GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec)); - player->doing_seek = FALSE; - MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); - } else { - ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, - GST_FORMAT_TIME, seek_flags, - GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); - } +static int +__mmplayer_gst_destroy_pipeline(mmplayer_t *player) +{ + gint timeout = 0; + int ret = MM_ERROR_NONE; - if (!ret) { - LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec); - goto SEEK_ERROR; - } - } - break; + MMPLAYER_FENTER(); - case MM_PLAYER_POS_FORMAT_PERCENT: - { - LOGD("seeking to(%lu)%% \n", position); + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE); - if (player->doing_seek) { - LOGD("not completed seek"); - return MM_ERROR_PLAYER_DOING_SEEK; - } + /* cleanup stuffs */ + MMPLAYER_FREEIF(player->type); + player->no_more_pad = FALSE; + player->num_dynamic_pad = 0; + player->demux_pad_index = 0; - if (!internal_called) - player->doing_seek = TRUE; + MMPLAYER_SUBTITLE_INFO_LOCK(player); + player->subtitle_language_list = NULL; + MMPLAYER_SUBTITLE_INFO_UNLOCK(player); - /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */ - pos_nsec = (gint64)((position * player->duration) / 100); - ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, - GST_FORMAT_TIME, seek_flags, - GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); - if (!ret) { - LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec); - goto SEEK_ERROR; - } - } - break; + __mmplayer_reset_gapless_state(player); - default: - goto INVALID_ARGS; + if (player->streamer) { + __mm_player_streaming_initialize(player->streamer, FALSE); + __mm_player_streaming_destroy(player->streamer); + player->streamer = NULL; } - /* NOTE : store last seeking point to overcome some bad operation - * (returning zero when getting current position) of some elements - */ - player->last_position = pos_nsec; - - /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */ - if (player->playback_rate > 1.0) - _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE); - - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; + /* cleanup unlinked mime type */ + MMPLAYER_FREEIF(player->unlinked_audio_mime); + MMPLAYER_FREEIF(player->unlinked_video_mime); + MMPLAYER_FREEIF(player->unlinked_demuxer_mime); -PENDING: - player->pending_seek.is_pending = TRUE; - player->pending_seek.format = format; - player->pending_seek.pos = position; + /* cleanup running stuffs */ + __mmplayer_cancel_eos_timer(player); - LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n", - MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos); + /* cleanup gst stuffs */ + if (player->pipeline) { + mmplayer_gst_element_t *mainbin = player->pipeline->mainbin; + GstTagList *tag_list = player->pipeline->tag_list; - return MM_ERROR_NONE; + /* first we need to disconnect all signal hander */ + __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL); -INVALID_ARGS: - LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format); - return MM_ERROR_INVALID_ARGUMENT; + if (mainbin) { + mmplayer_gst_element_t *audiobin = player->pipeline->audiobin; + mmplayer_gst_element_t *videobin = player->pipeline->videobin; + mmplayer_gst_element_t *textbin = player->pipeline->textbin; + GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst)); + gst_bus_set_sync_handler(bus, NULL, NULL, NULL); + gst_object_unref(bus); -SEEK_ERROR: - player->doing_seek = FALSE; - return MM_ERROR_PLAYER_SEEK; -} + timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); + 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; + } -#define TRICKPLAY_OFFSET GST_MSECOND + LOGW("succeeded in changing state to NULL"); -static int -__gst_get_position(mm_player_t* player, int format, unsigned long* position) -{ - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - gint64 pos_msec = 0; - gboolean ret = TRUE; + gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst)); - MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin, - MM_ERROR_PLAYER_NOT_INITIALIZED); + /* free fakesink */ + if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst) + gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst)); - current_state = MMPLAYER_CURRENT_STATE(player); + /* free avsysaudiosink + avsysaudiosink should be unref when destory pipeline just after start play with BT. + Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed. + */ + MMPLAYER_FREEIF(audiobin); + MMPLAYER_FREEIF(videobin); + MMPLAYER_FREEIF(textbin); + MMPLAYER_FREEIF(mainbin); + } - /* NOTE : query position except paused state to overcome some bad operation - * please refer to below comments in details - */ - if (current_state != MM_PLAYER_STATE_PAUSED) - ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec); + if (tag_list) + gst_tag_list_unref(tag_list); - /* NOTE : get last point to overcome some bad operation of some elements - *(returning zero when getting current position in paused state - * and when failed to get postion during seeking - */ - if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) { - LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state); + MMPLAYER_FREEIF(player->pipeline); + } + MMPLAYER_FREEIF(player->album_art); - if (player->playback_rate < 0.0) - pos_msec = player->last_position - TRICKPLAY_OFFSET; - else - pos_msec = player->last_position; + if (player->v_stream_caps) { + gst_caps_unref(player->v_stream_caps); + player->v_stream_caps = NULL; + } - if (!ret) - pos_msec = player->last_position; - else - player->last_position = pos_msec; + if (player->a_stream_caps) { + gst_caps_unref(player->a_stream_caps); + player->a_stream_caps = NULL; + } - LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec)); + if (player->s_stream_caps) { + gst_caps_unref(player->s_stream_caps); + player->s_stream_caps = NULL; + } + __mmplayer_track_destroy(player); - } else { - if (player->duration > 0 && pos_msec > player->duration) - pos_msec = player->duration; + if (player->sink_elements) + g_list_free(player->sink_elements); + player->sink_elements = NULL; - player->last_position = pos_msec; + if (player->bufmgr) { + tbm_bufmgr_deinit(player->bufmgr); + player->bufmgr = NULL; } - switch (format) { - case MM_PLAYER_POS_FORMAT_TIME: - *position = GST_TIME_AS_MSECONDS(pos_msec); - break; + LOGW("finished destroy pipeline"); - case MM_PLAYER_POS_FORMAT_PERCENT: - { - if (player->duration <= 0) { - LOGD("duration is [%lld], so returning position 0\n", player->duration); - *position = 0; - } else { - LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration); - *position = pos_msec * 100 / player->duration; - } - break; - } - default: - return MM_ERROR_PLAYER_INTERNAL; - } + MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; + return ret; } - -static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos) +static int +__mmplayer_gst_realize(mmplayer_t *player) { -#define STREAMING_IS_FINISHED 0 -#define BUFFERING_MAX_PER 100 -#define DEFAULT_PER_VALUE -1 -#define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min)) - - MMPlayerGstElement *mainbin = NULL; - gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE; - gint64 buffered_total = 0; - unsigned long position = 0; - gint buffered_sec = -1; - GstBufferingMode mode = GST_BUFFERING_STREAM; - gint64 content_size_time = player->duration; - guint64 content_size_bytes = player->http_content_size; + gint timeout = 0; + int ret = MM_ERROR_NONE; - MMPLAYER_RETURN_VAL_IF_FAIL(player && - player->pipeline && - player->pipeline->mainbin, - MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT); + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - *start_pos = 0; - *stop_pos = 0; + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY; - if (!MMPLAYER_IS_HTTP_STREAMING(player)) { - /* and rtsp is not ready yet. */ - LOGW("it's only used for http streaming case.\n"); - return MM_ERROR_PLAYER_NO_OP; + ret = __mmplayer_gst_create_pipeline(player); + if (ret) { + LOGE("failed to create pipeline"); + return ret; } - if (format != MM_PLAYER_POS_FORMAT_PERCENT) { - LOGW("Time format is not supported yet.\n"); - return MM_ERROR_INVALID_ARGUMENT; - } + /* 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, + player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout); - if (content_size_time <= 0 || content_size_bytes <= 0) { - LOGW("there is no content size."); - return MM_ERROR_NONE; + if (ret != MM_ERROR_NONE) { + /* return error if failed to set state */ + LOGE("failed to set READY state"); + return ret; } - if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) { - LOGW("fail to get current position."); - return MM_ERROR_NONE; - } + MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY); - LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes", - position, (guint)(content_size_time/GST_SECOND), content_size_bytes); + /* create dot before error-return. for debugging */ + MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize"); - mainbin = player->pipeline->mainbin; - start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time)); - - if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) { - GstQuery *query = NULL; - gint byte_in_rate = 0, byte_out_rate = 0; - gint64 estimated_total = 0; - - query = gst_query_new_buffering(GST_FORMAT_BYTES); - if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) { - LOGW("fail to get buffering query from queue2"); - if (query) - gst_query_unref(query); - return MM_ERROR_NONE; - } + MMPLAYER_FLEAVE(); - gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL); - LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate); + return ret; +} - if (mode == GST_BUFFERING_STREAM) { - /* using only queue in case of push mode(ts / mp3) */ - if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst, - GST_FORMAT_BYTES, &buffered_total)) { - LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total); - stop_per = 100 * buffered_total / content_size_bytes; - } - } else { - /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */ - guint idx = 0; - guint num_of_ranges = 0; - gint64 start_byte = 0, stop_byte = 0; - - gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total); - if (estimated_total != STREAMING_IS_FINISHED) { - /* buffered size info from queue2 */ - num_of_ranges = gst_query_get_n_buffering_ranges(query); - for (idx = 0; idx < num_of_ranges; idx++) { - gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte); - LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte); - - buffered_total += (stop_byte - start_byte); - } - } else - stop_per = BUFFERING_MAX_PER; - } - gst_query_unref(query); - } +static int +__mmplayer_gst_unrealize(mmplayer_t *player) +{ + int ret = MM_ERROR_NONE; - if (stop_per == DEFAULT_PER_VALUE) { - guint dur_sec = (guint)(content_size_time/GST_SECOND); - if (dur_sec > 0) { - guint avg_byterate = (guint)(content_size_bytes/dur_sec); + MMPLAYER_FENTER(); - /* buffered size info from multiqueue */ - if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) { - guint curr_size_bytes = 0; - g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst), - "curr-size-bytes", &curr_size_bytes, NULL); - LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes); - buffered_total += curr_size_bytes; - } + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL; + MMPLAYER_PRINT_STATE(player); - if (avg_byterate > 0) - buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate)); - else if (player->total_maximum_bitrate > 0) - buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate)); - else if (player->total_bitrate > 0) - buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate)); + /* release miscellaneous information */ + __mmplayer_release_misc(player); - if (buffered_sec >= 0) - stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec); - } + /* destroy pipeline */ + ret = __mmplayer_gst_destroy_pipeline(player); + if (ret != MM_ERROR_NONE) { + LOGE("failed to destory pipeline"); + return ret; } - *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100); - *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100); + /* release miscellaneous information. + these info needs to be released after pipeline is destroyed. */ + __mmplayer_release_misc_post(player); + + MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL); - LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n", - buffered_total, buffered_sec, *start_pos, *stop_pos); + MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; + return ret; } static int -__gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) +__mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param) { MMPLAYER_FENTER(); if (!player) { - LOGW("set_message_callback is called with invalid player handle\n"); + LOGW("set_message_callback is called with invalid player handle"); return MM_ERROR_PLAYER_NOT_INITIALIZED; } player->msg_cb = callback; player->msg_cb_param = user_param; - LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param); + LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param); MMPLAYER_FLEAVE(); return MM_ERROR_NONE; } -static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) +int +__mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data) { - int ret = MM_ERROR_PLAYER_INVALID_URI; + int ret = MM_ERROR_NONE; char *path = NULL; MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE); - - memset(data, 0, sizeof(MMPlayerParseProfile)); - - if ((path = strstr(uri, "es_buff://"))) { - if (strlen(path)) { - strncpy(data->uri, uri, MM_MAX_URL_LEN-1); - data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF; - ret = MM_ERROR_NONE; - } - } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) { - if (strlen(path)) { - strncpy(data->uri, uri, MM_MAX_URL_LEN-1); - data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; - ret = MM_ERROR_NONE; - } - } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) { - if (strlen(path)) { - gchar *tmp = NULL; - strncpy(data->uri, uri, MM_MAX_URL_LEN-1); - tmp = g_ascii_strdown(uri, strlen(uri)); - - if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest"))) - data->uri_type = MM_PLAYER_URI_TYPE_SS; - else - data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP; - - ret = MM_ERROR_NONE; - g_free(tmp); - } - } else if ((path = strstr(uri, "rtspu://"))) { - if (strlen(path)) { - strncpy(data->uri, uri, MM_MAX_URL_LEN-1); - data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; - ret = MM_ERROR_NONE; - } - } else if ((path = strstr(uri, "rtspr://"))) { - strncpy(data->uri, path, MM_MAX_URL_LEN-1); - char *separater = strstr(path, "*"); + MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI); + MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL); + MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI); - if (separater) { - int urgent_len = 0; - char *urgent = separater + strlen("*"); + memset(data, 0, sizeof(mmplayer_parse_profile_t)); - if ((urgent_len = strlen(urgent))) { - data->uri[strlen(path) - urgent_len - strlen("*")] = '\0'; - strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1); - data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; - ret = MM_ERROR_NONE; - } - } - } else if ((path = strstr(uri, "mms://"))) { - if (strlen(path)) { - strncpy(data->uri, uri, MM_MAX_URL_LEN-1); - data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS; - ret = MM_ERROR_NONE; - } + if (strstr(uri, "es_buff://")) { + __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF); + } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) { + __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP); + } else if (strstr(uri, "http://") || strstr(uri, "https://")) { + gchar *tmp = NULL; + tmp = g_ascii_strdown(uri, strlen(uri)); + if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest"))) + __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS); + else + __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP); + g_free(tmp); + } else if (strstr(uri, "mms://")) { + __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS); } else if ((path = strstr(uri, "mem://"))) { - if (strlen(path)) { - int mem_size = 0; - char *buffer = NULL; - char *seperator = strchr(path, ','); - char ext[100] = {0,}, size[100] = {0,}; - - if (seperator) { - if ((buffer = strstr(path, "ext="))) { - buffer += strlen("ext="); - - if (strlen(buffer)) { - strncpy(ext, buffer, 99); - - if ((seperator = strchr(ext, ',')) - || (seperator = strchr(ext, ' ')) - || (seperator = strchr(ext, '\0'))) { - seperator[0] = '\0'; - } - } - } - - if ((buffer = strstr(path, "size="))) { - buffer += strlen("size="); - - if (strlen(buffer) > 0) { - strncpy(size, buffer, 99); - - if ((seperator = strchr(size, ',')) - || (seperator = strchr(size, ' ')) - || (seperator = strchr(size, '\0'))) { - seperator[0] = '\0'; - } - - mem_size = atoi(size); - } - } - } - - LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param); - if (mem_size && param) { - if (data->input_mem.buf) - free(data->input_mem.buf); - data->input_mem.buf = malloc(mem_size); - - if (data->input_mem.buf) { - memcpy(data->input_mem.buf, param, mem_size); - data->input_mem.len = mem_size; - ret = MM_ERROR_NONE; - } else { - LOGE("failed to alloc mem %d", mem_size); - ret = MM_ERROR_PLAYER_INTERNAL; - } - - data->input_mem.offset = 0; - data->uri_type = MM_PLAYER_URI_TYPE_MEM; - } - } + ret = __mmplayer_set_mem_uri(data, path, param); } else { - gchar *location = NULL; - GError *err = NULL; - - if ((path = strstr(uri, "file://"))) { - - location = g_filename_from_uri(uri, NULL, &err); - - if (!location || (err != NULL)) { - LOGE("Invalid URI '%s' for filesrc: %s", path, - (err != NULL) ? err->message : "unknown error"); - - if (err) g_error_free(err); - if (location) g_free(location); - - data->uri_type = MM_PLAYER_URI_TYPE_NONE; - goto exit; - } - - LOGD("path from uri: %s", location); - } - - path = (location != NULL) ? (location) : ((char*)uri); - int file_stat = MM_ERROR_NONE; - - file_stat = util_exist_file_path(path); - - /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */ - if (file_stat == MM_ERROR_NONE) { - g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path); - - if (util_is_sdp_file(path)) { - LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n"); - data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; - } else { - data->uri_type = MM_PLAYER_URI_TYPE_FILE; - } - ret = MM_ERROR_NONE; - } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) { - data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION; - } else { - LOGE("invalid uri, could not play..\n"); - data->uri_type = MM_PLAYER_URI_TYPE_NONE; - } - - if (location) g_free(location); + ret = __mmplayer_set_file_uri(data, uri); } -exit: if (data->uri_type == MM_PLAYER_URI_TYPE_NONE) ret = MM_ERROR_PLAYER_FILE_NOT_FOUND; else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION) ret = MM_ERROR_PLAYER_PERMISSION_DENIED; /* dump parse result */ - SECURE_LOGW("incomming uri : %s\n", uri); - LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n", + SECURE_LOGW("incoming uri : %s", uri); + LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s", data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent); MMPLAYER_FLEAVE(); @@ -8102,25 +4425,25 @@ exit: return ret; } -gboolean -__mmplayer_can_do_interrupt(mm_player_t *player) +static gboolean +__mmplayer_can_do_interrupt(mmplayer_t *player) { if (!player || !player->pipeline || !player->attrs) { LOGW("not initialized"); goto FAILED; } - if (player->set_mode.pcm_extraction) { - LOGW("leave right now, %d", player->set_mode.pcm_extraction); + if (player->audio_decoded_cb) { + LOGW("not support in pcm extraction mode"); goto FAILED; } /* check if seeking */ - if (player->doing_seek) { + if (player->seek_state != MMPLAYER_SEEK_NONE) { MMMessageParamType msg_param; memset(&msg_param, 0, sizeof(MMMessageParamType)); msg_param.code = MM_ERROR_PLAYER_SEEK; - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); goto FAILED; } @@ -8155,15 +4478,15 @@ static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data) { - mm_player_t *player = NULL; + mmplayer_t *player = NULL; MMPLAYER_FENTER(); if (user_data == NULL) { - LOGE("- user_data is null\n"); + LOGE("- user_data is null"); return FALSE; } - player = (mm_player_t *)user_data; + player = (mmplayer_t *)user_data; /* do something to release resource here. * player stop and interrupt forwarding */ @@ -8171,16 +4494,16 @@ __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, LOGW("no need to interrupt, so leave"); } else { MMMessageParamType msg = {0, }; - unsigned long pos = 0; + gint64 pos = 0; player->interrupted_by_resource = TRUE; /* get last play position */ - if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) { + 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 = (unsigned int)pos; + msg.time.elapsed = pos; MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg); } LOGD("video resource conflict so, resource will be freed by unrealizing"); @@ -8201,13 +4524,22 @@ __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, return FALSE; } +static void +__mmplayer_initialize_video_roi(mmplayer_t *player) +{ + player->video_roi.scale_x = 0.0; + player->video_roi.scale_y = 0.0; + player->video_roi.scale_width = 1.0; + player->video_roi.scale_height = 1.0; +} + int _mmplayer_create_player(MMHandleType handle) { int ret = MM_ERROR_PLAYER_INTERNAL; bool enabled = false; - mm_player_t* player = MM_PLAYER_CAST(handle); + mmplayer_t *player = MM_PLAYER_CAST(handle); MMPLAYER_FENTER(); @@ -8226,13 +4558,13 @@ _mmplayer_create_player(MMHandleType handle) player->attrs = _mmplayer_construct_attribute(handle); if (!player->attrs) { - LOGE("Failed to construct attributes\n"); + LOGE("Failed to construct attributes"); return ret; } /* initialize gstreamer with configured parameter */ if (!__mmplayer_init_gstreamer(player)) { - LOGE("Initializing gstreamer failed\n"); + LOGE("Initializing gstreamer failed"); _mmplayer_deconstruct_attribute(handle); return ret; } @@ -8243,20 +4575,20 @@ _mmplayer_create_player(MMHandleType handle) /* create update tag lock */ g_mutex_init(&player->update_tag_lock); - /* create next play mutex */ - g_mutex_init(&player->next_play_thread_mutex); + /* create gapless play mutex */ + g_mutex_init(&player->gapless_play_thread_mutex); - /* create next play cond */ - g_cond_init(&player->next_play_thread_cond); + /* create gapless play cond */ + g_cond_init(&player->gapless_play_thread_cond); - /* create next play thread */ - player->next_play_thread = - g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL); - if (!player->next_play_thread) { - LOGE("failed to create next play thread"); + /* create gapless play thread */ + player->gapless_play_thread = + g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL); + if (!player->gapless_play_thread) { + LOGE("failed to create gapless play thread"); ret = MM_ERROR_PLAYER_RESOURCE_LIMIT; - g_mutex_clear(&player->next_play_thread_mutex); - g_cond_clear(&player->next_play_thread_cond); + g_mutex_clear(&player->gapless_play_thread_mutex); + g_cond_clear(&player->gapless_play_thread_cond); goto ERROR; } @@ -8269,23 +4601,19 @@ _mmplayer_create_player(MMHandleType handle) ret = _mmplayer_initialize_video_capture(player); if (ret != MM_ERROR_NONE) { - LOGE("failed to initialize video capture\n"); + LOGE("failed to initialize video capture"); goto ERROR; } /* initialize resource manager */ - if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create( - MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player, - &player->resource_manager)) { - LOGE("failed to initialize resource manager\n"); + 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"); + ret = MM_ERROR_PLAYER_INTERNAL; goto ERROR; } - if (MMPLAYER_IS_HTTP_PD(player)) { - player->pd_downloader = NULL; - player->pd_file_save_path = NULL; - } - /* create video bo lock and cond */ g_mutex_init(&player->video_bo_mutex); g_cond_init(&player->video_bo_cond); @@ -8305,10 +4633,6 @@ _mmplayer_create_player(MMHandleType handle) player->playback_rate = DEFAULT_PLAYBACK_RATE; player->play_subtitle = FALSE; - player->use_deinterleave = FALSE; - player->max_audio_channels = 0; - player->video_share_api_delta = 0; - player->video_share_clock_delta = 0; 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; @@ -8344,33 +4668,34 @@ _mmplayer_create_player(MMHandleType handle) player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV; player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV; + __mmplayer_initialize_video_roi(player); + /* set player state to null */ MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout; MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL); + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; ERROR: /* free lock */ g_mutex_clear(&player->fsink_lock); - /* free update tag lock */ g_mutex_clear(&player->update_tag_lock); - g_queue_free(player->bus_msg_q); + /* free gapless play thread */ + if (player->gapless_play_thread) { + MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player); + player->gapless_play_thread_exit = TRUE; + MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player); + MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player); - /* free next play thread */ - if (player->next_play_thread) { - MMPLAYER_NEXT_PLAY_THREAD_LOCK(player); - player->next_play_thread_exit = TRUE; - MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player); - MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player); - - g_thread_join(player->next_play_thread); - player->next_play_thread = NULL; + g_thread_join(player->gapless_play_thread); + player->gapless_play_thread = NULL; - g_mutex_clear(&player->next_play_thread_mutex); - g_cond_clear(&player->next_play_thread_cond); + g_mutex_clear(&player->gapless_play_thread_mutex); + g_cond_clear(&player->gapless_play_thread_cond); } /* release attributes */ @@ -8382,32 +4707,32 @@ ERROR: } static gboolean -__mmplayer_init_gstreamer(mm_player_t* player) +__mmplayer_init_gstreamer(mmplayer_t *player) { static gboolean initialized = FALSE; static const int max_argc = 50; - gint* argc = NULL; - gchar** argv = NULL; - gchar** argv2 = NULL; + gint *argc = NULL; + gchar **argv = NULL; + gchar **argv2 = NULL; GError *err = NULL; int i = 0; int arg_count = 0; if (initialized) { - LOGD("gstreamer already initialized.\n"); + LOGD("gstreamer already initialized."); return TRUE; } /* alloc */ argc = malloc(sizeof(int)); - argv = malloc(sizeof(gchar*) * max_argc); - argv2 = malloc(sizeof(gchar*) * max_argc); + argv = malloc(sizeof(gchar *) * max_argc); + argv2 = malloc(sizeof(gchar *) * max_argc); if (!argc || !argv || !argv2) goto ERROR; - memset(argv, 0, sizeof(gchar*) * max_argc); - memset(argv2, 0, sizeof(gchar*) * max_argc); + memset(argv, 0, sizeof(gchar *) * max_argc); + memset(argv2, 0, sizeof(gchar *) * max_argc); /* add initial */ *argc = 1; @@ -8438,18 +4763,18 @@ __mmplayer_init_gstreamer(mm_player_t* player) (*argc)++; } - LOGD("initializing gstreamer with following parameter\n"); - LOGD("argc : %d\n", *argc); + LOGD("initializing gstreamer with following parameter"); + LOGD("argc : %d", *argc); arg_count = *argc; for (i = 0; i < arg_count; i++) { argv2[i] = argv[i]; - LOGD("argv[%d] : %s\n", i, argv2[i]); + LOGD("argv[%d] : %s", i, argv2[i]); } /* initializing gstreamer */ if (!gst_init_check(argc, &argv, &err)) { - LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred"); + LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred"); if (err) g_error_free(err); @@ -8457,7 +4782,7 @@ __mmplayer_init_gstreamer(mm_player_t* player) } /* release */ for (i = 0; i < arg_count; i++) { - //LOGD("release - argv[%d] : %s\n", i, argv2[i]); + //LOGD("release - argv[%d] : %s", i, argv2[i]); MMPLAYER_FREEIF(argv2[i]); } @@ -8474,7 +4799,7 @@ ERROR: /* release */ for (i = 0; i < arg_count; i++) { - LOGD("free[%d] : %s\n", i, argv2[i]); + LOGD("free[%d] : %s", i, argv2[i]); MMPLAYER_FREEIF(argv2[i]); } @@ -8485,26 +4810,13 @@ ERROR: return FALSE; } -int -__mmplayer_destroy_streaming_ext(mm_player_t* player) -{ - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) { - _mmplayer_destroy_pd_downloader((MMHandleType)player); - MMPLAYER_FREEIF(player->pd_file_save_path); - } - - return MM_ERROR_NONE; -} - static void -__mmplayer_check_async_state_transition(mm_player_t* player) +__mmplayer_check_async_state_transition(mmplayer_t *player) { GstState element_state = GST_STATE_VOID_PENDING; GstState element_pending_state = GST_STATE_VOID_PENDING; GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; - GstElement * element = NULL; + GstElement *element = NULL; gboolean async = FALSE; /* check player handle */ @@ -8525,10 +4837,10 @@ __mmplayer_check_async_state_transition(mm_player_t* player) /* wait for state transition */ element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst; - ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND); + ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND); if (ret == GST_STATE_CHANGE_FAILURE) { - LOGE(" [%s] state : %s pending : %s \n", + LOGE(" [%s] state : %s pending : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(element_state), gst_element_state_get_name(element_pending_state)); @@ -8539,14 +4851,14 @@ __mmplayer_check_async_state_transition(mm_player_t* player) return; } - LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element)); + LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element)); return; } int _mmplayer_destroy(MMHandleType handle) { - mm_player_t* player = MM_PLAYER_CAST(handle); + mmplayer_t *player = MM_PLAYER_CAST(handle); MMPLAYER_FENTER(); @@ -8559,20 +4871,18 @@ _mmplayer_destroy(MMHandleType handle) /* check async state transition */ __mmplayer_check_async_state_transition(player); - __mmplayer_destroy_streaming_ext(player); + /* release gapless play thread */ + if (player->gapless_play_thread) { + MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player); + player->gapless_play_thread_exit = TRUE; + MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player); + MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player); - /* release next play thread */ - if (player->next_play_thread) { - MMPLAYER_NEXT_PLAY_THREAD_LOCK(player); - player->next_play_thread_exit = TRUE; - MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player); - MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player); - - LOGD("waitting for next play thread exit\n"); - g_thread_join(player->next_play_thread); - g_mutex_clear(&player->next_play_thread_mutex); - g_cond_clear(&player->next_play_thread_cond); - LOGD("next play thread released\n"); + LOGD("waitting 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); + LOGD("gapless play thread released"); } _mmplayer_release_video_capture(player); @@ -8580,11 +4890,11 @@ _mmplayer_destroy(MMHandleType handle) /* de-initialize resource manager */ if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy( player->resource_manager)) - LOGE("failed to deinitialize resource manager\n"); + LOGE("failed to deinitialize resource manager"); /* release pipeline */ if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) { - LOGE("failed to destory pipeline\n"); + LOGE("failed to destory pipeline"); return MM_ERROR_PLAYER_INTERNAL; } @@ -8625,38 +4935,9 @@ _mmplayer_destroy(MMHandleType handle) } int -__mmplayer_realize_streaming_ext(mm_player_t* player) -{ - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if (MMPLAYER_IS_HTTP_PD(player)) { - gboolean bret = FALSE; - - player->pd_downloader = _mmplayer_create_pd_downloader(); - if (!player->pd_downloader) { - LOGE("Unable to create PD Downloader..."); - ret = MM_ERROR_PLAYER_NO_FREE_SPACE; - } - - bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst); - - if (FALSE == bret) { - LOGE("Unable to create PD Downloader..."); - ret = MM_ERROR_PLAYER_NOT_INITIALIZED; - } - } - - MMPLAYER_FLEAVE(); - return ret; -} - -int _mmplayer_realize(MMHandleType hplayer) { - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; char *uri = NULL; void *param = NULL; MMHandleType attrs = 0; @@ -8665,24 +4946,24 @@ _mmplayer_realize(MMHandleType hplayer) MMPLAYER_FENTER(); /* check player handle */ - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED) + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); /* check current state */ MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE); attrs = MMPLAYER_GET_ATTRS(player); if (!attrs) { - LOGE("fail to get attributes.\n"); + LOGE("fail to get attributes."); return MM_ERROR_PLAYER_INTERNAL; } mm_attrs_get_string_by_name(attrs, "profile_uri", &uri); mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m); if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) { - ret = __mmfplayer_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\n"); + LOGE("failed to parse profile"); return ret; } } @@ -8695,7 +4976,7 @@ _mmplayer_realize(MMHandleType hplayer) } if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) { - LOGW("mms protocol is not supported format.\n"); + LOGW("mms protocol is not supported format."); return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT; } @@ -8706,23 +4987,49 @@ _mmplayer_realize(MMHandleType hplayer) player->smooth_streaming = FALSE; player->videodec_linked = 0; - player->videosink_linked = 0; player->audiodec_linked = 0; - player->audiosink_linked = 0; player->textsink_linked = 0; player->is_external_subtitle_present = FALSE; player->is_external_subtitle_added_now = FALSE; - /* set the subtitle ON default */ - player->is_subtitle_off = FALSE; + player->is_subtitle_off = FALSE; /* set the subtitle ON default */ + player->video360_metadata.is_spherical = -1; + player->is_openal_plugin_used = FALSE; + player->demux_pad_index = 0; + player->subtitle_language_list = NULL; + player->is_subtitle_force_drop = FALSE; + + __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); + + 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); + + if (prebuffer_ms > 0) { + prebuffer_ms = MAX(prebuffer_ms, 1000); + player->streamer->buffering_req.prebuffer_time = prebuffer_ms; + } + + if (rebuffer_ms > 0) { + player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED; + rebuffer_ms = MAX(rebuffer_ms, 1000); + player->streamer->buffering_req.rebuffer_time = rebuffer_ms; + } + + LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time, + player->streamer->buffering_req.rebuffer_time); + } /* realize pipeline */ - ret = __gst_realize(player); + ret = __mmplayer_gst_realize(player); if (ret != MM_ERROR_NONE) - LOGE("fail to realize the player.\n"); - else - ret = __mmplayer_realize_streaming_ext(player); + LOGE("fail to realize the player."); - player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT; MMPLAYER_BUS_MSG_THREAD_SIGNAL(player); MMPLAYER_FLEAVE(); @@ -8731,23 +5038,9 @@ _mmplayer_realize(MMHandleType hplayer) } int -__mmplayer_unrealize_streaming_ext(mm_player_t *player) -{ - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* destroy can called at anytime */ - if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) - _mmplayer_unrealize_pd_downloader((MMHandleType)player); - - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; -} - -int _mmplayer_unrealize(MMHandleType hplayer) { - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; int ret = MM_ERROR_NONE; MMPLAYER_FENTER(); @@ -8757,7 +5050,7 @@ _mmplayer_unrealize(MMHandleType hplayer) MMPLAYER_CMD_UNLOCK(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 */ @@ -8766,10 +5059,8 @@ _mmplayer_unrealize(MMHandleType hplayer) /* check async state transition */ __mmplayer_check_async_state_transition(player); - __mmplayer_unrealize_streaming_ext(player); - /* unrealize pipeline */ - ret = __gst_unrealize(player); + ret = __mmplayer_gst_unrealize(player); /* set asm stop if success */ if (MM_ERROR_NONE == ret) { @@ -8778,7 +5069,7 @@ _mmplayer_unrealize(MMHandleType hplayer) 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)\n", ret); + LOGE("failed to mark decoder resource for release, ret(0x%x)", ret); else player->video_decoder_resource = NULL; } @@ -8787,14 +5078,14 @@ _mmplayer_unrealize(MMHandleType hplayer) 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)\n", ret); + LOGE("failed to mark overlay resource for release, ret(0x%x)", ret); else player->video_overlay_resource = NULL; } ret = mm_resource_manager_commit(player->resource_manager); if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) - LOGE("failed to commit resource releases, ret(0x%x)\n", ret); + LOGE("failed to commit resource releases, ret(0x%x)", ret); } } else LOGE("failed and don't change asm state to stop"); @@ -8807,17 +5098,17 @@ _mmplayer_unrealize(MMHandleType hplayer) int _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) { - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return __gst_set_message_callback(player, callback, user_param); + return __mmplayer_gst_set_message_callback(player, callback, user_param); } int -_mmplayer_get_state(MMHandleType hplayer, int* state) +_mmplayer_get_state(MMHandleType hplayer, int *state) { - mm_player_t *player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT); @@ -8826,140 +5117,132 @@ _mmplayer_get_state(MMHandleType hplayer, int* state) return MM_ERROR_NONE; } - -int -_mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) +static int +__mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name) { - mm_player_t* player = (mm_player_t*) hplayer; - GstElement* vol_element = NULL; - int i = 0; + GstElement *vol_element = NULL; + 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\n", - 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)\n"); - 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\n"); - LOGD("but, current stored volume will be set when it's created.\n"); + 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) { + LOGD("offload pipeline"); + volume_elem_id = MMPLAYER_A_SINK; + } - if (vol_element) { - LOGD("volume is set [%f]\n", 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, MMPlayerVolumeType* volume) +_mmplayer_set_volume(MMHandleType hplayer, float volume) { - mm_player_t* player = (mm_player_t*) hplayer; - int i = 0; + 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(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) { - mm_player_t* player = (mm_player_t*) hplayer; - GstElement* vol_element = NULL; + mmplayer_t *player = (mmplayer_t *)hplayer; 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\n"); + *volume = player->sound.volume; - /* FIXIT : definitly, we need _BAD_PARAM error code */ - return MM_ERROR_INVALID_ARGUMENT; - } + LOGD("current vol = %f", *volume); - player->sound.mute = mute; + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; +} + +int +_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); - /* just hold mute value if pipeline is not ready */ - if (!player->pipeline || !player->pipeline->audiobin) { - LOGD("pipeline is not ready. holding mute value\n"); - return MM_ERROR_NONE; - } + LOGD("mute = %d", mute); - vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst; + player->sound.mute = mute; - /* NOTE : volume will only created when the bt is enabled */ - if (vol_element) { - LOGD("mute : %d\n", mute); - g_object_set(vol_element, "mute", mute, NULL); - } else - LOGD("volume elemnet is not created. using volume in audiosink\n"); + ret = __mmplayer_gst_set_volume_property(player, "mute"); MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; + return ret; } int -_mmplayer_get_mute(MMHandleType hplayer, int* pmute) +_mmplayer_get_mute(MMHandleType hplayer, bool *mute) { - mm_player_t* player = (mm_player_t*) hplayer; + 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); + MMPLAYER_RETURN_VAL_IF_FAIL(mute, 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\n"); - *pmute = player->sound.mute; - return MM_ERROR_NONE; - } + *mute = player->sound.mute; - *pmute = player->sound.mute; + LOGD("current mute = %d", *mute); MMPLAYER_FLEAVE(); @@ -8969,7 +5252,7 @@ _mmplayer_get_mute(MMHandleType hplayer, int* pmute) int _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param) { - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; MMPLAYER_FENTER(); @@ -8977,7 +5260,7 @@ _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_chan player->video_stream_changed_cb = callback; player->video_stream_changed_cb_user_param = user_param; - LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb); + LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb); MMPLAYER_FLEAVE(); @@ -8987,7 +5270,7 @@ _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_chan int _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param) { - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; MMPLAYER_FENTER(); @@ -8995,7 +5278,7 @@ _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_chan player->audio_stream_changed_cb = callback; player->audio_stream_changed_cb_user_param = user_param; - LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb); + LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb); MMPLAYER_FLEAVE(); @@ -9003,18 +5286,18 @@ _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_chan } int -_mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) +_mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param) { - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - player->audio_stream_render_cb_ex = callback; - player->audio_stream_cb_user_param = user_param; - player->audio_stream_sink_sync = sync; - LOGD("Audio Stream cb Handle value is %p : %p audio_stream_sink_sync : %d\n", player, player->audio_stream_render_cb_ex, player->audio_stream_sink_sync); + player->audio_decoded_cb = callback; + player->audio_decoded_cb_user_param = user_param; + player->audio_extract_opt = opt; + LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt); MMPLAYER_FLEAVE(); @@ -9022,9 +5305,9 @@ _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio } int -_mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) +_mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param) { - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; MMPLAYER_FENTER(); @@ -9033,102 +5316,39 @@ _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callba if (callback && !player->bufmgr) player->bufmgr = tbm_bufmgr_init(-1); - player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE; - player->video_stream_cb = callback; - player->video_stream_cb_user_param = user_param; - - LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + player->set_mode.video_export = (callback) ? true : false; + player->video_decoded_cb = callback; + player->video_decoded_cb_user_param = user_param; - player->audio_stream_cb = callback; - player->audio_stream_cb_user_param = user_param; - LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb); + LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export); MMPLAYER_FLEAVE(); return MM_ERROR_NONE; } -static int -__mmplayer_start_streaming_ext(mm_player_t *player) -{ - gint ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if (MMPLAYER_IS_HTTP_PD(player)) { - if (!player->pd_downloader) { - ret = __mmplayer_realize_streaming_ext(player); - - if (ret != MM_ERROR_NONE) { - LOGE("failed to realize streaming ext\n"); - return ret; - } - } - - if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) { - ret = _mmplayer_start_pd_downloader((MMHandleType)player); - if (!ret) { - LOGE("ERROR while starting PD...\n"); - return MM_ERROR_PLAYER_NOT_INITIALIZED; - } - ret = MM_ERROR_NONE; - } - } - - MMPLAYER_FLEAVE(); - return ret; -} - int _mmplayer_start(MMHandleType hplayer) { - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; gint ret = MM_ERROR_NONE; MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); /* check current state */ MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START); - /* NOTE : we should check and create pipeline again if not created as we destroy - * whole pipeline when stopping in streamming playback - */ - if (!player->pipeline) { - ret = __gst_realize(player); - if (MM_ERROR_NONE != ret) { - LOGE("failed to realize before starting. only in streamming\n"); - /* unlock */ - return ret; - } - } - - ret = __mmplayer_start_streaming_ext(player); - if (ret != MM_ERROR_NONE) { - LOGE("failed to start streaming ext 0x%X", ret); - return ret; - } - /* start pipeline */ - ret = __gst_start(player); + ret = __mmplayer_gst_start(player); if (ret != MM_ERROR_NONE) - LOGE("failed to start player.\n"); + LOGE("failed to start player."); + + if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) { + LOGD("force playing start even during buffering"); + player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT; + } MMPLAYER_FLEAVE(); @@ -9137,12 +5357,12 @@ _mmplayer_start(MMHandleType hplayer) /* NOTE: post "not supported codec message" to application * when one codec is not found during AUTOPLUGGING in MSL. - * So, it's separated with error of __mmplayer_gst_callback(). + * So, it's separated with error of __mmplayer_gst_bus_msg_callback(). * And, if any codec is not found, don't send message here. * Because GST_ERROR_MESSAGE is posted by other plugin internally. */ int -__mmplayer_handle_missed_plugin(mm_player_t* player) +__mmplayer_handle_missed_plugin(mmplayer_t *player) { MMMessageParamType msg_param; memset(&msg_param, 0, sizeof(MMMessageParamType)); @@ -9152,7 +5372,7 @@ __mmplayer_handle_missed_plugin(mm_player_t* player) MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n", + LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x", player->not_supported_codec, player->can_support_codec); if (player->not_found_demuxer) { @@ -9179,12 +5399,12 @@ __mmplayer_handle_missed_plugin(mm_player_t* player) memset(&msg_param, 0, sizeof(MMMessageParamType)); if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) { - LOGW("not found AUDIO codec, posting error code to application.\n"); + LOGW("not found AUDIO codec, posting error code to application."); msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime); } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) { - LOGW("not found VIDEO codec, posting error code to application.\n"); + LOGW("not found VIDEO codec, posting error code to application."); msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND; msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime); @@ -9197,7 +5417,7 @@ __mmplayer_handle_missed_plugin(mm_player_t* player) return MM_ERROR_NONE; } else { // no any supported codec case - LOGW("not found any codec, posting error code to application.\n"); + LOGW("not found any codec, posting error code to application."); if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) { msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; @@ -9218,34 +5438,35 @@ __mmplayer_handle_missed_plugin(mm_player_t* player) return MM_ERROR_NONE; } -static void __mmplayer_check_pipeline(mm_player_t* player) +static void +__mmplayer_check_pipeline(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; - if (player->gapless.reconfigure) { - LOGW("pipeline is under construction.\n"); + if (!player->gapless.reconfigure) + return; - MMPLAYER_PLAYBACK_LOCK(player); - MMPLAYER_PLAYBACK_UNLOCK(player); + LOGW("pipeline is under construction."); - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); + MMPLAYER_PLAYBACK_LOCK(player); + MMPLAYER_PLAYBACK_UNLOCK(player); - /* wait for state transition */ - ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND); + timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); - if (ret == GST_STATE_CHANGE_FAILURE) - LOGE("failed to change pipeline state within %d sec\n", 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); } /* NOTE : it should be able to call 'stop' anytime*/ int _mmplayer_stop(MMHandleType hplayer) { - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; int ret = MM_ERROR_NONE; MMPLAYER_FENTER(); @@ -9262,16 +5483,14 @@ _mmplayer_stop(MMHandleType hplayer) /* NOTE : application should not wait for EOS after calling STOP */ __mmplayer_cancel_eos_timer(player); - __mmplayer_unrealize_streaming_ext(player); - /* reset */ - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; /* stop pipeline */ - ret = __gst_stop(player); + ret = __mmplayer_gst_stop(player); if (ret != MM_ERROR_NONE) - LOGE("failed to stop player.\n"); + LOGE("failed to stop player."); MMPLAYER_FLEAVE(); @@ -9281,8 +5500,8 @@ _mmplayer_stop(MMHandleType hplayer) int _mmplayer_pause(MMHandleType hplayer) { - mm_player_t* player = (mm_player_t*)hplayer; - gint64 pos_msec = 0; + mmplayer_t *player = (mmplayer_t *)hplayer; + gint64 pos_nsec = 0; gboolean async = FALSE; gint ret = MM_ERROR_NONE; @@ -9319,10 +5538,10 @@ _mmplayer_pause(MMHandleType hplayer) *(returning zero when getting current position in paused state) of some * elements */ - if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec)) - LOGW("getting current position failed in paused\n"); + if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) + LOGW("getting current position failed in paused"); - player->last_position = pos_msec; + player->last_position = pos_nsec; /* For rtspsrc stack , npt-start value coming from server is used for finding the current position. But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing. @@ -9342,10 +5561,10 @@ _mmplayer_pause(MMHandleType hplayer) } /* pause pipeline */ - ret = __gst_pause(player, async); + ret = __mmplayer_gst_pause(player, async); if (ret != MM_ERROR_NONE) - LOGE("failed to pause player. ret : 0x%x\n", ret); + LOGE("failed to pause player. ret : 0x%x", 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")) @@ -9357,111 +5576,82 @@ _mmplayer_pause(MMHandleType hplayer) return ret; } +/* in case of streaming, pause could take long time.*/ int -_mmplayer_resume(MMHandleType hplayer) +_mmplayer_abort_pause(MMHandleType hplayer) { - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; int ret = MM_ERROR_NONE; - gboolean async = FALSE; MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* Changing back sync mode rtspsrc to async */ - if ((MMPLAYER_IS_RTSP_STREAMING(player))) { - LOGD("async resume for rtsp case"); - async = TRUE; - } - - /* check current state */ - MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME); - - ret = __gst_resume(player, async); + MMPLAYER_RETURN_VAL_IF_FAIL(player && + player->pipeline && + player->pipeline->mainbin, + MM_ERROR_PLAYER_NOT_INITIALIZED); - if (ret != MM_ERROR_NONE) - LOGE("failed to resume player.\n"); + LOGD("set the pipeline state to READY"); - MMPLAYER_FLEAVE(); + /* set state to READY */ + ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, + GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player)); + if (ret != MM_ERROR_NONE) { + LOGE("fail to change state to READY"); + return MM_ERROR_PLAYER_INTERNAL; + } + LOGD("succeeded in changing state to READY"); return ret; } -static int -__mmplayer_set_pcm_extraction(mm_player_t* player) +int +_mmplayer_resume(MMHandleType hplayer) { - gint64 start_nsec = 0; - gint64 end_nsec = 0; - gint64 dur_nsec = 0; - gint64 dur_msec = 0; - int required_start = 0; - int required_end = 0; - int ret = 0; + mmplayer_t *player = (mmplayer_t *)hplayer; + int ret = MM_ERROR_NONE; + gboolean async = FALSE; MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - - mm_attrs_multiple_get(player->attrs, - NULL, - "pcm_extraction_start_msec", &required_start, - "pcm_extraction_end_msec", &required_end, - NULL); - - LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end); - - if (required_start == 0 && required_end == 0) { - LOGD("extracting entire stream"); - return MM_ERROR_NONE; - } else if (required_start < 0 || required_start > required_end || required_end < 0) { - LOGD("invalid range for pcm extraction"); - return MM_ERROR_INVALID_ARGUMENT; - } + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - /* get duration */ - ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec); - if (!ret) { - LOGE("failed to get duration"); - return MM_ERROR_PLAYER_INTERNAL; - } - dur_msec = GST_TIME_AS_MSECONDS(dur_nsec); + if ((MMPLAYER_IS_RTSP_STREAMING(player))) { + if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */ + player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */ + return ret; + } - if (dur_msec < required_end) { - // FIXME - LOGD("invalid end pos for pcm extraction"); - return MM_ERROR_INVALID_ARGUMENT; + /* Changing back sync mode rtspsrc to async */ + LOGD("async resume for rtsp case"); + async = TRUE; } - start_nsec = required_start * G_GINT64_CONSTANT(1000000); - end_nsec = required_end * G_GINT64_CONSTANT(1000000); + /* check current state */ + MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME); - if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, - 1.0, - GST_FORMAT_TIME, - (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), - GST_SEEK_TYPE_SET, start_nsec, - GST_SEEK_TYPE_SET, end_nsec))) { - LOGE("failed to seek for pcm extraction\n"); + ret = __mmplayer_gst_resume(player, async); + if (ret != MM_ERROR_NONE) + LOGE("failed to resume player."); - return MM_ERROR_PLAYER_SEEK; + if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) { + LOGD("force resume even during buffering"); + player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT; } - LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; + return ret; } int _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming) { - mm_player_t* player = (mm_player_t*)hplayer; - gint64 pos_msec = 0; + 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; - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; + mmplayer_state_e current_state = MM_PLAYER_STATE_NONE; MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); @@ -9470,7 +5660,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); @@ -9479,41 +5669,41 @@ _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming) /* If the position is reached at start potion during fast backward, EOS is posted. * So, This EOS have to be classified with it which is posted at reaching the end of stream. - * */ + */ player->playback_rate = rate; current_state = MMPLAYER_CURRENT_STATE(player); if (current_state != MM_PLAYER_STATE_PAUSED) - ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec); + ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec); - LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state); + LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state); if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) { - LOGW("returning last point : %lld\n", player->last_position); - pos_msec = player->last_position; + LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position); + pos_nsec = player->last_position; } if (rate >= 0) { - start = pos_msec; + start = pos_nsec; stop = GST_CLOCK_TIME_NONE; } else { start = GST_CLOCK_TIME_NONE; - stop = pos_msec; + stop = pos_nsec; } - if (!__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), GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop)) { - LOGE("failed to set speed playback\n"); + LOGE("failed to set speed playback"); return MM_ERROR_PLAYER_SEEK; } - LOGD("succeeded to set speed playback as %0.1f\n", rate); + LOGD("succeeded to set speed playback as %0.1f", rate); MMPLAYER_FLEAVE(); @@ -9521,9 +5711,9 @@ _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming) } int -_mmplayer_set_position(MMHandleType hplayer, int format, int position) +_mmplayer_set_position(MMHandleType hplayer, gint64 position) { - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; int ret = MM_ERROR_NONE; MMPLAYER_FENTER(); @@ -9533,7 +5723,7 @@ _mmplayer_set_position(MMHandleType hplayer, int format, int position) /* check pipline building state */ __mmplayer_check_pipeline(player); - ret = __gst_set_position(player, format, (unsigned long)position, FALSE); + ret = __mmplayer_gst_set_position(player, position, FALSE); MMPLAYER_FLEAVE(); @@ -9541,58 +5731,58 @@ _mmplayer_set_position(MMHandleType hplayer, int format, int position) } int -_mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) +_mmplayer_get_position(MMHandleType hplayer, gint64 *position) { - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; int ret = MM_ERROR_NONE; MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - ret = __gst_get_position(player, format, position); + ret = __mmplayer_gst_get_position(player, position); return ret; } int -_mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) +_mmplayer_get_duration(MMHandleType hplayer, gint64 *duration) { - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; int ret = MM_ERROR_NONE; MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT); - ret = __gst_get_buffer_position(player, format, start_pos, stop_pos); + if (g_strrstr(player->type, "video/mpegts")) + __mmplayer_update_duration_value(player); + *duration = player->duration; return ret; } int -_mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) +_mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos) { - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; int ret = MM_ERROR_NONE; - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - ret = __gst_adjust_subtitle_position(player, format, position); - - MMPLAYER_FLEAVE(); + ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos); return ret; } + int -_mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) +_mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position) { - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; int ret = MM_ERROR_NONE; MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - ret = __gst_adjust_video_position(player, offset); + ret = __mmplayer_gst_adjust_subtitle_position(player, position); MMPLAYER_FLEAVE(); @@ -9600,7 +5790,7 @@ _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) } static gboolean -__mmplayer_is_midi_type(gchar* str_caps) +__mmplayer_is_midi_type(gchar *str_caps) { if ((g_strrstr(str_caps, "audio/midi")) || (g_strrstr(str_caps, "application/x-gst_ff-mmf")) || @@ -9609,7 +5799,7 @@ __mmplayer_is_midi_type(gchar* str_caps) (g_strrstr(str_caps, "audio/mobile-xmf")) || (g_strrstr(str_caps, "audio/xmf")) || (g_strrstr(str_caps, "audio/mxmf"))) { - LOGD("midi\n"); + LOGD("midi"); return TRUE; } @@ -9620,15 +5810,15 @@ static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps) { if (g_strrstr(str_caps, "application/x-id3") || - (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1"))) + (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1"))) return TRUE; return FALSE; } static void -__mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps) +__mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps) { - GstStructure* caps_structure = NULL; + GstStructure *caps_structure = NULL; gint samplerate = 0; gint channels = 0; @@ -9644,40 +5834,58 @@ __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps) gst_structure_get_int(caps_structure, "channels", &channels); mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels); - LOGD("audio samplerate : %d channels : %d\n", samplerate, channels); + LOGD("audio samplerate : %d channels : %d", samplerate, channels); } static void -__mmplayer_update_content_type_info(mm_player_t* player) +__mmplayer_update_content_type_info(mmplayer_t *player) { MMPLAYER_FENTER(); MMPLAYER_RETURN_IF_FAIL(player && player->type); if (__mmplayer_is_midi_type(player->type)) { player->bypass_audio_effect = TRUE; - } else if (g_strrstr(player->type, "application/x-hls")) { + return; + } + + if (!player->streamer) { + LOGD("no need to check streaming type"); + return; + } + + if (g_strrstr(player->type, "application/x-hls")) { /* If it can't know exact type when it parses uri because of redirection case, * it will be fixed by typefinder or when doing autoplugging. */ player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS; - if (player->streamer) { - player->streamer->is_adaptive_streaming = TRUE; - player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED; - player->streamer->buffering_req.rebuffer_time = 5 * 1000; - } + player->streamer->is_adaptive_streaming = TRUE; } else if (g_strrstr(player->type, "application/dash+xml")) { player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH; + player->streamer->is_adaptive_streaming = TRUE; } + /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */ + if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) { + player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED; + + if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */ + if (player->streamer->is_adaptive_streaming) + player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME; + else + player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME; + } + } + + LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time); MMPLAYER_FLEAVE(); } -static void +void __mmplayer_typefind_have_type(GstElement *tf, guint probability, -GstCaps *caps, gpointer data) + GstCaps *caps, gpointer data) { - mm_player_t* player = (mm_player_t*)data; - GstPad* pad = NULL; + mmplayer_t *player = (mmplayer_t *)data; + GstPad *pad = NULL; MMPLAYER_FENTER(); @@ -9686,14 +5894,13 @@ GstCaps *caps, gpointer data) /* store type string */ MMPLAYER_FREEIF(player->type); player->type = gst_caps_to_string(caps); - if (player->type) { - LOGD("[handle: %p] media type %s found, probability %d%% / %d\n", + if (player->type) + LOGD("[handle: %p] media type %s found, probability %d%% / %d", player, player->type, probability, gst_caps_get_size(caps)); - } if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (g_strrstr(player->type, "audio/x-raw-int"))) { - LOGE("not support media format\n"); + LOGE("not support media format"); if (player->msg_posted == FALSE) { MMMessageParamType msg_param; @@ -9712,23 +5919,21 @@ GstCaps *caps, gpointer data) pad = gst_element_get_static_pad(tf, "src"); if (!pad) { - LOGE("fail to get typefind src pad.\n"); + LOGE("fail to get typefind src pad."); return; } - if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) { + if (!__mmplayer_gst_create_decoder(player, pad, caps)) { gboolean async = FALSE; - LOGE("failed to autoplug %s\n", player->type); + LOGE("failed to autoplug %s", player->type); mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async); if (async && player->msg_posted == FALSE) __mmplayer_handle_missed_plugin(player); - goto DONE; } -DONE: gst_object_unref(GST_OBJECT(pad)); MMPLAYER_FLEAVE(); @@ -9736,8 +5941,8 @@ DONE: return; } -static GstElement * -__mmplayer_create_decodebin(mm_player_t* player) +GstElement * +__mmplayer_gst_make_decodebin(mmplayer_t *player) { GstElement *decodebin = NULL; @@ -9747,153 +5952,155 @@ __mmplayer_create_decodebin(mm_player_t* player) decodebin = gst_element_factory_make("decodebin", NULL); if (!decodebin) { - LOGE("fail to create decodebin\n"); + LOGE("fail to create decodebin"); goto ERROR; } /* raw pad handling signal */ - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK(__mmplayer_gst_decode_pad_added), player); + __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", + G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player); /* no-more-pad pad handling signal */ - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", - G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player); + __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", + G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player); - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", - G_CALLBACK(__mmplayer_gst_decode_pad_removed), player); + __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", + G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player); /* This signal is emitted when a pad for which there is no further possible decoding is added to the decodebin.*/ - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", - G_CALLBACK(__mmplayer_gst_decode_unknown_type), player); + __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", + G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player); /* This signal is emitted whenever decodebin finds a new stream. It is emitted before looking for any elements that can handle that stream.*/ - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", - G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player); + __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", + G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player); /* This signal is emitted whenever decodebin finds a new stream. It is emitted before looking for any elements that can handle that stream.*/ - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", - G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player); + __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", + G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player); /* This signal is emitted once decodebin has finished decoding all the data.*/ - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained", - G_CALLBACK(__mmplayer_gst_decode_drained), player); + __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained", + G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player); /* This signal is emitted when a element is added to the bin.*/ - MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added", - G_CALLBACK(__mmplayer_gst_element_added), player); + __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added", + G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player); ERROR: return decodebin; } -static gboolean -__mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps) +static GstElement * +__mmplayer_gst_make_queue2(mmplayer_t *player) { - MMPlayerGstElement* mainbin = NULL; - GstElement* decodebin = NULL; - GstElement* queue2 = NULL; - GstPad* sinkpad = NULL; - GstPad* qsrcpad = NULL; + GstElement *queue2 = NULL; gint64 dur_bytes = 0L; - - guint max_buffer_size_bytes = 0; - gint init_buffering_time = player->streamer->buffering_req.prebuffer_time; + mmplayer_gst_element_t *mainbin = NULL; + muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE; MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL); mainbin = player->pipeline->mainbin; - if ((!MMPLAYER_IS_HTTP_PD(player)) && - (MMPLAYER_IS_HTTP_STREAMING(player))) { - LOGD("creating http streaming buffering queue(queue2)\n"); + queue2 = gst_element_factory_make("queue2", "queue2"); + if (!queue2) { + LOGE("failed to create buffering queue element"); + return NULL; + } - if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) { - LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n"); - } else { - queue2 = gst_element_factory_make("queue2", "queue2"); - if (!queue2) { - LOGE("failed to create buffering queue element\n"); - goto ERROR; - } + if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) + LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst)); - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) { - LOGE("failed to add buffering queue\n"); - goto ERROR; - } + LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes); - sinkpad = gst_element_get_static_pad(queue2, "sink"); - qsrcpad = gst_element_get_static_pad(queue2, "src"); + /* NOTE : in case of ts streaming, player could not get the correct duration info * + * skip the pull mode(file or ring buffering) setting. */ + if (dur_bytes > 0) { + if (!g_strrstr(player->type, "video/mpegts")) { + type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER; + player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size; + } + } else { + dur_bytes = 0; + } - if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { - LOGE("failed to link buffering queue\n"); - goto ERROR; - } + __mm_player_streaming_set_queue2(player->streamer, + queue2, + FALSE, + type, + (guint64)dur_bytes); /* no meaning at the moment */ - if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) - LOGE("fail to get duration.\n"); + return queue2; +} - LOGD("dur_bytes = %lld\n", dur_bytes); +gboolean +__mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps) +{ + mmplayer_gst_element_t *mainbin = NULL; + GstElement *decodebin = NULL; + GstElement *queue2 = NULL; + GstPad *sinkpad = NULL; + GstPad *qsrcpad = NULL; - muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE; + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE); - if (dur_bytes > 0) { - if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) { - type = MUXED_BUFFER_TYPE_FILE; - } else { - type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER; - player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size; - } - } else { - dur_bytes = 0; - } + mainbin = player->pipeline->mainbin; - /* NOTE : we cannot get any duration info from ts container in case of streaming */ - // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) - if (!g_strrstr(player->type, "video/mpegts")) { - max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024); - LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes); - - // FIXME : pass ini setting directly. is this ok? - __mm_player_streaming_set_queue2(player->streamer, - queue2, - FALSE, - max_buffer_size_bytes, - player->ini.http_buffering_time, - 1.0, // no meaning - player->ini.http_buffering_limit, // no meaning - type, - player->http_file_buffering_path, - (guint64)dur_bytes); - } + if (MMPLAYER_IS_HTTP_STREAMING(player)) { - if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) { - LOGE("failed to sync queue2 state with parent\n"); - goto ERROR; - } + if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) { + LOGW("need to check: muxed buffer is not null"); + } + + queue2 = __mmplayer_gst_make_queue2(player); + if (!queue2) { + LOGE("failed to make queue2"); + goto ERROR; + } + + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) { + LOGE("failed to add buffering queue"); + goto ERROR; + } - srcpad = qsrcpad; + sinkpad = gst_element_get_static_pad(queue2, "sink"); + qsrcpad = gst_element_get_static_pad(queue2, "src"); - gst_object_unref(GST_OBJECT(sinkpad)); + if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) { + LOGE("failed to link [%s:%s]-[%s:%s]", + GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); + goto ERROR; + } - mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER; - mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2; + if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) { + LOGE("failed to sync queue2 state with parent"); + goto ERROR; } + + mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER; + mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2; + + srcpad = qsrcpad; + + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; } /* create decodebin */ - decodebin = __mmplayer_create_decodebin(player); - + decodebin = __mmplayer_gst_make_decodebin(player); if (!decodebin) { - LOGE("can not create autoplug element\n"); + LOGE("failed to make decodebin"); goto ERROR; } if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) { - LOGE("failed to add decodebin\n"); + LOGE("failed to add decodebin"); goto ERROR; } @@ -9905,39 +6112,42 @@ __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstC sinkpad = gst_element_get_static_pad(decodebin, "sink"); if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { - LOGE("failed to link decodebin\n"); + LOGE("failed to link [%s:%s]-[%s:%s]", + GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); goto ERROR; } gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; + gst_object_unref(GST_OBJECT(qsrcpad)); + qsrcpad = NULL; mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG; mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin; /* set decodebin property about buffer in streaming playback. * - * in case of HLS/DASH, it does not need to have big buffer * + * in case of HLS/DASH, it does not need to have big buffer * * because it is kind of adaptive streaming. */ - if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) { - guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES; - guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME; - init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time); + if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) { + gint init_buffering_time = DEFAULT_PREBUFFERING_TIME; + gint high_percent = 0; - if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player) - || MMPLAYER_IS_DASH_STREAMING(player)) { - max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES; - max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME; - } + if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME) + init_buffering_time = player->streamer->buffering_req.prebuffer_time; + + high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME); + + LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent); g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE, - "high-percent", (gint)player->ini.http_buffering_limit, - "low-percent", 1, // 1% - "max-size-bytes", max_size_bytes, - "max-size-time", (guint64)(max_size_time * GST_SECOND), + "high-percent", high_percent, + "max-size-bytes", MAX_BUFFER_SIZE_BYTES, + "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND), "max-size-buffers", 0, NULL); // disable or automatic } - if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) { - LOGE("failed to sync decodebin state with parent\n"); + if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) { + LOGE("failed to sync decodebin state with parent"); goto ERROR; } @@ -9950,6 +6160,9 @@ ERROR: if (sinkpad) gst_object_unref(GST_OBJECT(sinkpad)); + if (qsrcpad) + gst_object_unref(GST_OBJECT(qsrcpad)); + if (queue2) { /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state. * You need to explicitly set elements to the NULL state before @@ -9985,14 +6198,14 @@ ERROR: } static int -__mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime) +__mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime) { MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT); - LOGD("class : %s, mime : %s \n", factory_class, mime); + LOGD("class : %s, mime : %s", factory_class, mime); /* add missing plugin */ /* NOTE : msl should check missing plugin for image mime type. @@ -10001,7 +6214,7 @@ __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_c */ if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) { if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) { - LOGD("not found demuxer\n"); + LOGD("not found demuxer"); player->not_found_demuxer = TRUE; player->unlinked_demuxer_mime = g_strdup_printf("%s", mime); @@ -10011,22 +6224,22 @@ __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_c if (!g_strrstr(factory_class, "Demuxer")) { if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) { - LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n", + LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d", player->can_support_codec, player->videodec_linked, player->audiodec_linked); /* check that clip have multi tracks or not */ if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) { - LOGD("video plugin is already linked\n"); + LOGD("video plugin is already linked"); } else { - LOGW("add VIDEO to missing plugin\n"); + LOGW("add VIDEO to missing plugin"); player->not_supported_codec |= MISSING_PLUGIN_VIDEO; player->unlinked_video_mime = g_strdup_printf("%s", mime); } } else if (g_str_has_prefix(mime, "audio")) { if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) { - LOGD("audio plugin is already linked\n"); + LOGD("audio plugin is already linked"); } else { - LOGW("add AUDIO to missing plugin\n"); + LOGW("add AUDIO to missing plugin"); player->not_supported_codec |= MISSING_PLUGIN_AUDIO; player->unlinked_audio_mime = g_strdup_printf("%s", mime); } @@ -10039,211 +6252,197 @@ DONE: return MM_ERROR_NONE; } - static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data) { - mm_player_t* player = (mm_player_t*)data; + mmplayer_t *player = (mmplayer_t *)data; MMPLAYER_FENTER(); - MMPLAYER_RETURN_IF_FAIL(player); + MMPLAYER_RETURN_IF_FAIL(player); + + /* remove fakesink. */ + if (!__mmplayer_gst_remove_fakesink(player, + &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) { + /* NOTE : __mmplayer_pipeline_complete() can be called several time. because + * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various + * source element are not same. To overcome this situation, this function will called + * several places and several times. Therefore, this is not an error case. + */ + return; + } + + LOGD("[handle: %p] pipeline has completely constructed", player); + + if ((player->ini.async_start) && + (player->msg_posted == FALSE) && + (player->cmd >= MMPLAYER_COMMAND_START)) + __mmplayer_handle_missed_plugin(player); + + MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete"); +} + +static int +__mmplayer_check_profile(void) +{ + char *profileName; + static int profile_tv = -1; + + if (__builtin_expect(profile_tv != -1, 1)) + return profile_tv; + + system_info_get_platform_string("http://tizen.org/feature/profile", &profileName); + switch (*profileName) { + case 't': + case 'T': + profile_tv = 1; + break; + default: + profile_tv = 0; + break; + } + free(profileName); + + return profile_tv; +} + +static gboolean +__mmplayer_get_next_uri(mmplayer_t *player) +{ + mmplayer_parse_profile_t profile; + gint uri_idx = 0; + guint num_of_list = 0; + char *uri = NULL; + + num_of_list = g_list_length(player->uri_info.uri_list); + uri_idx = player->uri_info.uri_idx; + + LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx); + for (uri_idx++; uri_idx < num_of_list; uri_idx++) { + uri = g_list_nth_data(player->uri_info.uri_list, uri_idx); + if (!uri) { + LOGW("next uri does not exist"); + continue; + } + + if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) { + LOGE("failed to parse profile"); + continue; + } + + if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) && + (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) { + LOGW("uri type is not supported(%d)", profile.uri_type); + continue; + } + + LOGD("success to find next uri %d", uri_idx); + break; + } - /* remove fakesink. */ - if (!__mmplayer_gst_remove_fakesink(player, - &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) { - /* NOTE : __mmplayer_pipeline_complete() can be called several time. because - * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various - * source element are not same. To overcome this situation, this function will called - * several places and several times. Therefore, this is not an error case. - */ - return; + if (uri_idx == num_of_list) { + LOGE("failed to find next uri"); + return FALSE; } - LOGD("[handle: %p] pipeline has completely constructed", player); + player->uri_info.uri_idx = uri_idx; + mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri); - if ((player->ini.async_start) && - (player->msg_posted == FALSE) && - (player->cmd >= MMPLAYER_COMMAND_START)) - __mmplayer_handle_missed_plugin(player); + if (mm_attrs_commit_all(player->attrs)) { + LOGE("failed to commit"); + return FALSE; + } - MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete"); + SECURE_LOGD("next playback uri: %s", uri); + return TRUE; } static gboolean -__mmplayer_verify_next_play_path(mm_player_t *player) +__mmplayer_verify_gapless_play_path(mmplayer_t *player) { +#define REPEAT_COUNT_INFINITELY -1 +#define REPEAT_COUNT_MIN 2 + MMHandleType attrs = 0; - MMPlayerParseProfile profile; - gint uri_idx = 0, check_cnt = 0; - char *uri = NULL; - gint mode = MM_PLAYER_PD_MODE_NONE; gint video = 0; gint count = 0; gint gapless = 0; guint num_of_list = 0; - static int profile_tv = -1; + int profile_tv = -1; MMPLAYER_FENTER(); - LOGD("checking for gapless play"); + LOGD("checking for gapless play option"); if (player->pipeline->textbin) { - LOGE("subtitle path is enabled. gapless play is not supported.\n"); + LOGE("subtitle path is enabled. gapless play is not supported."); goto ERROR; } attrs = MMPLAYER_GET_ATTRS(player); if (!attrs) { - LOGE("fail to get attributes.\n"); + LOGE("fail to get attributes."); goto ERROR; } mm_attrs_get_int_by_name(attrs, "content_video_found", &video); - if (__builtin_expect(profile_tv == -1, 0)) { - char *profileName; - system_info_get_platform_string("http://tizen.org/feature/profile", &profileName); - switch (*profileName) { - case 't': - case 'T': - profile_tv = 1; - break; - default: - profile_tv = 0; - } - free(profileName); - } /* gapless playback is not supported in case of video at TV profile. */ + profile_tv = __mmplayer_check_profile(); if (profile_tv && video) { LOGW("not support video gapless playback"); goto ERROR; } - if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) { - if (mode == TRUE) { - LOGW("pd mode\n"); - goto ERROR; - } - } - if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) - LOGE("can not get play count\n"); + LOGE("failed to get play count"); if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE) - LOGE("can not get gapless mode\n"); + LOGE("failed to get gapless mode"); - if (video && !gapless) { - LOGW("not enabled video gapless playback"); - goto ERROR; - } - - if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */ - gapless = 1; - - if (!gapless) { - LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */ + /* check repeat count in case of audio */ + if (!gapless && + (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) { + LOGW("gapless is disabled"); goto ERROR; } num_of_list = g_list_length(player->uri_info.uri_list); - LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list); + LOGD("repeat count = %d, num_of_list = %d", count, num_of_list); if (num_of_list == 0) { - if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) { - LOGE("can not get profile_uri\n"); - goto ERROR; - } - - if (!uri) { - LOGE("uri list is empty.\n"); + /* 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) { + LOGD("there is no next uri and no repeat"); goto ERROR; } - - player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri)); - LOGD("add original path : %s ", uri); - - num_of_list = 1; - uri = NULL; - } - - uri_idx = player->uri_info.uri_idx; - - while (TRUE) { - check_cnt++; - - if (check_cnt > num_of_list) { - LOGE("there is no valid uri."); + LOGD("looping cnt %d", count); + } else { + /* gapless playback path */ + if (!__mmplayer_get_next_uri(player)) { + LOGE("failed to get next uri"); goto ERROR; } - - LOGD("uri idx : %d / %d\n", uri_idx, num_of_list); - - if (uri_idx < num_of_list-1) { - uri_idx++; - } else { - if ((count <= 1) && (count != -1)) { - LOGD("no repeat."); - goto ERROR; - } else if (count > 1) { - /* 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 (mmf_attrs_commit(attrs)) - LOGE("failed to commit attribute\n"); - } - - /* count < 0 : repeat continually */ - uri_idx = 0; - } - - uri = g_list_nth_data(player->uri_info.uri_list, uri_idx); - LOGD("uri idx : %d, uri = %s\n", uri_idx, uri); - - if (uri == NULL) { - LOGW("next uri does not exist\n"); - continue; - } - - if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) { - LOGE("failed to parse profile\n"); - continue; - } - - if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) && - (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) { - LOGW("uri type is not supported(%d).", profile.uri_type); - continue; - } - - break; - } - - player->uri_info.uri_idx = uri_idx; - mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri); - - if (mmf_attrs_commit(player->attrs)) { - LOGE("failed to commit.\n"); - goto ERROR; } - - LOGD("next uri %s(%d)\n", uri, uri_idx); - return TRUE; ERROR: - - LOGE("unable to play next path. EOS will be posted soon.\n"); + LOGE("unable to play gapless path. EOS will be posted soon"); return FALSE; } static void -__mmplayer_initialize_next_play(mm_player_t *player) +__mmplayer_initialize_gapless_play(mmplayer_t *player) { int i; @@ -10252,22 +6451,18 @@ __mmplayer_initialize_next_play(mm_player_t *player) player->smooth_streaming = FALSE; player->videodec_linked = 0; player->audiodec_linked = 0; - player->videosink_linked = 0; - player->audiosink_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.format = MM_PLAYER_POS_FORMAT_TIME; + 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->doing_seek = FALSE; - player->max_audio_channels = 0; + player->seek_state = MMPLAYER_SEEK_NONE; player->is_subtitle_force_drop = FALSE; player->play_subtitle = FALSE; player->adjust_subtitle_pos = 0; @@ -10275,7 +6470,7 @@ __mmplayer_initialize_next_play(mm_player_t *player) player->total_bitrate = 0; player->total_maximum_bitrate = 0; - _mmplayer_track_initialize(player); + __mmplayer_track_initialize(player); __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX); for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) { @@ -10290,17 +6485,6 @@ __mmplayer_initialize_next_play(mm_player_t *player) mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0); - /* clean found parsers */ - if (player->parsers) { - GList *parsers = player->parsers; - for (; parsers; parsers = g_list_next(parsers)) { - gchar *name = parsers->data; - MMPLAYER_FREEIF(name); - } - g_list_free(player->parsers); - player->parsers = NULL; - } - /* clean found audio decoders */ if (player->audio_decoders) { GList *a_dec = player->audio_decoders; @@ -10316,21 +6500,19 @@ __mmplayer_initialize_next_play(mm_player_t *player) } static void -__mmplayer_activate_next_source(mm_player_t *player, GstState target) +__mmplayer_activate_next_source(mmplayer_t *player, GstState target) { - MMPlayerGstElement *mainbin = NULL; + mmplayer_gst_element_t *mainbin = NULL; MMMessageParamType msg_param = {0,}; GstElement *element = NULL; MMHandleType attrs = 0; char *uri = NULL; - enum MainElementID elemId = MMPLAYER_M_NUM; + main_element_id_e elem_idx = MMPLAYER_M_NUM; MMPLAYER_FENTER(); - if ((player == NULL) || - (player->pipeline == NULL) || - (player->pipeline->mainbin == NULL)) { - LOGE("player is null.\n"); + if (!player || !player->pipeline || !player->pipeline->mainbin) { + LOGE("player is not initialized"); goto ERROR; } @@ -10339,102 +6521,36 @@ __mmplayer_activate_next_source(mm_player_t *player, GstState target) attrs = MMPLAYER_GET_ATTRS(player); if (!attrs) { - LOGE("fail to get attributes.\n"); + LOGE("fail to get attributes"); goto ERROR; } /* Initialize Player values */ - __mmplayer_initialize_next_play(player); + __mmplayer_initialize_gapless_play(player); mm_attrs_get_string_by_name(attrs, "profile_uri", &uri); - if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) { - LOGE("failed to parse profile\n"); + 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("it's dash or hls. not support."); + LOGE("dash or hls is not supportable"); msg_param.code = MM_ERROR_PLAYER_INVALID_URI; goto ERROR; } - /* setup source */ - switch (player->profile.uri_type) { - /* file source */ - case MM_PLAYER_URI_TYPE_FILE: - { - LOGD("using filesrc for 'file://' handler.\n"); - if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) { - LOGE("failed to get storage info"); - break; - } - - element = gst_element_factory_make("filesrc", "source"); - - if (!element) { - LOGE("failed to create filesrc\n"); - break; - } - - g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */ - break; - } - case MM_PLAYER_URI_TYPE_URL_HTTP: - { - gchar *user_agent, *cookies, **cookie_list; - gint http_timeout = DEFAULT_HTTP_TIMEOUT; - user_agent = cookies = NULL; - cookie_list = NULL; - - element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source"); - if (!element) { - LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element); - break; - } - LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element); - - /* get attribute */ - mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies); - mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent); - - if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) { - LOGD("get timeout from ini\n"); - http_timeout = player->ini.http_timeout; - } - - /* get attribute */ - SECURE_LOGD("location : %s\n", player->profile.uri); - SECURE_LOGD("cookies : %s\n", cookies); - SECURE_LOGD("user_agent : %s\n", user_agent); - LOGD("timeout : %d\n", http_timeout); - - /* setting property to streaming source */ - g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); - g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL); - g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL); - - /* parsing cookies */ - if ((cookie_list = util_get_cookie_list((const char*)cookies))) - g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL); - if (user_agent) - g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL); - break; - } - default: - LOGE("not support uri type %d\n", player->profile.uri_type); - break; - } - + element = __mmplayer_gst_create_source(player); if (!element) { - LOGE("no source element was created.\n"); + LOGE("no source element was created"); goto ERROR; } if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) { - LOGE("failed to add source element to pipeline\n"); + LOGE("failed to add source element to pipeline"); gst_object_unref(GST_OBJECT(element)); element = NULL; goto ERROR; @@ -10449,52 +6565,52 @@ __mmplayer_activate_next_source(mm_player_t *player, GstState target) if (MMPLAYER_IS_HTTP_STREAMING(player)) { if (player->streamer == NULL) { player->streamer = __mm_player_streaming_create(); - __mm_player_streaming_initialize(player->streamer); + __mm_player_streaming_initialize(player->streamer, TRUE); } - elemId = MMPLAYER_M_TYPEFIND; + elem_idx = MMPLAYER_M_TYPEFIND; element = gst_element_factory_make("typefind", "typefinder"); - MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", - G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player); + __mmplayer_add_signal_connection(player, G_OBJECT(element), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player); } else { - elemId = MMPLAYER_M_AUTOPLUG; - element = __mmplayer_create_decodebin(player); + elem_idx = MMPLAYER_M_AUTOPLUG; + element = __mmplayer_gst_make_decodebin(player); } /* check autoplug element is OK */ if (!element) { - LOGE("can not create element(%d)\n", elemId); + 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\n"); + LOGE("failed to add sinkbin to pipeline"); gst_object_unref(GST_OBJECT(element)); element = NULL; goto ERROR; } - mainbin[elemId].id = elemId; - mainbin[elemId].gst = element; + mainbin[elem_idx].id = elem_idx; + mainbin[elem_idx].gst = element; - if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) { - LOGE("Failed to link src - autoplug(or typefind)\n"); + if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) { + LOGE("Failed to link src - autoplug(or typefind)"); goto ERROR; } if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) { - LOGE("Failed to change state of src element\n"); + LOGE("Failed to change state of src element"); goto ERROR; } if (!MMPLAYER_IS_HTTP_STREAMING(player)) { if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) { - LOGE("Failed to change state of decodebin\n"); + LOGE("Failed to change state of decodebin"); goto ERROR; } } else { if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { - LOGE("Failed to change state of src element\n"); + LOGE("Failed to change state of src element"); goto ERROR; } } @@ -10517,12 +6633,12 @@ ERROR: } static gboolean -__mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type) +__mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type) { - mm_player_selector_t *selector = &player->selector[type]; - MMPlayerGstElement *sinkbin = NULL; - enum MainElementID selectorId = MMPLAYER_M_NUM; - enum MainElementID sinkId = MMPLAYER_M_NUM; + mmplayer_selector_t *selector = &player->selector[type]; + mmplayer_gst_element_t *sinkbin = NULL; + main_element_id_e selectorId = MMPLAYER_M_NUM; + main_element_id_e sinkId = MMPLAYER_M_NUM; GstPad *srcpad = NULL; GstPad *sinkpad = NULL; gboolean send_notice = FALSE; @@ -10575,7 +6691,7 @@ __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type) /* 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("application/flush-buffer"); + 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); } @@ -10607,7 +6723,7 @@ __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type) } static void -__mmplayer_deactivate_old_path(mm_player_t *player) +__mmplayer_deactivate_old_path(mmplayer_t *player) { MMPLAYER_FENTER(); MMPLAYER_RETURN_IF_FAIL(player); @@ -10619,17 +6735,17 @@ __mmplayer_deactivate_old_path(mm_player_t *player) 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_deinitialize(player->streamer); + __mm_player_streaming_initialize(player->streamer, FALSE); __mm_player_streaming_destroy(player->streamer); player->streamer = NULL; } MMPLAYER_PLAYBACK_LOCK(player); - MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player); + MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player); MMPLAYER_FLEAVE(); return; @@ -10641,7 +6757,7 @@ ERROR: /*post error*/ msg.code = MM_ERROR_PLAYER_INTERNAL; - LOGE("next_uri_play> deactivate error"); + LOGE("gapless_uri_play> deactivate error"); MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg); player->msg_posted = TRUE; @@ -10649,46 +6765,32 @@ ERROR: return; } -int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path) -{ - int result = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if (file_path) { - player->http_file_buffering_path = (gchar*)file_path; - LOGD("temp file path: %s\n", player->http_file_buffering_path); - } - MMPLAYER_FLEAVE(); - return result; -} - -int _mmplayer_set_uri(MMHandleType hplayer, const char* uri) +int +_mmplayer_set_uri(MMHandleType hplayer, const char *uri) { int result = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri); - if (mmf_attrs_commit(player->attrs)) { - LOGE("failed to commit the original uri.\n"); + if (mm_attrs_commit_all(player->attrs)) { + LOGE("failed to commit the original uri."); result = MM_ERROR_PLAYER_INTERNAL; } else { if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE) - LOGE("failed to add the original uri in the uri list.\n"); + LOGE("failed to add the original uri in the uri list."); } MMPLAYER_FLEAVE(); return result; } -int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path) +int +_mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path) { - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; guint num_of_list = 0; MMPLAYER_FENTER(); @@ -10697,21 +6799,21 @@ int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_ MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT); if (player->pipeline && player->pipeline->textbin) { - LOGE("subtitle path is enabled.\n"); + LOGE("subtitle path is enabled."); return MM_ERROR_PLAYER_INVALID_STATE; } num_of_list = g_list_length(player->uri_info.uri_list); - if (is_first_path == TRUE) { + if (is_first_path) { if (num_of_list == 0) { player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri)); - LOGD("add original path : %s", 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); - LOGD("change original path : %s", uri); + SECURE_LOGD("change original path : %s", uri); } } else { MMHandleType attrs = 0; @@ -10731,21 +6833,22 @@ int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_ player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri)); player->uri_info.uri_idx = 0; - LOGD("add original path at first : %s(%d)", original_uri); + SECURE_LOGD("add original path at first : %s", original_uri); } } player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri)); - LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list)); + SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list)); } MMPLAYER_FLEAVE(); return MM_ERROR_NONE; } -int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri) +int +_mmplayer_get_next_uri(MMHandleType hplayer, char **uri) { - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; char *next_uri = NULL; guint num_of_list = 0; @@ -10763,7 +6866,7 @@ int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri) uri_idx = 0; next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx); - LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri); + LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri); *uri = g_strdup(next_uri); } @@ -10773,13 +6876,13 @@ int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri) } static void -__mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, -GstCaps *caps, gpointer data) +__mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, + GstCaps *caps, gpointer data) { - mm_player_t* player = (mm_player_t*)data; - const gchar* klass = NULL; - const gchar* mime = NULL; - gchar* caps_str = NULL; + mmplayer_t *player = (mmplayer_t *)data; + const gchar *klass = NULL; + const gchar *mime = NULL; + gchar *caps_str = NULL; klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS); mime = gst_structure_get_name(gst_caps_get_structure(caps, 0)); @@ -10795,18 +6898,18 @@ GstCaps *caps, gpointer data) } static gboolean -__mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, -GstCaps * caps, gpointer data) +__mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, + GstCaps *caps, gpointer data) { - mm_player_t* player = (mm_player_t*)data; - const char* mime = NULL; + mmplayer_t *player = (mmplayer_t *)data; + const char *mime = NULL; gboolean ret = TRUE; MMPLAYER_LOG_GST_CAPS_TYPE(caps); mime = gst_structure_get_name(gst_caps_get_structure(caps, 0)); if (g_str_has_prefix(mime, "audio")) { - GstStructure* caps_structure = NULL; + GstStructure *caps_structure = NULL; gint samplerate = 0; gint channels = 0; gchar *caps_str = NULL; @@ -10842,16 +6945,225 @@ GstCaps * caps, gpointer data) return ret; } -static int -__mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name) +static gboolean +__mmplayer_is_audio_offload_device_type(mmplayer_t *player) { - int ret = MM_ERROR_NONE; + gboolean ret = TRUE; + GDBusConnection *conn = NULL; + GError *err = NULL; + GVariant *result = NULL; + const gchar *dbus_device_type = NULL; + const gchar *dbus_ret = NULL; + gint idx = 0; + + 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); + g_error_free(err); + ret = FALSE; + goto DONE; + } + + result = g_dbus_connection_call_sync(conn, + "org.pulseaudio.Server", + "/org/pulseaudio/StreamManager", + "org.pulseaudio.StreamManager", + "GetCurrentMediaRoutingPath", + g_variant_new("(s)", "out"), + G_VARIANT_TYPE("(ss)"), + G_DBUS_CALL_FLAGS_NONE, + 2000, + NULL, + &err); + if (!result || err) { + LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL); + g_error_free(err); + ret = FALSE; + goto DONE; + } + + /* device type is listed in stream-map.json at mmfw-sysconf */ + 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; + 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++) { + if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) { + LOGD("audio offload is supportable"); + ret = TRUE; + goto DONE; + } + } + + LOGD("audio offload is not supportable"); + ret = FALSE; + +DONE: + g_variant_unref(result); + g_object_unref(conn); + + return ret; +} + +static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player) +{ + mmplayer_state_e current_state = MM_PLAYER_STATE_NONE; + gint64 position = 0; + + MMPLAYER_RETURN_IF_FAIL(player && player->attrs && + player->pipeline && player->pipeline->mainbin); + + MMPLAYER_CMD_LOCK(player); + current_state = MMPLAYER_CURRENT_STATE(player); + + if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position)) + LOGW("getting current position failed in paused"); + + _mmplayer_unrealize((MMHandleType)player); + _mmplayer_realize((MMHandleType)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"); + + _mmplayer_pause((MMHandleType)player); + + if (current_state == MM_PLAYER_STATE_PLAYING) + _mmplayer_start((MMHandleType)player); + MMPLAYER_CMD_UNLOCK(player); + + LOGD("rebuilding audio pipeline is completed."); +} + +void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data) +{ + mmplayer_t *player = (mmplayer_t *)user_data; + mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER; + gboolean is_supportable = FALSE; + + if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE) + LOGW("failed to get device type"); + else + LOGD("dev type (%d), connected (%d)", dev_type, is_connected); + + if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) && + (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) && + (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) { + LOGD("ignore this dev connected info"); + return; + } + + is_supportable = __mmplayer_is_audio_offload_device_type(player); + if (player->build_audio_offload == is_supportable) { + LOGD("keep current pipeline without re-building"); + return; + } + + /* rebuild pipeline */ + LOGD("re-build pipeline - offload: %d", is_supportable); + player->build_audio_offload = FALSE; + __mmplayer_rebuild_audio_pipeline(player); + + return; +} + +static gboolean +__mmplayer_add_audio_device_connected_cb(mmplayer_t *player) +{ + unsigned int id = 0; + + if (player->audio_device_cb_id != 0) { + LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id); + return TRUE; + } + + if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG, + __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) { + LOGD("added device connected cb (%u)", id); + player->audio_device_cb_id = id; + } else { + LOGW("failed to add device connected cb"); + return FALSE; + } + + return TRUE; +} + +static gboolean +__mmplayer_can_build_audio_offload_path(mmplayer_t *player) +{ + gboolean ret = FALSE; + GstElementFactory *factory = NULL; + + MMPLAYER_FENTER(); + 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)) + goto DONE; + + if (!strcmp(player->ini.audio_offload_sink_element, "")) { + LOGD("there is no audio offload sink"); + goto DONE; + } + + if (player->ini.audio_offload_device_type[0][0] == '\0') { + LOGW("there is no audio device type to support offload"); + goto DONE; + } + + factory = gst_element_factory_find(player->ini.audio_offload_sink_element); + if (!factory) { + LOGW("there is no installed audio offload sink element"); + goto DONE; + } + gst_object_unref(factory); + + if (!__mmplayer_add_audio_device_connected_cb(player)) + goto DONE; + + if (!__mmplayer_is_audio_offload_device_type(player)) + goto DONE; + + LOGD("audio offload can be built"); + ret = TRUE; + +DONE: + MMPLAYER_FLEAVE(); + return ret; +} + +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"))) { - GstStructure* str = NULL; - gint channels = 0; + mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */ + + if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) { + LOGD("expose audio path to build offload output path"); + player->build_audio_offload = TRUE; + /* update codec info */ + player->not_supported_codec &= MISSING_PLUGIN_VIDEO; + player->can_support_codec |= FOUND_PLUGIN_AUDIO; + player->audiodec_linked = 1; + + ret = GST_AUTOPLUG_SELECT_EXPOSE; + goto DONE; + } + mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type); LOGD("audio codec type: %d", codec_type); @@ -10860,7 +7172,7 @@ __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* cap 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 = MM_ERROR_PLAYER_INTERNAL; + ret = GST_AUTOPLUG_SELECT_SKIP; goto DONE; } } @@ -10869,19 +7181,11 @@ __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* cap 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 = MM_ERROR_PLAYER_INTERNAL; + ret = GST_AUTOPLUG_SELECT_SKIP; goto DONE; } } - str = gst_caps_get_structure(caps, 0); - if (str) { - gst_structure_get_int(str, "channels", &channels); - - LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels); - if (player->max_audio_channels < channels) - player->max_audio_channels = channels; - } /* set stream information */ if (!player->audiodec_linked) __mmplayer_set_audio_attrs(player, caps); @@ -10901,7 +7205,7 @@ __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* cap 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 = MM_ERROR_PLAYER_INTERNAL; + ret = GST_AUTOPLUG_SELECT_SKIP; goto DONE; } } @@ -10909,7 +7213,7 @@ __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* cap /* 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 = MM_ERROR_PLAYER_INTERNAL; + ret = GST_AUTOPLUG_SELECT_SKIP; goto DONE; } } @@ -10925,12 +7229,12 @@ __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* cap &player->video_decoder_resource) != MM_RESOURCE_MANAGER_ERROR_NONE) { LOGE("could not mark video_decoder resource for acquire"); - ret = MM_ERROR_PLAYER_INTERNAL; + ret = GST_AUTOPLUG_SELECT_SKIP; goto DONE; } } else { LOGW("video decoder resource is already acquired, skip it."); - ret = MM_ERROR_PLAYER_INTERNAL; + ret = GST_AUTOPLUG_SELECT_SKIP; goto DONE; } @@ -10938,8 +7242,8 @@ __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* cap /* 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\n"); - ret = MM_ERROR_PLAYER_INTERNAL; + LOGE("could not acquire resources for video decoding"); + ret = GST_AUTOPLUG_SELECT_SKIP; goto DONE; } } @@ -10954,24 +7258,16 @@ DONE: return ret; } -static gint -__mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, -GstCaps* caps, GstElementFactory* factory, gpointer data) +gint +__mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad, + GstCaps *caps, GstElementFactory *factory, gpointer data) { - /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed - We are defining our own and will be removed when it actually exposed */ - typedef enum { - GST_AUTOPLUG_SELECT_TRY, - GST_AUTOPLUG_SELECT_EXPOSE, - GST_AUTOPLUG_SELECT_SKIP - } GstAutoplugSelectResult; - GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY; - mm_player_t* player = (mm_player_t*)data; + mmplayer_t *player = (mmplayer_t *)data; - gchar* factory_name = NULL; - gchar* caps_str = NULL; - const gchar* klass = NULL; + gchar *factory_name = NULL; + gchar *caps_str = NULL; + const gchar *klass = NULL; gint idx = 0; factory_name = GST_OBJECT_NAME(factory); @@ -10989,7 +7285,7 @@ GstCaps* caps, GstElementFactory* factory, gpointer data) /* 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]\n", + LOGW("skipping [%s] by exculde keyword [%s]", factory_name, player->ini.exclude_element_keyword[idx]); result = GST_AUTOPLUG_SELECT_SKIP; @@ -10997,6 +7293,15 @@ GstCaps* caps, GstElementFactory* factory, gpointer data) } } + for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) { + if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) { + LOGW("skipping [%s] by unsupported codec keyword [%s]", + factory_name, player->ini.unsupported_codec_keyword[idx]); + result = GST_AUTOPLUG_SELECT_SKIP; + goto DONE; + } + } + /* exclude webm format */ /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT * because webm format is not supportable. @@ -11015,7 +7320,7 @@ GstCaps* caps, GstElementFactory* factory, gpointer data) * So, those plugins should be skipped for error handling. */ if (g_strrstr(klass, "Codec/Decoder/Image")) { - LOGD("skipping [%s] by not required\n", factory_name); + LOGD("skipping [%s] by not required", factory_name); result = GST_AUTOPLUG_SELECT_SKIP; goto DONE; } @@ -11023,13 +7328,13 @@ GstCaps* caps, GstElementFactory* factory, gpointer data) if ((MMPLAYER_IS_MS_BUFF_SRC(player)) && (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) { // TO CHECK : subtitle if needed, add subparse exception. - LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name); + LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name); result = GST_AUTOPLUG_SELECT_SKIP; goto DONE; } if (g_strrstr(factory_name, "mpegpsdemux")) { - LOGD("skipping PS container - not support\n"); + LOGD("skipping PS container - not support"); result = GST_AUTOPLUG_SELECT_SKIP; goto DONE; } @@ -11046,8 +7351,8 @@ GstCaps* caps, GstElementFactory* factory, gpointer data) /* don't make video because of not required */ if ((stype == MM_DISPLAY_SURFACE_NULL) && - (player->set_mode.media_packet_video_stream == FALSE)) { - LOGD("no video because it's not required. -> return expose"); + (!player->set_mode.video_export)) { + LOGD("no need video decoding, expose pad"); result = GST_AUTOPLUG_SELECT_EXPOSE; goto DONE; } @@ -11070,9 +7375,9 @@ GstCaps* caps, GstElementFactory* factory, gpointer data) } if (g_strrstr(klass, "Codec/Decoder")) { - if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) { - LOGD("skipping %s codec", factory_name); - result = GST_AUTOPLUG_SELECT_SKIP; + result = __mmplayer_check_codec_info(player, klass, caps, factory_name); + if (result != GST_AUTOPLUG_SELECT_TRY) { + LOGW("skip add decoder"); goto DONE; } } @@ -11084,30 +7389,33 @@ DONE: } static void -__mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, -gpointer data) +__mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, + gpointer data) { - //mm_player_t* player = (mm_player_t*)data; - GstCaps* caps = NULL; + //mmplayer_t *player = (mmplayer_t *)data; + GstCaps *caps = NULL; - LOGD("[Decodebin2] pad-removed signal\n"); + LOGD("[Decodebin2] pad-removed signal"); caps = gst_pad_query_caps(new_pad, NULL); - if (caps) { - gchar* caps_str = NULL; - caps_str = gst_caps_to_string(caps); + if (!caps) { + LOGW("query caps is NULL"); + return; + } - LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem)); + gchar *caps_str = NULL; + caps_str = gst_caps_to_string(caps); - MMPLAYER_FREEIF(caps_str); - gst_caps_unref(caps); - } + LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem)); + + MMPLAYER_FREEIF(caps_str); + gst_caps_unref(caps); } static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data) { - mm_player_t* player = (mm_player_t*)data; + mmplayer_t *player = (mmplayer_t *)data; GstIterator *iter = NULL; GValue item = { 0, }; GstPad *pad = NULL; @@ -11119,18 +7427,13 @@ __mmplayer_gst_decode_drained(GstElement *bin, gpointer data) LOGD("__mmplayer_gst_decode_drained"); - if (player->use_deinterleave == TRUE) { - LOGD("group playing mode."); - return; - } - 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_next_play_path(player)) { + !__mmplayer_verify_gapless_play_path(player)) { LOGD("decoding is finished."); __mmplayer_reset_gapless_state(player); MMPLAYER_CMD_UNLOCK(player); @@ -11183,35 +7486,26 @@ __mmplayer_gst_decode_drained(GstElement *bin, gpointer data) MMPLAYER_FLEAVE(); } -static void +void __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data) { - mm_player_t* player = (mm_player_t*)data; - const gchar* klass = NULL; - gchar* factory_name = NULL; + mmplayer_t *player = (mmplayer_t *)data; + const gchar *klass = NULL; + gchar *factory_name = NULL; klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS); factory_name = GST_OBJECT_NAME(gst_element_get_factory(element)); - LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element)); + LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element)); if (__mmplayer_add_dump_buffer_probe(player, element)) LOGD("add buffer probe"); - //<- if (g_strrstr(klass, "Codec/Decoder/Audio")) { - gchar* selected = NULL; + gchar *selected = NULL; selected = g_strdup(GST_ELEMENT_NAME(element)); player->audio_decoders = g_list_append(player->audio_decoders, selected); } - //-> temp code - - if (g_strrstr(klass, "Parser")) { - gchar* selected = NULL; - - selected = g_strdup(factory_name); - player->parsers = g_list_append(player->parsers, selected); - } if (g_strrstr(klass, "Demuxer/Adaptive")) { player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX; @@ -11225,20 +7519,10 @@ __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data "max-video-width", player->adaptive_info.limit.width, "max-video-height", player->adaptive_info.limit.height, NULL); - } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) { - /* FIXIT : first value will be overwritten if there's more - * than 1 demuxer/parser - */ - - //LOGD("plugged element is demuxer. take it\n"); + } else if (g_strrstr(klass, "Demuxer")) { + //LOGD("plugged element is demuxer. take it"); player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX; player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element; - - /*Added for multi audio support */ // Q. del? - if (g_strrstr(klass, "Demux")) { - player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX; - player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element; - } } if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) { @@ -11249,13 +7533,10 @@ __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data // to support trust-zone only if (g_strrstr(factory_name, "asfdemux")) { - LOGD("set file-location %s\n", player->profile.uri); + LOGD("set file-location %s", player->profile.uri); g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL); - - if (player->video_hub_download_mode == TRUE) - g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL); } else if (g_strrstr(factory_name, "legacyh264parse")) { - LOGD("[%s] output-format to legacyh264parse\n", "mssdemux"); + LOGD("[%s] output-format to legacyh264parse", "mssdemux"); g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */ } else if (g_strrstr(factory_name, "mpegaudioparse")) { if ((MMPLAYER_IS_HTTP_STREAMING(player)) && @@ -11269,70 +7550,26 @@ __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) && (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) { - LOGD("plugged element is multiqueue. take it\n"); + LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element)); player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER; player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element; - if (!MMPLAYER_IS_HTTP_PD(player) && - ((MMPLAYER_IS_HTTP_STREAMING(player)) || - (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) { + if ((MMPLAYER_IS_HTTP_STREAMING(player)) || + (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, - TRUE, - player->ini.http_buffering_time, - 1.0, - player->ini.http_buffering_limit); - + __mm_player_streaming_set_multiqueue(player->streamer, element); __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst); } - } - - return; -} - -static gboolean __mmplayer_configure_audio_callback(mm_player_t* player) -{ - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - - if (MMPLAYER_IS_STREAMING(player)) - return FALSE; - - /* This callback can be set to music player only. */ - if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) { - LOGW("audio callback is not supported for video"); - return FALSE; - } - - if (player->audio_stream_cb) { - GstPad *pad = NULL; - - pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink"); - - if (!pad) { - LOGE("failed to get sink pad from audiosink to probe data\n"); - return FALSE; - } - player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, - __mmplayer_audio_stream_probe, player, NULL); - gst_object_unref(pad); - - pad = NULL; - } else { - LOGE("There is no audio callback to configure.\n"); - return FALSE; } - MMPLAYER_FLEAVE(); - - return TRUE; + return; } static void -__mmplayer_release_misc(mm_player_t* player) +__mmplayer_release_misc(mmplayer_t *player) { int i; bool cur_mode = player->set_mode.rich_audio; @@ -11340,14 +7577,13 @@ __mmplayer_release_misc(mm_player_t* player) MMPLAYER_RETURN_IF_FAIL(player); - player->video_stream_cb = NULL; - player->video_stream_cb_user_param = NULL; - player->video_stream_prerolled = FALSE; + player->video_decoded_cb = NULL; + player->video_decoded_cb_user_param = NULL; + player->video_stream_prerolled = false; - player->audio_stream_cb = NULL; - player->audio_stream_render_cb_ex = NULL; - player->audio_stream_cb_user_param = NULL; - player->audio_stream_sink_sync = 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; @@ -11358,7 +7594,7 @@ __mmplayer_release_misc(mm_player_t* player) player->sent_bos = FALSE; player->playback_rate = DEFAULT_PLAYBACK_RATE; - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; player->total_bitrate = 0; player->total_maximum_bitrate = 0; @@ -11370,25 +7606,25 @@ __mmplayer_release_misc(mm_player_t* player) player->http_content_size = 0; player->not_supported_codec = MISSING_PLUGIN_NONE; player->can_support_codec = FOUND_PLUGIN_NONE; - player->pending_seek.is_pending = FALSE; - player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME; + player->pending_seek.is_pending = false; player->pending_seek.pos = 0; player->msg_posted = FALSE; player->has_many_types = FALSE; - player->max_audio_channels = 0; - player->video_share_api_delta = 0; - player->video_share_clock_delta = 0; player->is_subtitle_force_drop = FALSE; player->play_subtitle = FALSE; player->adjust_subtitle_pos = 0; - player->last_multiwin_status = FALSE; player->has_closed_caption = FALSE; - player->set_mode.media_packet_video_stream = FALSE; + player->set_mode.video_export = false; player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE; - memset(&player->set_mode, 0, sizeof(MMPlayerSetMode)); + memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t)); /* recover mode */ player->set_mode.rich_audio = cur_mode; + 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; + for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) { player->bitrate[i] = 0; player->maximum_bitrate[i] = 0; @@ -11435,11 +7671,12 @@ __mmplayer_release_misc(mm_player_t* player) player->sound.rg_enable = false; + __mmplayer_initialize_video_roi(player); MMPLAYER_FLEAVE(); } static void -__mmplayer_release_misc_post(mm_player_t* player) +__mmplayer_release_misc_post(mmplayer_t *player) { char *original_uri = NULL; MMPLAYER_FENTER(); @@ -11450,17 +7687,6 @@ __mmplayer_release_misc_post(mm_player_t* player) mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0); - /* clean found parsers */ - if (player->parsers) { - GList *parsers = player->parsers; - for (; parsers; parsers = g_list_next(parsers)) { - gchar *name = parsers->data; - MMPLAYER_FREEIF(name); - } - g_list_free(player->parsers); - player->parsers = NULL; - } - /* clean found audio decoders */ if (player->audio_decoders) { GList *a_dec = player->audio_decoders; @@ -11478,10 +7704,10 @@ __mmplayer_release_misc_post(mm_player_t* player) if (player->attrs) { mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri); - LOGD("restore original uri = %s\n", original_uri); + LOGD("restore original uri = %s", original_uri); - if (mmf_attrs_commit(player->attrs)) - LOGE("failed to commit the original uri.\n"); + if (mm_attrs_commit_all(player->attrs)) + LOGE("failed to commit the original uri."); } GList *uri_list = player->uri_info.uri_list; @@ -11511,49 +7737,8 @@ __mmplayer_release_misc_post(mm_player_t* player) MMPLAYER_FLEAVE(); } -static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name) -{ - GstElement *element = NULL; - GstPad *sinkpad; - - LOGD("creating %s to plug\n", name); - - element = gst_element_factory_make(name, NULL); - if (!element) { - LOGE("failed to create queue\n"); - return NULL; - } - - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) { - LOGE("failed to set state READY to %s\n", name); - gst_object_unref(element); - return NULL; - } - - if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) { - LOGE("failed to add %s\n", name); - gst_object_unref(element); - return NULL; - } - - sinkpad = gst_element_get_static_pad(element, "sink"); - - if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) { - LOGE("failed to link %s\n", name); - gst_object_unref(sinkpad); - gst_object_unref(element); - return NULL; - } - - LOGD("linked %s to pipeline successfully\n", name); - - gst_object_unref(sinkpad); - - return element; -} - gboolean -__mmplayer_check_subtitle(mm_player_t* player) +__mmplayer_check_subtitle(mmplayer_t *player) { MMHandleType attrs = 0; char *subtitle_uri = NULL; @@ -11571,7 +7756,7 @@ __mmplayer_check_subtitle(mm_player_t* player) if (!subtitle_uri || !strlen(subtitle_uri)) return FALSE; - LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri)); + SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri)); player->is_external_subtitle_present = TRUE; MMPLAYER_FLEAVE(); @@ -11579,443 +7764,72 @@ __mmplayer_check_subtitle(mm_player_t* player) return TRUE; } -static gboolean -__mmplayer_can_extract_pcm(mm_player_t* player) -{ - MMHandleType attrs = 0; - gboolean sound_extraction = FALSE; - - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("fail to get attributes."); - return FALSE; - } - - /* get sound_extraction property */ - mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction); - - if (!sound_extraction) { - LOGD("checking pcm extraction mode : %d ", sound_extraction); - return FALSE; - } - - return TRUE; -} - -static gboolean -__mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message) -{ - LOGD("\n"); - MMMessageParamType msg_param; - gchar *msg_src_element = NULL; - GstStructure *s = NULL; - guint error_id = 0; - gchar *error_string = NULL; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE); - - s = gst_structure_copy(gst_message_get_structure(message)); - - - if (!gst_structure_get_uint(s, "error_id", &error_id)) - error_id = MMPLAYER_STREAMING_ERROR_NONE; - - switch (error_id) { - case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO: - msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO; - break; - case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO: - msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO; - break; - case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL: - msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL; - break; - case MMPLAYER_STREAMING_ERROR_DNS_FAIL: - msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL; - break; - case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED; - break; - case MMPLAYER_STREAMING_ERROR_BAD_SERVER: - msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER; - break; - case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL: - msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL; - break; - case MMPLAYER_STREAMING_ERROR_INVALID_URL: - msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL; - break; - case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG: - msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG; - break; - case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES: - msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES; - break; - case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT: - msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT; - break; - case MMPLAYER_STREAMING_ERROR_BAD_REQUEST: - msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST; - break; - case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED; - break; - case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED; - break; - case MMPLAYER_STREAMING_ERROR_FORBIDDEN: - msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN; - break; - case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND: - msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND; - break; - case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED; - break; - case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE; - break; - case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED; - break; - case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT: - msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT; - break; - case MMPLAYER_STREAMING_ERROR_GONE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE; - break; - case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED; - break; - case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED; - break; - case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE; - break; - case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE; - break; - case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE; - break; - case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD: - msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD; - break; - case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND: - msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND; - break; - case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH: - msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH; - break; - case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID: - msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID; - break; - case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE; - break; - case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE; - break; - case MMPLAYER_STREAMING_ERROR_INVALID_RANGE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE; - break; - case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY: - msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY; - break; - case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED; - break; - case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED; - break; - case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT: - msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT; - break; - case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE; - break; - case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR: - msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR; - break; - case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED; - break; - case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY: - msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY; - break; - case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE; - break; - case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT: - msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT; - break; - case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED; - break; - case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED; - break; - default: - { - gst_structure_free(s); - return MM_ERROR_PLAYER_STREAMING_FAIL; - } - } - - error_string = g_strdup(gst_structure_get_string(s, "error_string")); - if (error_string) - msg_param.data = (void *) error_string; - - if (message->src) { - msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src)); - - LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n", - msg_src_element, msg_param.code, (char*)msg_param.data); - } - - /* post error to application */ - if (!player->msg_posted) { - MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); - - /* don't post more if one was sent already */ - player->msg_posted = TRUE; - } else - LOGD("skip error post because it's sent already.\n"); - - gst_structure_free(s); - MMPLAYER_FLEAVE(); - g_free(error_string); - - return TRUE; - -} - -static void -__mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms) -{ - MMPLAYER_RETURN_IF_FAIL(player); - - /* post now if delay is zero */ - if (delay_in_ms == 0 || player->set_mode.pcm_extraction) { - LOGD("eos delay is zero. posting EOS now\n"); - MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL); - - if (player->set_mode.pcm_extraction) - __mmplayer_cancel_eos_timer(player); - - return; - } - - /* cancel if existing */ - __mmplayer_cancel_eos_timer(player); - - /* init new timeout */ - /* NOTE : consider give high priority to this timer */ - LOGD("posting EOS message after [%d] msec\n", delay_in_ms); - - player->eos_timer = g_timeout_add(delay_in_ms, - __mmplayer_eos_timer_cb, player); - - player->context.global_default = g_main_context_default(); - LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer); - - /* check timer is valid. if not, send EOS now */ - if (player->eos_timer == 0) { - LOGW("creating timer for delayed EOS has failed. sending EOS now\n"); - MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL); - } -} - -static void -__mmplayer_cancel_eos_timer(mm_player_t* player) +void +__mmplayer_cancel_eos_timer(mmplayer_t *player) { MMPLAYER_RETURN_IF_FAIL(player); if (player->eos_timer) { LOGD("cancel eos timer"); __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer); - player->eos_timer = 0; - } - - return; -} - -static gboolean -__mmplayer_eos_timer_cb(gpointer u_data) -{ - mm_player_t* player = NULL; - MMHandleType attrs = 0; - int count = 0; - - MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE); - - player = (mm_player_t*) u_data; - attrs = MMPLAYER_GET_ATTRS(player); - - mm_attrs_get_int_by_name(attrs, "profile_play_count", &count); - - if (count == -1) { - gint ret_value = 0; - ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE); - if (ret_value != MM_ERROR_NONE) - LOGE("seeking to 0 failed in repeat play"); - } else { - /* posting eos */ - MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL); - } - - /* we are returning FALSE as we need only one posting */ - return FALSE; -} - -/* sending event to one of sinkelements */ -static gboolean -__gst_send_event_to_sink(mm_player_t* player, GstEvent* event) -{ - GstEvent * event2 = NULL; - GList *sinks = NULL; - gboolean res = FALSE; - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE); - - /* While adding subtitles in live feeds seek is getting called. - Adding defensive check in framework layer.*/ - if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) { - if (MMPLAYER_IS_LIVE_STREAMING(player)) { - LOGE("Should not send seek event during live playback"); - return TRUE; - } - } - - if (player->play_subtitle) - event2 = gst_event_copy((const GstEvent *)event); - - sinks = player->sink_elements; - while (sinks) { - GstElement *sink = GST_ELEMENT_CAST(sinks->data); - - if (GST_IS_ELEMENT(sink)) { - /* keep ref to the event */ - gst_event_ref(event); - - if ((res = gst_element_send_event(sink, event))) { - LOGD("sending event[%s] to sink element [%s] success!\n", - GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink)); - - /* rtsp case, asyn_done is not called after seek during pause state */ - if (MMPLAYER_IS_RTSP_STREAMING(player)) { - if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) { - if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) { - LOGD("RTSP seek completed, after pause state..\n"); - player->doing_seek = FALSE; - MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); - } - - } - } - - if (MMPLAYER_IS_MS_BUFF_SRC(player)) { - sinks = g_list_next(sinks); - continue; - } else { - break; - } - } - - LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n", - GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink)); - } - - sinks = g_list_next(sinks); - } - - /* Note : Textbin is not linked to the video or audio bin. - * It needs to send the event to the text sink seperatelly. - */ - if (player->play_subtitle && player->pipeline) { - GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst); - - if (GST_IS_ELEMENT(text_sink)) { - /* keep ref to the event */ - gst_event_ref(event2); - - if ((res = gst_element_send_event(text_sink, event2))) - LOGD("sending event[%s] to subtitle sink element [%s] success!\n", - GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink)); - else - LOGE("sending event[%s] to subtitle sink element [%s] failed!\n", - GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink)); - - gst_event_unref(event2); - } - } - - gst_event_unref(event); - - MMPLAYER_FLEAVE(); + player->eos_timer = 0; + } - return res; + return; } static void -__mmplayer_add_sink(mm_player_t* player, GstElement* sink) +__mmplayer_add_sink(mmplayer_t *player, GstElement *sink) { MMPLAYER_FENTER(); MMPLAYER_RETURN_IF_FAIL(player); MMPLAYER_RETURN_IF_FAIL(sink); - player->sink_elements = - g_list_append(player->sink_elements, sink); + player->sink_elements = g_list_append(player->sink_elements, sink); MMPLAYER_FLEAVE(); } static void -__mmplayer_del_sink(mm_player_t* player, GstElement* sink) +__mmplayer_del_sink(mmplayer_t *player, GstElement *sink) { MMPLAYER_FENTER(); MMPLAYER_RETURN_IF_FAIL(player); MMPLAYER_RETURN_IF_FAIL(sink); - player->sink_elements = - g_list_remove(player->sink_elements, sink); + player->sink_elements = g_list_remove(player->sink_elements, sink); MMPLAYER_FLEAVE(); } -static gboolean -__gst_seek(mm_player_t* player, GstElement * element, gdouble rate, - GstFormat format, GstSeekFlags flags, GstSeekType cur_type, - gint64 cur, GstSeekType stop_type, gint64 stop) +void +__mmplayer_add_signal_connection(mmplayer_t *player, GObject *object, + mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data) { - GstEvent* event = NULL; - gboolean result = FALSE; + mmplayer_signal_item_t *item = NULL; MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player); - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - - if (player->pipeline && player->pipeline->textbin) - __mmplayer_drop_subtitle(player, FALSE); + if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) { + LOGE("invalid signal type [%d]", type); + return; + } - event = gst_event_new_seek(rate, format, flags, cur_type, - cur, stop_type, stop); + item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t)); + if (!item) { + LOGE("cannot connect signal [%s]", signal); + return; + } - result = __gst_send_event_to_sink(player, event); + item->obj = object; + item->sig = g_signal_connect(object, signal, cb_funct, u_data); + player->signals[type] = g_list_append(player->signals[type], item); MMPLAYER_FLEAVE(); - - return result; + return; } /* NOTE : be careful with calling this api. please refer to below glib comment @@ -12036,10 +7850,10 @@ __gst_seek(mm_player_t* player, GstElement * element, gdouble rate, * g_signal_handler_disconnect(instance, id); */ static void -__mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type) +__mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type) { - GList* sig_list = NULL; - MMPlayerSignalItem* item = NULL; + GList *sig_list = NULL; + mmplayer_signal_item_t *item = NULL; MMPLAYER_FENTER(); @@ -12077,16 +7891,12 @@ __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType typ return; } -int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay) +int +_mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay) { - mm_player_t* player = 0; + mmplayer_t *player = 0; int prev_display_surface_type = 0; void *prev_display_overlay = NULL; - const gchar *klass = NULL; - gchar *cur_videosink_name = NULL; - int ret = 0; - int i = 0; - int num_of_dec = 2; /* DEC1, DEC2 */ MMPLAYER_FENTER(); @@ -12095,6 +7905,14 @@ int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface 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"); + return MM_ERROR_NONE; + } + + LOGD("videosink element is not yet ready"); + if (surface_type >= MM_DISPLAY_SURFACE_NUM) { LOGE("Not support this surface type(%d) for changing vidoesink", surface_type); MMPLAYER_FLEAVE(); @@ -12117,350 +7935,25 @@ int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface return MM_ERROR_PLAYER_INTERNAL; } - /* check videosink element is created */ - if (!player->pipeline || !player->pipeline->videobin || - !player->pipeline->videobin[MMPLAYER_V_SINK].gst) { - LOGD("videosink element is not yet ready"); - - /* 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 (mmf_attrs_commit(player->attrs)) { - LOGE("failed to commit attribute"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; - } - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - } else { - /* get player command status */ - if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) { - LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INVALID_STATE; - } - - /* surface change */ - for (i = 0 ; i < num_of_dec ; i++) { - if (player->pipeline->mainbin && - player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) { - GstElementFactory *decfactory; - decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst); - - klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS); - if ((g_strrstr(klass, "Codec/Decoder/Video"))) { - if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) { - ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay); - if (ret) { - goto ERROR_CASE; - } else { - LOGW("success to changing display surface(%d)", surface_type); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - } - } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) { - ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay); - if (ret) { - goto ERROR_CASE; - } else { - LOGW("success to changing display surface(%d)", surface_type); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - } - } else { - LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name); - ret = MM_ERROR_PLAYER_INTERNAL; - goto ERROR_CASE; - } - } - } - } - } - -ERROR_CASE: - /* rollback to previous attributes */ - mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type); - mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*)); - if (mmf_attrs_commit(player->attrs)) { - LOGE("failed to commit attributes to rollback"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; - } - MMPLAYER_FLEAVE(); - return ret; -} - -/* NOTE : It does not support some use cases, eg using colorspace converter */ -int -__mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay) -{ - GstPad *src_pad_dec = NULL; - GstPad *sink_pad_videosink = NULL; - GstPad *sink_pad_videobin = NULL; - GstClock *clock = NULL; - MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM; - int ret = MM_ERROR_NONE; - gboolean is_audiobin_created = TRUE; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT); - MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT); - MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT); - - LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element); - LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay); - - /* get information whether if audiobin is created */ - if (!player->pipeline->audiobin || - !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) { - LOGW("audiobin is null, this video content may not have audio data"); - is_audiobin_created = FALSE; - } - - /* get current state of player */ - previous_state = MMPLAYER_CURRENT_STATE(player); - LOGD("previous state(%d)", previous_state); - - - /* get src pad of decoder and block it */ - src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src"); - if (!src_pad_dec) { - LOGE("failed to get src pad from decode in mainbin"); - return MM_ERROR_PLAYER_INTERNAL; - } - - if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) { - LOGW("trying to block pad(video)"); -// if (!gst_pad_set_blocked(src_pad_dec, TRUE)) - gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, - NULL, NULL, NULL); - { - LOGE("failed to set block pad(video)"); - return MM_ERROR_PLAYER_INTERNAL; - } - LOGW("pad is blocked(video)"); - } else { - /* no data flows, so no need to do pad_block */ - if (player->doing_seek) - LOGW("not completed seek(%d), do nothing", player->doing_seek); - - LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)"); - } - - /* remove pad */ - if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, - GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) { - LOGE("failed to remove previous ghost_pad for videobin"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* change state of videobin to NULL */ - LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL); - ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL); - if (ret != GST_STATE_CHANGE_SUCCESS) { - LOGE("failed to change state of videobin to NULL"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* unlink between decoder and videobin and remove previous videosink from videobin */ - gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst)); - if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) { - LOGE("failed to remove former videosink from videobin"); - return MM_ERROR_PLAYER_INTERNAL; - } - - __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst); - - /* create a new videosink and add it to videobin */ - player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink"); - if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) { - LOGE("failed to create videosink element\n"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; - } - gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst)); - __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst); - g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL); - - /* save attributes */ - if (player->attrs) { - /* set a new display surface type */ - mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type); - /* set a new diplay overlay */ - switch (surface_type) { - case MM_DISPLAY_SURFACE_OVERLAY: - LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay); - mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay)); - break; - default: - LOGE("invalid type(%d) for changing display surface", surface_type); - MMPLAYER_FLEAVE(); - return MM_ERROR_INVALID_ARGUMENT; - } - if (mmf_attrs_commit(player->attrs)) { - LOGE("failed to commit"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; - } - } else { - LOGE("player->attrs is null, failed to save attributes"); + /* 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; } - /* update video param */ - if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) { - LOGE("failed to update video param"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* change state of videobin to READY */ - LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY); - ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY); - if (ret != GST_STATE_CHANGE_SUCCESS) { - LOGE("failed to change state of videobin to READY"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* change ghostpad */ - sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink"); - if (!sink_pad_videosink) { - LOGE("failed to get sink pad from videosink element"); - return MM_ERROR_PLAYER_INTERNAL; - } - player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink); - if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) { - LOGE("failed to set active to ghost_pad"); - return MM_ERROR_PLAYER_INTERNAL; - } - if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) { - LOGE("failed to change ghostpad for videobin"); - return MM_ERROR_PLAYER_INTERNAL; - } - gst_object_unref(sink_pad_videosink); - - /* link decoder with videobin */ - sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink"); - if (!sink_pad_videobin) { - LOGE("failed to get sink pad from videobin"); - return MM_ERROR_PLAYER_INTERNAL; - } - if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) { - LOGE("failed to link"); - return MM_ERROR_PLAYER_INTERNAL; - } - gst_object_unref(sink_pad_videobin); - - /* clock setting for a new videosink plugin */ - /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink, - so we set it from audiosink plugin or pipeline(system clock) */ - if (!is_audiobin_created) { - LOGW("audiobin is not created, get clock from pipeline.."); - clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst); - } else { - clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst); - } - if (clock) { - GstClockTime now; - GstClockTime base_time; - LOGD("set the clock to videosink"); - gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock); - clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst); - if (clock) { - LOGD("got clock of videosink"); - now = gst_clock_get_time(clock); - base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time; - LOGD("at time %" GST_TIME_FORMAT ", base %" - GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time)); - } else { - LOGE("failed to get clock of videosink after setting clock"); - return MM_ERROR_PLAYER_INTERNAL; - } - } else - LOGW("failed to get clock, maybe it is the time before first playing"); - - if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) { - /* change state of videobin to PAUSED */ - LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING); - ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING); - if (ret != GST_STATE_CHANGE_FAILURE) { - LOGW("change state of videobin to PLAYING, ret(%d)", ret); - } else { - LOGE("failed to change state of videobin to PLAYING"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* release blocked and unref src pad of video decoder */ - #if 0 - if (!gst_pad_set_blocked(src_pad_dec, FALSE)) { - LOGE("failed to set pad blocked FALSE(video)"); - return MM_ERROR_PLAYER_INTERNAL; - } - #endif - LOGW("pad is unblocked(video)"); - } else { - if (player->doing_seek) - LOGW("not completed seek(%d)", player->doing_seek); - /* change state of videobin to PAUSED */ - LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED); - ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED); - if (ret != GST_STATE_CHANGE_FAILURE) { - LOGW("change state of videobin to PAUSED, ret(%d)", ret); - } else { - LOGE("failed to change state of videobin to PLAYING"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* already skipped pad block */ - LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)"); - } - - /* do get/set position for new videosink plugin */ - { - unsigned long position = 0; - gint64 pos_msec = 0; - - LOGD("do get/set position for new videosink plugin"); - if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) { - LOGE("failed to get position"); - return MM_ERROR_PLAYER_INTERNAL; - } -#ifdef SINKCHANGE_WITH_ACCURATE_SEEK - /* accurate seek */ - if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) { - LOGE("failed to set position"); - return MM_ERROR_PLAYER_INTERNAL; - } -#else - /* key unit seek */ - pos_msec = position * G_GINT64_CONSTANT(1000000); - ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0, - GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), - GST_SEEK_TYPE_SET, pos_msec, - GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); - if (!ret) { - LOGE("failed to set position"); - return MM_ERROR_PLAYER_INTERNAL; - } -#endif - } - - if (src_pad_dec) - gst_object_unref(src_pad_dec); - LOGD("success to change sink"); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; } - /* Note : if silent is true, then subtitle would not be displayed. :*/ -int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent) +int +_mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent) { - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; MMPLAYER_FENTER(); @@ -12469,17 +7962,18 @@ int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent) player->set_mode.subtitle_off = silent; - LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF"); + LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF"); MMPLAYER_FLEAVE(); return MM_ERROR_NONE; } -int _mmplayer_sync_subtitle_pipeline(mm_player_t* player) +int +_mmplayer_sync_subtitle_pipeline(mmplayer_t *player) { - MMPlayerGstElement* mainbin = NULL; - MMPlayerGstElement* textbin = NULL; + mmplayer_gst_element_t *mainbin = NULL; + mmplayer_gst_element_t *textbin = NULL; GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; GstState current_state = GST_STATE_VOID_PENDING; GstState element_state = GST_STATE_VOID_PENDING; @@ -12523,12 +8017,11 @@ int _mmplayer_sync_subtitle_pipeline(mm_player_t* player) ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND); if (GST_STATE_CHANGE_FAILURE == ret) { - LOGE("fail to state change.\n"); + LOGE("fail to state change."); result = MM_ERROR_PLAYER_INTERNAL; goto ERROR; } } - gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time); gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time); @@ -12540,14 +8033,14 @@ int _mmplayer_sync_subtitle_pipeline(mm_player_t* player) // seek to current position if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) { result = MM_ERROR_PLAYER_INVALID_STATE; - LOGE("gst_element_query_position failed, invalid state\n"); + LOGE("gst_element_query_position failed, invalid state"); goto ERROR; } - LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate); + 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) { - __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 */ @@ -12581,16 +8074,16 @@ ERROR: } static int -__mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath) +__mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath) { GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; GstState current_state = GST_STATE_VOID_PENDING; MMHandleType attrs = 0; - MMPlayerGstElement* mainbin = NULL; - MMPlayerGstElement* textbin = NULL; + mmplayer_gst_element_t *mainbin = NULL; + mmplayer_gst_element_t *textbin = NULL; - gchar* subtitle_uri = NULL; + gchar *subtitle_uri = NULL; int result = MM_ERROR_NONE; const gchar *charset = NULL; @@ -12609,20 +8102,20 @@ __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* fi current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst); if (current_state < GST_STATE_READY) { result = MM_ERROR_PLAYER_INVALID_STATE; - LOGE("Pipeline is not in proper state\n"); + LOGE("Pipeline is not in proper state"); goto EXIT; } attrs = MMPLAYER_GET_ATTRS(player); if (!attrs) { - LOGE("cannot get content attribute\n"); + LOGE("cannot get content attribute"); result = MM_ERROR_PLAYER_INTERNAL; goto EXIT; } mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri); if (!subtitle_uri || strlen(subtitle_uri) < 1) { - LOGE("subtitle uri is not proper filepath\n"); + LOGE("subtitle uri is not proper filepath"); result = MM_ERROR_PLAYER_INVALID_URI; goto EXIT; } @@ -12633,16 +8126,16 @@ __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* fi goto EXIT; } - LOGD("old subtitle file path is [%s]\n", subtitle_uri); - LOGD("new subtitle file path is [%s]\n", filepath); + LOGD("old subtitle file path is [%s]", subtitle_uri); + 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\n"); + LOGD("No need to swtich subtitle, as input filepath is same as current filepath"); goto EXIT; } else { mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); - if (mmf_attrs_commit(player->attrs)) { - LOGE("failed to commit.\n"); + if (mm_attrs_commit_all(player->attrs)) { + LOGE("failed to commit."); goto EXIT; } } @@ -12679,7 +8172,7 @@ __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* fi charset = util_get_charset(filepath); if (charset) { - LOGD("detected charset is %s\n", charset); + LOGD("detected charset is %s", charset); g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL); } @@ -12691,10 +8184,11 @@ EXIT: } /* API to switch between external subtitles */ -int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath) +int +_mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath) { int result = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*)hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; char *path = NULL; MMPLAYER_FENTER(); @@ -12719,7 +8213,7 @@ int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filep if (!player->pipeline) { /* IDLE state */ mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); - if (mmf_attrs_commit(player->attrs)) { + if (mm_attrs_commit_all(player->attrs)) { LOGE("failed to commit"); /* subtitle path will not be created */ return MM_ERROR_PLAYER_INTERNAL; } @@ -12730,7 +8224,7 @@ int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filep if (!__mmplayer_check_subtitle(player)) { mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); - if (mmf_attrs_commit(player->attrs)) { + if (mm_attrs_commit_all(player->attrs)) { LOGE("failed to commit"); return MM_ERROR_PLAYER_INTERNAL; } @@ -12762,14 +8256,14 @@ int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filep } static int -__mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index) +__mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index) { int result = MM_ERROR_NONE; - gchar* change_pad_name = NULL; - GstPad* sinkpad = NULL; - MMPlayerGstElement* mainbin = NULL; - enum MainElementID elemId = MMPLAYER_M_NUM; - GstCaps* caps = NULL; + gchar *change_pad_name = NULL; + GstPad *sinkpad = NULL; + mmplayer_gst_element_t *mainbin = NULL; + main_element_id_e elem_idx = MMPLAYER_M_NUM; + GstCaps *caps = NULL; gint total_track_num = 0; MMPLAYER_FENTER(); @@ -12777,36 +8271,36 @@ __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); - LOGD("Change Track(%d) to %d\n", type, index); + LOGD("Change Track(%d) to %d", type, index); mainbin = player->pipeline->mainbin; if (type == MM_PLAYER_TRACK_TYPE_AUDIO) { - elemId = MMPLAYER_M_A_INPUT_SELECTOR; + elem_idx = MMPLAYER_M_A_INPUT_SELECTOR; } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) { - elemId = MMPLAYER_M_T_INPUT_SELECTOR; + elem_idx = MMPLAYER_M_T_INPUT_SELECTOR; } else { /* Changing Video Track is not supported. */ - LOGE("Track Type Error\n"); + LOGE("Track Type Error"); goto EXIT; } - if (mainbin[elemId].gst == NULL) { + if (mainbin[elem_idx].gst == NULL) { result = MM_ERROR_PLAYER_NO_OP; - LOGD("Req track doesn't exist\n"); + LOGD("Req track doesn't exist"); goto EXIT; } total_track_num = player->selector[type].total_track_num; if (total_track_num <= 0) { result = MM_ERROR_PLAYER_NO_OP; - LOGD("Language list is not available \n"); + LOGD("Language list is not available"); goto EXIT; } if ((index < 0) || (index >= total_track_num)) { result = MM_ERROR_INVALID_ARGUMENT; - LOGD("Not a proper index : %d \n", index); + LOGD("Not a proper index : %d", index); goto EXIT; } @@ -12814,21 +8308,21 @@ __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int change_pad_name = g_strdup_printf("sink_%u", index); if (change_pad_name == NULL) { result = MM_ERROR_PLAYER_INTERNAL; - LOGD("Pad does not exists\n"); + LOGD("Pad does not exists"); goto EXIT; } - LOGD("new active pad name: %s\n", change_pad_name); + LOGD("new active pad name: %s", change_pad_name); - sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name); + sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name); if (sinkpad == NULL) { LOGD("sinkpad is NULL"); result = MM_ERROR_PLAYER_INTERNAL; goto EXIT; } - LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad)); - g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL); + LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad)); + g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL); caps = gst_pad_get_current_caps(sinkpad); MMPLAYER_LOG_GST_CAPS_TYPE(caps); @@ -12840,973 +8334,1203 @@ __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int __mmplayer_set_audio_attrs(player, caps); EXIT: - MMPLAYER_FREEIF(change_pad_name); return result; } -int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index) +int +_mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index) { int result = MM_ERROR_NONE; - mm_player_t* player = NULL; - MMPlayerGstElement* mainbin = NULL; + mmplayer_t *player = NULL; + mmplayer_gst_element_t *mainbin = NULL; gint current_active_index = 0; GstState current_state = GST_STATE_VOID_PENDING; - GstEvent* event = NULL; + GstEvent *event = NULL; gint64 time = 0; MMPLAYER_FENTER(); - player = (mm_player_t*)hplayer; + player = (mmplayer_t *)hplayer; MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); if (!player->pipeline) { - LOGE("Track %d pre setting -> %d\n", type, index); + LOGE("Track %d pre setting -> %d", type, index); + + player->selector[type].active_pad_index = index; + goto EXIT; + } + + mainbin = player->pipeline->mainbin; + + current_active_index = player->selector[type].active_pad_index; + + /*If index is same as running index no need to change the pad*/ + if (current_active_index == index) + goto EXIT; + + if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) { + result = MM_ERROR_PLAYER_INVALID_STATE; + goto EXIT; + } + + 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"); + goto EXIT; + } + + result = __mmplayer_change_selector_pad(player, type, index); + if (result != MM_ERROR_NONE) { + LOGE("change selector pad error"); + goto EXIT; + } + + player->selector[type].active_pad_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; + } + } + +EXIT: + return result; +} + +int +_mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent) +{ + mmplayer_t *player = (mmplayer_t *)hplayer; + + MMPLAYER_FENTER(); + + /* check player handle */ + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + *silent = player->set_mode.subtitle_off; + + LOGD("subtitle is %s.", silent ? "ON" : "OFF"); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +static gboolean +__mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element) +{ + MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); + MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE); + + gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element)); + gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2]; + + int idx = 0; + + for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) { + if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) { + LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]); + mmplayer_dump_t *dump_s; + dump_s = g_try_malloc(sizeof(mmplayer_dump_t)); + if (dump_s == NULL) { + LOGE("malloc fail"); + return FALSE; + } + + dump_s->dump_element_file = NULL; + dump_s->dump_pad = NULL; + dump_s->dump_pad = gst_element_get_static_pad(element, "sink"); + + if (dump_s->dump_pad) { + memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2); + snprintf(dump_file_name, PLAYER_INI_MAX_STRLEN * 2, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]); + dump_s->dump_element_file = fopen(dump_file_name, "w+"); + dump_s->probe_handle_id = gst_pad_add_probe(dump_s->dump_pad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_dump_buffer_probe_cb, dump_s->dump_element_file, NULL); + /* add list for removed buffer probe and close FILE */ + player->dump_list = g_list_append(player->dump_list, dump_s); + LOGD("%s sink pad added buffer probe for dump", factory_name); + return TRUE; + } else { + MMPLAYER_FREEIF(dump_s); + LOGE("failed to get %s sink pad added", factory_name); + } + } + } + return FALSE; +} + +static GstPadProbeReturn +__mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) +{ + FILE *dump_data = (FILE *)u_data; +// int written = 0; + GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); + GstMapInfo probe_info = GST_MAP_INFO_INIT; - player->selector[type].active_pad_index = index; - goto EXIT; - } + MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS); - mainbin = player->pipeline->mainbin; + gst_buffer_map(buffer, &probe_info, GST_MAP_READ); - current_active_index = player->selector[type].active_pad_index; +// LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); - /*If index is same as running index no need to change the pad*/ - if (current_active_index == index) - goto EXIT; + fwrite(probe_info.data, 1, probe_info.size , dump_data); - if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) { - result = MM_ERROR_PLAYER_INVALID_STATE; - goto EXIT; - } + gst_buffer_unmap(buffer, &probe_info); - 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\n"); - goto EXIT; - } + return GST_PAD_PROBE_OK; +} - result = __mmplayer_change_selector_pad(player, type, index); - if (result != MM_ERROR_NONE) { - LOGE("change selector pad error\n"); - goto EXIT; - } +static void +__mmplayer_release_dump_list(GList *dump_list) +{ + GList *d_list = dump_list; - player->selector[type].active_pad_index = index; + if (!d_list) + return; - 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) { - __gst_send_event_to_sink(player, event); - } else { - result = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; + for (; d_list; d_list = g_list_next(d_list)) { + mmplayer_dump_t *dump_s = d_list->data; + if (dump_s->dump_pad) { + if (dump_s->probe_handle_id) + gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id); + gst_object_unref(GST_OBJECT(dump_s->dump_pad)); + } + if (dump_s->dump_element_file) { + fclose(dump_s->dump_element_file); + dump_s->dump_element_file = NULL; } + MMPLAYER_FREEIF(dump_s); } - -EXIT: - return result; + g_list_free(dump_list); + dump_list = NULL; } -int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent) +int +_mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist) { - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; MMPLAYER_FENTER(); - /* check player handle */ MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT); - *silent = player->set_mode.subtitle_off; - - LOGD("subtitle is %s.\n", silent ? "ON" : "OFF"); + *exist = (bool)player->has_closed_caption; MMPLAYER_FLEAVE(); return MM_ERROR_NONE; } -gboolean -__is_ms_buff_src(mm_player_t* player) -{ - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - - return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE; -} - -gboolean -__has_suffix(mm_player_t* player, const gchar* suffix) +void +_mm_player_video_stream_internal_buffer_unref(void *buffer) { - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE); - - gboolean ret = FALSE; - gchar* t_url = g_ascii_strdown(player->profile.uri, -1); - gchar* t_suffix = g_ascii_strdown(suffix, -1); - - if (g_str_has_suffix(player->profile.uri, suffix)) - ret = TRUE; - - MMPLAYER_FREEIF(t_url); - MMPLAYER_FREEIF(t_suffix); - - return ret; + MMPLAYER_FENTER(); + if (buffer) { + // LOGD("unref internal gst buffer %p", buffer); + gst_buffer_unref((GstBuffer *)buffer); + buffer = NULL; + } + MMPLAYER_FLEAVE(); } int -_mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode) +_mmplayer_get_timeout(MMHandleType hplayer, int *timeout) { - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; + + MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT); - if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) { - MMPLAYER_PRINT_STATE(player); - LOGE("wrong-state : can't set the download mode to parse"); - return MM_ERROR_PLAYER_INVALID_STATE; - } + if (MMPLAYER_IS_STREAMING(player)) + *timeout = (int)player->ini.live_state_change_timeout; + else + *timeout = (int)player->ini.localplayback_state_change_timeout; - LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF"); - player->video_hub_download_mode = mode; + LOGD("timeout = %d", *timeout); + MMPLAYER_FLEAVE(); return MM_ERROR_NONE; } int -_mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable) +_mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num) { - mm_player_t* player = (mm_player_t*) hplayer; + 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); - LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF"); - player->sync_handler = enable; + *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; } -int -_mmplayer_set_video_share_master_clock(MMHandleType hplayer, - long long clock, - long long clock_delta, - long long video_time, - long long media_clock, - long long audio_time) -{ - mm_player_t* player = (mm_player_t*) hplayer; - MMPlayerGstElement* mainbin = NULL; - GstClockTime start_time_audio = 0, start_time_video = 0; - GstClockTimeDiff base_time = 0, new_base_time = 0; - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - gint64 api_delta = 0; - gint64 position = 0, position_delta = 0; - gint64 adj_base_time = 0; - GstClock *curr_clock = NULL; - GstClockTime curr_time = 0; - gboolean query_ret = TRUE; - int result = MM_ERROR_NONE; - +static void +__mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type) +{ + int i = 0; MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player); - MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED); + for (i = 0; i < MMPLAYER_PATH_MAX; i++) { - // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time); + if (path_type == MMPLAYER_PATH_MAX || path_type == i) { + player->storage_info[i].type = STORAGE_TYPE_INTERNAL; + player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE; + player->storage_info[i].id = -1; + memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN); - if ((video_time < 0) || (player->doing_seek)) { - LOGD("skip setting master clock. %lld", video_time); - goto EXIT; + if (path_type != MMPLAYER_PATH_MAX) + break; + } } - mainbin = player->pipeline->mainbin; - - curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst)); - curr_time = gst_clock_get_time(curr_clock); - - current_state = MMPLAYER_CURRENT_STATE(player); - - if (current_state == MM_PLAYER_STATE_PLAYING) - query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position); + MMPLAYER_FLEAVE(); +} - if ((current_state != MM_PLAYER_STATE_PLAYING) || - (!query_ret)) { - position = player->last_position; - LOGD("query fail. %lld", position); - } +int +_mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state) +{ + int ret = MM_ERROR_NONE; + mmplayer_t *player = (mmplayer_t *)hplayer; + MMMessageParamType msg_param = {0, }; - clock *= GST_USECOND; - clock_delta *= GST_USECOND; + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - api_delta = clock - curr_time; - if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta)) - player->video_share_api_delta = api_delta; - else - clock_delta += (api_delta - player->video_share_api_delta); + LOGW("state changed storage %d:%d", id, state); - if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) { - player->video_share_clock_delta = (gint64)clock_delta; + if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED) + return MM_ERROR_NONE; - position_delta = (position/GST_USECOND) - video_time; - position_delta *= GST_USECOND; + /* FIXME: text path should be handled seperately. */ + 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) + && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) { + LOGW("external storage is removed"); - adj_base_time = position_delta; - LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time); + if (player->msg_posted == FALSE) { + memset(&msg_param, 0, sizeof(MMMessageParamType)); + msg_param.code = MM_ERROR_PLAYER_INVALID_URI; + MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); + player->msg_posted = TRUE; + } - } else { - gint64 new_play_time = 0; - gint64 network_delay = 0; + /* unrealize the player */ + ret = _mmplayer_unrealize(hplayer); + if (ret != MM_ERROR_NONE) + LOGE("failed to unrealize"); + } - video_time *= GST_USECOND; + MMPLAYER_FLEAVE(); + return ret; +} - network_delay = clock_delta - player->video_share_clock_delta; - new_play_time = video_time + network_delay; +int +_mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info) +{ + int ret = MM_ERROR_NONE; + mmplayer_t *player = (mmplayer_t *)hplayer; + int idx = 0, total = 0; + gchar *result = NULL, *tmp = NULL; - adj_base_time = position - new_play_time; + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT); - LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)", - network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay); + total = *num = g_list_length(player->adaptive_info.var_list); + if (total <= 0) { + LOGW("There is no stream variant info."); + return ret; } - /* Adjust Current Stream Time with base_time of sink - * 1. Set Start time to CLOCK NONE, to control the base time by MSL - * 2. Set new base time - * if adj_base_time is positive value, the stream time will be decreased. - * 3. If seek event is occurred, the start time will be reset. */ - if ((player->pipeline->audiobin) && - (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) { - start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst); - - if (start_time_audio != GST_CLOCK_TIME_NONE) { - LOGD("audio sink : gst_element_set_start_time -> NONE"); - gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE); - } - - base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst); - } + result = g_strdup(""); + for (idx = 0 ; idx < total ; idx++) { + stream_variant_t *v_data = NULL; + v_data = g_list_nth_data(player->adaptive_info.var_list, idx); - if ((player->pipeline->videobin) && - (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) { - start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst); + if (v_data) { + gchar data[64] = {0}; + snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height); - if (start_time_video != GST_CLOCK_TIME_NONE) { - LOGD("video sink : gst_element_set_start_time -> NONE"); - gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE); + tmp = g_strconcat(result, data, NULL); + g_free(result); + result = tmp; + } else { + LOGW("There is no variant data in %d", idx); + (*num)--; } - - // if videobin exist, get base_time from videobin. - base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst); } - new_base_time = base_time + adj_base_time; - - if ((player->pipeline->audiobin) && - (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) - gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time); - - if ((player->pipeline->videobin) && - (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) - gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time); + *var_info = (char *)result; -EXIT: + LOGD("variant info %d:%s", *num, *var_info); MMPLAYER_FLEAVE(); - - return result; + return ret; } int -_mmplayer_get_video_share_master_clock(MMHandleType hplayer, - long long *video_time, - long long *media_clock, - long long *audio_time) +_mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height) { - mm_player_t* player = (mm_player_t*) hplayer; - MMPlayerGstElement* mainbin = NULL; - GstClock *curr_clock = NULL; - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - gint64 position = 0; - gboolean query_ret = TRUE; + 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(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED); + LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height); - MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT); - MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT); - MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT); + player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE); + player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE); + player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE); - mainbin = player->pipeline->mainbin; + if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) { + LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst)); + g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst, + "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL); - curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst)); + /* FIXME: seek to current position for applying new variant limitation */ + } - current_state = MMPLAYER_CURRENT_STATE(player); + MMPLAYER_FLEAVE(); + return ret; - if (current_state != MM_PLAYER_STATE_PAUSED) - query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position); +} - if ((current_state == MM_PLAYER_STATE_PAUSED) || - (!query_ret)) - position = player->last_position; +int +_mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height) +{ + int ret = MM_ERROR_NONE; + mmplayer_t *player = (mmplayer_t *)hplayer; - *media_clock = *video_time = *audio_time = (position/GST_USECOND); + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT); - LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time); + *bandwidth = player->adaptive_info.limit.bandwidth; + *width = player->adaptive_info.limit.width; + *height = player->adaptive_info.limit.height; - if (curr_clock) - gst_object_unref(curr_clock); + LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height); MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; + return ret; } -static gboolean -__mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element) +int +_mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms) { - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE); - - gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element)); - gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2]; - - int idx = 0; - - for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) { - if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) { - LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]); - mm_player_dump_t *dump_s; - dump_s = g_malloc(sizeof(mm_player_dump_t)); + int ret = MM_ERROR_NONE; + mmplayer_t *player = (mmplayer_t *)hplayer; - if (dump_s == NULL) { - LOGE("malloc fail"); - return FALSE; - } + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT); + MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP); - dump_s->dump_element_file = NULL; - dump_s->dump_pad = NULL; - dump_s->dump_pad = gst_element_get_static_pad(element, "sink"); + *prebuffer_ms = player->streamer->buffering_req.prebuffer_time; - if (dump_s->dump_pad) { - memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2); - snprintf(dump_file_name, PLAYER_INI_MAX_STRLEN*2, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]); - dump_s->dump_element_file = fopen(dump_file_name, "w+"); - dump_s->probe_handle_id = gst_pad_add_probe(dump_s->dump_pad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_dump_buffer_probe_cb, dump_s->dump_element_file, NULL); - /* add list for removed buffer probe and close FILE */ - player->dump_list = g_list_append(player->dump_list, dump_s); - LOGD("%s sink pad added buffer probe for dump", factory_name); - return TRUE; - } else { - g_free(dump_s); - dump_s = NULL; - LOGE("failed to get %s sink pad added", factory_name); - } + if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME) + *rebuffer_ms = player->streamer->buffering_req.rebuffer_time; + else /* live case */ + *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME; + LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms); - } - } - return FALSE; + MMPLAYER_FLEAVE(); + return ret; } -static GstPadProbeReturn -__mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) +int +_mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type) { - FILE *dump_data = (FILE *) u_data; -// int written = 0; - GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); - GstMapInfo probe_info = GST_MAP_INFO_INIT; +#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; - MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE); + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - gst_buffer_map(buffer, &probe_info, GST_MAP_READ); + 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("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); + 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; + 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; + default: + LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type)); + return MM_ERROR_COMMON_INVALID_ARGUMENT; + break; + } - fwrite(probe_info.data, 1, probe_info.size , dump_data); + LOGD("update %s codec_type to %d", attr_name, codec_type); - return GST_PAD_PROBE_OK; -} + attrs = MMPLAYER_GET_ATTRS(player); + mm_attrs_set_int_by_name(attrs, attr_name, codec_type); -static void -__mmplayer_release_dump_list(GList *dump_list) -{ - if (dump_list) { - GList *d_list = dump_list; - for (; d_list; d_list = g_list_next(d_list)) { - mm_player_dump_t *dump_s = d_list->data; - if (dump_s->dump_pad) { - if (dump_s->probe_handle_id) - gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id); - } - if (dump_s->dump_element_file) { - fclose(dump_s->dump_element_file); - dump_s->dump_element_file = NULL; - } - MMPLAYER_FREEIF(dump_s); - } - g_list_free(dump_list); - dump_list = NULL; + if (mm_attrs_commit_all(player->attrs)) { + LOGE("failed to commit codec_type attributes"); + return MM_ERROR_PLAYER_INTERNAL; } + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; } int -_mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist) +_mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled) { - mm_player_t* player = (mm_player_t*) hplayer; + mmplayer_t *player = (mmplayer_t *)hplayer; + GstElement *rg_vol_element = NULL; MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT); - *exist = player->has_closed_caption; + player->sound.rg_enable = enabled; + + /* just hold rgvolume enable value if pipeline is not ready */ + if (!player->pipeline || !player->pipeline->audiobin) { + LOGD("pipeline is not ready. holding rgvolume enable value"); + return MM_ERROR_NONE; + } + + rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst; + + if (!rg_vol_element) { + LOGD("rgvolume element is not created"); + return MM_ERROR_PLAYER_INTERNAL; + } + + if (enabled) + g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL); + else + g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL); MMPLAYER_FLEAVE(); return MM_ERROR_NONE; } -void _mm_player_video_stream_internal_buffer_unref(void *buffer) +int +_mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled) { + mmplayer_t *player = (mmplayer_t *)hplayer; + GstElement *rg_vol_element = NULL; + gboolean enable = FALSE; + MMPLAYER_FENTER(); - if (buffer) { - // LOGD("unref internal gst buffer %p", buffer); - gst_buffer_unref((GstBuffer *)buffer); - buffer = NULL; - } - MMPLAYER_FLEAVE(); -} -void -__gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO; - guint64 current_level_bytes = 0; + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT); - MMPLAYER_RETURN_IF_FAIL(player); + /* just hold enable_rg value if pipeline is not ready */ + if (!player->pipeline || !player->pipeline->audiobin) { + LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable); + *enabled = player->sound.rg_enable; + return MM_ERROR_NONE; + } - g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL); + rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst; - LOGI("app-src: feed audio(%llu)\n", current_level_bytes); - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); + if (!rg_vol_element) { + LOGD("rgvolume element is not created"); + return MM_ERROR_PLAYER_INTERNAL; + } - if (player->media_stream_buffer_status_cb[type]) - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]); - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); + g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL); + *enabled = (bool)enable; + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; } -void -__gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data) +int +_mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height) { - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO; - guint64 current_level_bytes = 0; - - MMPLAYER_RETURN_IF_FAIL(player); + mmplayer_t *player = (mmplayer_t *)hplayer; + MMHandleType attrs = 0; + void *handle = NULL; + int ret = MM_ERROR_NONE; - g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL); + MMPLAYER_FENTER(); - LOGI("app-src: feed video(%llu)\n", current_level_bytes); + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); - if (player->media_stream_buffer_status_cb[type]) - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]); - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); -} + attrs = MMPLAYER_GET_ATTRS(player); + MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL); -void -__gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT; - guint64 current_level_bytes = 0; + mm_attrs_get_data_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; + } - MMPLAYER_RETURN_IF_FAIL(player); + player->video_roi.scale_x = scale_x; + player->video_roi.scale_y = scale_y; + player->video_roi.scale_width = scale_width; + player->video_roi.scale_height = scale_height; - LOGI("app-src: feed subtitle\n"); + /* check video sinkbin is created */ + if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) + return MM_ERROR_NONE; - g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL); + if (!gst_video_overlay_set_video_roi_area( + GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst), + scale_x, scale_y, scale_width, scale_height)) + ret = MM_ERROR_PLAYER_INTERNAL; + else + LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)", + scale_x, scale_y, scale_width, scale_height); - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); - if (player->media_stream_buffer_status_cb[type]) - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]); + MMPLAYER_FLEAVE(); - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); + return ret; } -void -__gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data) +int +_mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height) { - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO; - guint64 current_level_bytes = 0; - - MMPLAYER_RETURN_IF_FAIL(player); + mmplayer_t *player = (mmplayer_t *)hplayer; + int ret = MM_ERROR_NONE; - LOGI("app-src: audio buffer is full.\n"); + MMPLAYER_FENTER(); - g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL); + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT); - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); + *scale_x = player->video_roi.scale_x; + *scale_y = player->video_roi.scale_y; + *scale_width = player->video_roi.scale_width; + *scale_height = player->video_roi.scale_height; - if (player->media_stream_buffer_status_cb[type]) - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]); + LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)", + *scale_x, *scale_y, *scale_width, *scale_height); - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); + return ret; } -void -__gst_appsrc_enough_video_data(GstElement *element, gpointer user_data) +static gboolean +__mmplayer_update_duration_value(mmplayer_t *player) { - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO; - guint64 current_level_bytes = 0; + gboolean ret = FALSE; + gint64 dur_nsec = 0; + LOGD("try to update duration"); - MMPLAYER_RETURN_IF_FAIL(player); + if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) { + player->duration = dur_nsec; + LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec)); + ret = TRUE; + } - LOGI("app-src: video buffer is full.\n"); + if (player->duration < 0) { + LOGW("duration is Non-Initialized !!!"); + player->duration = 0; + } - g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL); + /* update streaming service type */ + player->streaming_type = __mmplayer_get_stream_service_type(player); - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); - if (player->media_stream_buffer_status_cb[type]) - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]); + /* check duration is OK */ + if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) + /* FIXIT : find another way to get duration here. */ + LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!"); - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); + return ret; } -gboolean -__gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data) +static gboolean +__mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs) { - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO; + /* update audio params + NOTE : We need original audio params and it can be only obtained from src pad of audio + decoder. Below code only valid when we are not using 'resampler' just before + 'audioconverter'. */ + GstCaps *caps_a = NULL; + GstPad *pad = NULL; + gint samplerate = 0, channels = 0; + GstStructure *p = NULL; + GstElement *aconv = NULL; - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); + LOGD("try to update audio attrs"); - LOGD("app-src: seek audio data %llu\n", position); - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); + MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE); - if (player->media_stream_seek_data_cb[type]) - player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]); - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); + 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; + } - return TRUE; -} + pad = gst_element_get_static_pad(aconv, "sink"); -gboolean -__gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO; + if (!pad) { + LOGW("failed to get pad from audio converter"); + return FALSE; + } - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); + caps_a = gst_pad_get_current_caps(pad); + if (!caps_a) { + LOGW("not ready to get audio caps"); + gst_object_unref(pad); + return FALSE; + } - LOGD("app-src: seek video data %llu\n", position); - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); - if (player->media_stream_seek_data_cb[type]) - player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]); - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); + p = gst_caps_get_structure(caps_a, 0); - return TRUE; -} + mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate); -gboolean -__gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT; + gst_structure_get_int(p, "rate", &samplerate); + mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate); - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); + gst_structure_get_int(p, "channels", &channels); + mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels); - LOGD("app-src: seek subtitle data\n"); - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); + SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels); - if (player->media_stream_seek_data_cb[type]) - player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]); - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); + gst_caps_unref(caps_a); + gst_object_unref(pad); return TRUE; } -int -_mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel) +static gboolean +__mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs) { - mm_player_t* player = (mm_player_t*) hplayer; + LOGD("try to update video attrs"); - MMPLAYER_FENTER(); + GstCaps *caps_v = NULL; + GstPad *pad = NULL; + gint tmpNu, tmpDe; + gint width, height; + GstStructure *p = NULL; - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE); + MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE); - player->pcm_samplerate = samplerate; - player->pcm_channel = channel; + pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink"); + if (!pad) { + LOGD("no videosink sink pad"); + return FALSE; + } - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; -} + caps_v = gst_pad_get_current_caps(pad); + /* Use v_stream_caps, if fail to get video_sink sink pad*/ + if (!caps_v && player->v_stream_caps) { + caps_v = player->v_stream_caps; + gst_caps_ref(caps_v); + } -int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout) -{ - mm_player_t* player = (mm_player_t*) hplayer; + if (!caps_v) { + LOGD("no negitiated caps from videosink"); + gst_object_unref(pad); + return FALSE; + } - MMPLAYER_FENTER(); + 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); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT); + gst_structure_get_int(p, "height", &height); + mm_attrs_set_int_by_name(attrs, "content_video_height", height); - if (MMPLAYER_IS_STREAMING(player)) - *timeout = player->ini.live_state_change_timeout; - else - *timeout = player->ini.localplayback_state_change_timeout; + gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe); - LOGD("timeout = %d\n", *timeout); + SECURE_LOGD("width : %d height : %d", width, height); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; + gst_caps_unref(caps_v); + gst_object_unref(pad); + + if (tmpDe > 0) { + mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe); + SECURE_LOGD("fps : %d", tmpNu / tmpDe); + } + + return TRUE; } -int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num) +static gboolean +__mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs) { - mm_player_t* player = (mm_player_t*) hplayer; + gboolean ret = FALSE; + guint64 data_size = 0; + gchar *path = NULL; + struct stat sb; - MMPLAYER_FENTER(); + /* FIXIT : please make it clear the dependancy with duration/codec/uritype */ + if (!player->duration) + return FALSE; - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT); + if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) { + mm_attrs_get_string_by_name(attrs, "profile_uri", &path); + if (stat(path, &sb) == 0) + data_size = (guint64)sb.st_size; - *num = player->video_num_buffers; - *extra_num = player->video_extra_num_buffers; + } else if (MMPLAYER_IS_HTTP_STREAMING(player)) { + data_size = player->http_content_size; + } - LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num); + LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; + if (data_size) { + guint64 bitrate = 0; + guint64 msec_dur = 0; + + 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); + + ret = TRUE; + } else { + LOGD("player duration is less than 0"); + } + } + + if (MMPLAYER_IS_RTSP_STREAMING(player)) { + if (player->total_bitrate) { + mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate); + ret = TRUE; + } + } + + return ret; } static void -__mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type) +__mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type) { - int i = 0; - MMPLAYER_FENTER(); - MMPLAYER_RETURN_IF_FAIL(player); - - for (i = 0; i < MMPLAYER_PATH_MAX; i++) { - - if (path_type == MMPLAYER_PATH_MAX || path_type == i) { - player->storage_info[i].type = STORAGE_TYPE_INTERNAL; - player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE; - player->storage_info[i].id = -1; - memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN); + strncpy(data->uri, uri, MM_MAX_URL_LEN - 1); + data->uri_type = uri_type; +} - if (path_type != MMPLAYER_PATH_MAX) - break; +static int +__mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param) +{ + int ret = MM_ERROR_PLAYER_INVALID_URI; + int mem_size = 0; + char *buffer = NULL; + char *seperator = strchr(path, ','); + char ext[100] = {0,}, size[100] = {0,}; + + if (seperator) { + if ((buffer = strstr(path, "ext="))) { + buffer += strlen("ext="); + + if (strlen(buffer)) { + strncpy(ext, buffer, 99); + + if ((seperator = strchr(ext, ',')) + || (seperator = strchr(ext, ' ')) + || (seperator = strchr(ext, '\0'))) { + seperator[0] = '\0'; + } + } } - } - MMPLAYER_FLEAVE(); -} + if ((buffer = strstr(path, "size="))) { + buffer += strlen("size="); -int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state) -{ - int ret = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*)hplayer; - MMMessageParamType msg_param = {0, }; + if (strlen(buffer) > 0) { + strncpy(size, buffer, 99); - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + if ((seperator = strchr(size, ',')) + || (seperator = strchr(size, ' ')) + || (seperator = strchr(size, '\0'))) { + seperator[0] = '\0'; + } - LOGW("state changed storage %d:%d", id, state); + mem_size = atoi(size); + } + } + } - if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED) - return MM_ERROR_NONE; + LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param); - /* FIXME: text path should be handled seperately. */ - 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) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) { - LOGW("external storage is removed"); + if (mem_size && param) { + if (data->input_mem.buf) + free(data->input_mem.buf); + data->input_mem.buf = malloc(mem_size); - if (player->msg_posted == FALSE) { - memset(&msg_param, 0, sizeof(MMMessageParamType)); - msg_param.code = MM_ERROR_PLAYER_INVALID_URI; - MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); - player->msg_posted = TRUE; + if (data->input_mem.buf) { + memcpy(data->input_mem.buf, param, mem_size); + data->input_mem.len = mem_size; + ret = MM_ERROR_NONE; + } else { + LOGE("failed to alloc mem %d", mem_size); + ret = MM_ERROR_PLAYER_INTERNAL; } - /* unrealize the player */ - ret = _mmplayer_unrealize(hplayer); - if (ret != MM_ERROR_NONE) - LOGE("failed to unrealize"); + data->input_mem.offset = 0; + data->uri_type = MM_PLAYER_URI_TYPE_MEM; } - MMPLAYER_FLEAVE(); return ret; } -int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info) +static int +__mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri) { + gchar *location = NULL; + GError *err = NULL; + char *path = NULL; int ret = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; - int idx = 0, total = 0; - gchar *result = NULL, *tmp = NULL; - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT); + if ((path = strstr(uri, "file://"))) { + location = g_filename_from_uri(uri, NULL, &err); + if (!location || (err != NULL)) { + LOGE("Invalid URI '%s' for filesrc: %s", path, + (err != NULL) ? err->message : "unknown error"); + if (err) + g_error_free(err); - total = *num = g_list_length(player->adaptive_info.var_list); - if (total <= 0) { - LOGW("There is no stream variant info."); - return ret; + MMPLAYER_FREEIF(location); + + data->uri_type = MM_PLAYER_URI_TYPE_NONE; + return MM_ERROR_PLAYER_INVALID_URI; + } + LOGD("path from uri: %s", location); } - result = g_strdup(""); - for (idx = 0 ; idx < total ; idx++) { - VariantData *v_data = NULL; - v_data = g_list_nth_data(player->adaptive_info.var_list, idx); + path = (location != NULL) ? (location) : ((char *)uri); - if (v_data) { - gchar data[64] = {0}; - snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height); - tmp = g_strconcat(result, data, NULL); - g_free(result); - result = tmp; + ret = util_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)) { + LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc"); + data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; } else { - LOGW("There is no variant data in %d", idx); - (*num)--; + data->uri_type = MM_PLAYER_URI_TYPE_FILE; } + } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) { + data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION; + } else { + LOGE("invalid uri, could not play.."); + data->uri_type = MM_PLAYER_URI_TYPE_NONE; } - *var_info = (char *)result; + MMPLAYER_FREEIF(location); - LOGD("variant info %d:%s", *num, *var_info); - MMPLAYER_FLEAVE(); return ret; } -int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height) +static mmplayer_video_decoded_data_info_t * +__mmplayer_create_stream_from_pad(GstPad *pad) { - int ret = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; + GstCaps *caps = NULL; + GstStructure *structure = NULL; + unsigned int fourcc = 0; + const gchar *string_format = NULL; + mmplayer_video_decoded_data_info_t *stream = NULL; + gint width, height; + MMPixelFormatType format; + GstVideoInfo info; - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + caps = gst_pad_get_current_caps(pad); + if (!caps) { + LOGE("Caps is NULL."); + return NULL; + } - LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height); + /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */ + structure = gst_caps_get_structure(caps, 0); + gst_structure_get_int(structure, "width", &width); + gst_structure_get_int(structure, "height", &height); + string_format = gst_structure_get_string(structure, "format"); - player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE); - player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE); - player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE); + if (string_format) + fourcc = _mmplayer_convert_fourcc_string_to_value(string_format); + format = util_get_pixtype(fourcc); + gst_video_info_from_caps(&info, caps); + gst_caps_unref(caps); - if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) { - LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst)); - g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst, - "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL); + /* moved here */ + if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) { + LOGE("Wrong condition!!"); + return NULL; + } - /* FIXME: seek to current position for applying new variant limitation */ + stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t)); + if (!stream) { + LOGE("failed to alloc mem for video data"); + return NULL; } - MMPLAYER_FLEAVE(); - return ret; + stream->width = width; + stream->height = height; + stream->format = format; + stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info); + return stream; } -int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height) -{ - int ret = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT); - - *bandwidth = player->adaptive_info.limit.bandwidth; - *width = player->adaptive_info.limit.width; - *height = player->adaptive_info.limit.height; - - LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height); +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; + + for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) { + bo = gst_tizen_memory_get_bos(mem, index); + if (bo) + stream->bo[index] = tbm_bo_ref(bo); + else + LOGE("failed to get bo for index %d", index); + } - MMPLAYER_FLEAVE(); - return ret; + for (index = 0; index < stream->plane_num; index++) { + tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch); + stream->stride[index] = pitch; + if (pitch) + stream->elevation[index] = size / pitch; + else + stream->elevation[index] = stream->height; + } } -int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms) +static gboolean +__mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream) { - int ret = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) - LOGW("buffer_ms will not be applied."); + if (stream->format == MM_PIXEL_FORMAT_I420) { + int ret = TBM_SURFACE_ERROR_NONE; + tbm_surface_h surface; + tbm_surface_info_s info; + surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420); - LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms); + ret = tbm_surface_get_info(surface, &info); + if (ret != TBM_SURFACE_ERROR_NONE) { + tbm_surface_destroy(surface); + return FALSE; + } - if (player->streamer == NULL) { - player->streamer = __mm_player_streaming_create(); - __mm_player_streaming_initialize(player->streamer); + tbm_surface_destroy(surface); + stream->stride[0] = info.planes[0].stride; + stream->elevation[0] = info.planes[0].size / info.planes[0].stride; + stream->stride[1] = info.planes[1].stride; + stream->elevation[1] = info.planes[1].size / info.planes[1].stride; + stream->stride[2] = info.planes[2].stride; + stream->elevation[2] = info.planes[2].size / info.planes[2].stride; + stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size; + } else if (stream->format == MM_PIXEL_FORMAT_RGBA) { + stream->stride[0] = stream->width * 4; + stream->elevation[0] = stream->height; + stream->bo_size = stream->stride[0] * stream->height; + } else { + LOGE("Not support format %d", stream->format); + return FALSE; } - if (buffer_ms >= 0) - player->streamer->buffering_req.prebuffer_time = buffer_ms; - - if (rebuffer_ms >= 0) - player->streamer->buffering_req.rebuffer_time = rebuffer_ms; - - MMPLAYER_FLEAVE(); - return ret; - + return TRUE; } -int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms) +static gboolean +__mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem) { - int ret = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; + tbm_bo_handle thandle; + gboolean is_mapped; + int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, }; + int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, }; + int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, }; + int i = 0; + int j = 0; + int k = 0; + unsigned char *src = NULL; + unsigned char *dest = NULL; + GstMapInfo mapinfo = GST_MAP_INFO_INIT; - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT); + is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE); + if (!is_mapped) { + LOGE("fail to gst_memory_map"); + return FALSE; + } - if (player->streamer == NULL) { - player->streamer = __mm_player_streaming_create(); - __mm_player_streaming_initialize(player->streamer); + if (!mapinfo.data) { + LOGE("data pointer is wrong"); + goto ERROR; } - *buffer_ms = player->streamer->buffering_req.prebuffer_time; - *rebuffer_ms = player->streamer->buffering_req.rebuffer_time; + stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size); + if (!stream->bo[0]) { + LOGE("Fail to tbm_bo_alloc!!"); + goto ERROR; + } - LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms); + thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE); + if (!thandle.ptr) { + LOGE("thandle pointer is wrong"); + goto ERROR; + } - MMPLAYER_FLEAVE(); - return ret; -} + if (stream->format == MM_PIXEL_FORMAT_I420) { + src_stride[0] = GST_ROUND_UP_4(stream->width); + src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1); + src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height); + src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1)); -int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type) -{ -#define IDX_FIRST_SW_CODEC 0 - mm_player_t* player = (mm_player_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; + dest_offset[0] = 0; + dest_offset[1] = stream->stride[0] * stream->elevation[0]; + dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1]; - MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + for (i = 0; i < 3; i++) { + src = mapinfo.data + src_offset[i]; + dest = thandle.ptr + dest_offset[i]; - 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]); + if (i > 0) + k = 1; - switch (stream_type) { - case MM_PLAYER_STREAM_TYPE_AUDIO: - 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 a codec for codec_type %d", codec_type); - return MM_ERROR_PLAYER_NO_OP; - } - break; - case MM_PLAYER_STREAM_TYPE_VIDEO: - 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 v codec for codec_type %d", codec_type); - return MM_ERROR_PLAYER_NO_OP; + for (j = 0; j < stream->height >> k; j++) { + memcpy(dest, src, stream->width>>k); + src += src_stride[i]; + dest += stream->stride[i]; + } } - - break; - default: - LOGE("Invalid stream type %d", stream_type); - return MM_ERROR_COMMON_INVALID_ARGUMENT; - break; + } else if (stream->format == MM_PIXEL_FORMAT_RGBA) { + memcpy(thandle.ptr, mapinfo.data, stream->bo_size); + } else { + LOGE("Not support format %d", stream->format); + goto ERROR; } - LOGD("update %s codec_type to %d", attr_name, codec_type); + tbm_bo_unmap(stream->bo[0]); + gst_memory_unmap(mem, &mapinfo); - attrs = MMPLAYER_GET_ATTRS(player); - mm_attrs_set_int_by_name(attrs, attr_name, codec_type); + return TRUE; - if (mmf_attrs_commit(player->attrs)) { - LOGE("failed to commit codec_type attributes"); - return MM_ERROR_PLAYER_INTERNAL; - } +ERROR: + if (stream->bo[0]) + tbm_bo_unmap(stream->bo[0]); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; + if (is_mapped) + gst_memory_unmap(mem, &mapinfo); + + return FALSE; } -int -_mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled) +static void +__mmplayer_set_pause_state(mmplayer_t *player) { - mm_player_t* player = (mm_player_t*) hplayer; - GstElement* rg_vol_element = NULL; - - MMPLAYER_FENTER(); - - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + if (player->sent_bos) + return; - player->sound.rg_enable = enabled; + /* rtsp case, get content attrs by GstMessage */ + if (MMPLAYER_IS_RTSP_STREAMING(player)) + return; - /* just hold rgvolume enable value if pipeline is not ready */ - if (!player->pipeline || !player->pipeline->audiobin) { - LOGD("pipeline is not ready. holding rgvolume enable value\n"); - return MM_ERROR_NONE; - } + /* it's first time to update all content attrs. */ + __mmplayer_update_content_attrs(player, ATTR_ALL); +} - rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst; +static void +__mmplayer_set_playing_state(mmplayer_t *player) +{ + gchar *audio_codec = NULL; - if (!rg_vol_element) { - LOGD("rgvolume element is not created"); - return MM_ERROR_PLAYER_INTERNAL; + if (player->resumed_by_rewind && player->playback_rate < 0.0) { + /* initialize because auto resume is done well. */ + player->resumed_by_rewind = FALSE; + player->playback_rate = 1.0; } - if (enabled) - g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL); - else - g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL); + if (player->sent_bos) + return; - MMPLAYER_FLEAVE(); + /* try to get content metadata */ - return MM_ERROR_NONE; -} + /* 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 + * legacy mmfw-player api + */ + __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY); -int -_mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled) -{ - mm_player_t* player = (mm_player_t*) hplayer; - GstElement* rg_vol_element = NULL; - gboolean enable = FALSE; + if ((player->cmd == MMPLAYER_COMMAND_START) + || (player->cmd == MMPLAYER_COMMAND_RESUME)) { + __mmplayer_handle_missed_plugin(player); + } - MMPLAYER_FENTER(); + /* check audio codec field is set or not + * we can get it from typefinder or codec's caps. + */ + mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT); + /* The codec format can't be sent for audio only case like amr, mid etc. + * Because, parser don't make related TAG. + * So, if it's not set yet, fill it with found data. + */ + if (!audio_codec) { + if (g_strrstr(player->type, "audio/midi")) + audio_codec = "MIDI"; + else if (g_strrstr(player->type, "audio/x-amr")) + audio_codec = "AMR"; + else if (g_strrstr(player->type, "audio/mpeg") + && !g_strrstr(player->type, "mpegversion=(int)1")) + audio_codec = "AAC"; + else + audio_codec = "unknown"; - /* just hold enable_rg value if pipeline is not ready */ - if (!player->pipeline || !player->pipeline->audiobin) { - LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable); - *enabled = player->sound.rg_enable; - return MM_ERROR_NONE; - } + mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec); - rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst; + if (mm_attrs_commit_all(player->attrs)) + LOGE("failed to update attributes"); - if (!rg_vol_element) { - LOGD("rgvolume element is not created"); - return MM_ERROR_PLAYER_INTERNAL; + LOGD("set audio codec type with caps"); } - g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL); - *enabled = enable; - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; + return; }