4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
42 #include <mm_attrs_private.h>
44 #include <mm_sound_focus.h>
46 #include "mm_player_priv.h"
47 #include "mm_player_ini.h"
48 #include "mm_player_attrs.h"
49 #include "mm_player_capture.h"
50 #include "mm_player_utils.h"
51 #include "mm_player_tracks.h"
53 #include <system_info.h>
55 /*===========================================================================================
57 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
59 ========================================================================================== */
61 /*---------------------------------------------------------------------------
62 | GLOBAL CONSTANT DEFINITIONS: |
63 ---------------------------------------------------------------------------*/
65 /*---------------------------------------------------------------------------
66 | IMPORTED VARIABLE DECLARATIONS: |
67 ---------------------------------------------------------------------------*/
69 /*---------------------------------------------------------------------------
70 | IMPORTED FUNCTION DECLARATIONS: |
71 ---------------------------------------------------------------------------*/
73 /*---------------------------------------------------------------------------
75 ---------------------------------------------------------------------------*/
76 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
77 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
79 #define MM_VOLUME_FACTOR_DEFAULT 1.0
80 #define MM_VOLUME_FACTOR_MIN 0
81 #define MM_VOLUME_FACTOR_MAX 1.0
83 /* Don't need to sleep for sound fadeout
84 * fadeout related fucntion will be deleted(Deprecated)
86 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
88 #define MM_PLAYER_MPEG_VNAME "mpegversion"
89 #define MM_PLAYER_DIVX_VNAME "divxversion"
90 #define MM_PLAYER_WMV_VNAME "wmvversion"
91 #define MM_PLAYER_WMA_VNAME "wmaversion"
93 #define DEFAULT_PLAYBACK_RATE 1.0
94 #define PLAYBACK_RATE_EX_AUDIO_MIN 0.5
95 #define PLAYBACK_RATE_EX_AUDIO_MAX 2.0
96 #define PLAYBACK_RATE_EX_VIDEO_MIN 0.5
97 #define PLAYBACK_RATE_EX_VIDEO_MAX 1.5
98 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
100 #define GST_QUEUE_DEFAULT_TIME 4
101 #define GST_QUEUE_HLS_TIME 8
103 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
104 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
105 (player->ini.http_use_file_buffer) && \
106 (player->http_file_buffering_path) && \
107 (strlen(player->http_file_buffering_path) > 0))
108 #define MM_PLAYER_NAME "mmplayer"
110 #define PLAYER_DISPLAY_MODE_DST_ROI 5
112 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
114 /*---------------------------------------------------------------------------
115 | LOCAL CONSTANT DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
118 /*---------------------------------------------------------------------------
119 | LOCAL DATA TYPE DEFINITIONS: |
120 ---------------------------------------------------------------------------*/
122 /*---------------------------------------------------------------------------
123 | GLOBAL VARIABLE DEFINITIONS: |
124 ---------------------------------------------------------------------------*/
126 /*---------------------------------------------------------------------------
127 | LOCAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL FUNCTION PROTOTYPES: |
132 ---------------------------------------------------------------------------*/
133 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
134 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
135 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
136 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
137 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
138 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
139 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
141 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
142 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
143 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
144 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
145 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
146 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
147 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
148 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
152 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
153 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
155 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
156 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
157 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
158 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
159 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
160 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
161 //static void __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
163 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
164 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
165 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
167 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
168 //static void __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
169 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
170 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player);
171 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
174 static void __mmplayer_init_factories(mm_player_t* player);
175 static void __mmplayer_release_factories(mm_player_t* player);
176 static void __mmplayer_release_misc(mm_player_t* player);
177 static void __mmplayer_release_misc_post(mm_player_t* player);
178 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
179 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
180 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
182 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
183 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
185 int __mmplayer_switch_audio_sink(mm_player_t* player);
186 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
187 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
188 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
189 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
190 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
191 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
193 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
194 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
195 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
196 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
197 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
198 static gboolean __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad);
199 static gboolean __mmplayer_link_sink(mm_player_t* player, GstPad *srcpad);
200 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
201 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
202 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
203 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
204 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
205 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
206 static gpointer __mmplayer_next_play_thread(gpointer data);
207 static gpointer __mmplayer_repeat_thread(gpointer data);
208 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
211 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
212 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
213 static void __mmplayer_release_dump_list(GList *dump_list);
215 static int __gst_realize(mm_player_t* player);
216 static int __gst_unrealize(mm_player_t* player);
217 static int __gst_start(mm_player_t* player);
218 static int __gst_stop(mm_player_t* player);
219 static int __gst_pause(mm_player_t* player, gboolean async);
220 static int __gst_resume(mm_player_t* player, gboolean async);
221 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
222 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
223 gint64 cur, GstSeekType stop_type, gint64 stop);
224 static int __gst_pending_seek(mm_player_t* player);
226 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
227 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
228 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
229 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
230 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
232 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
234 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
235 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
238 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
239 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
241 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
242 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
245 static gboolean __is_ms_buff_src(mm_player_t* player);
246 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
248 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
249 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
250 static int __mmplayer_start_streaming_ext(mm_player_t *player);
251 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
252 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
254 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
255 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
256 static void __mmplayer_check_pipeline(mm_player_t* player);
257 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
258 static void __mmplayer_deactivate_old_path(mm_player_t *player);
259 #if 0 // We'll need this in future.
260 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
263 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
264 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
266 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
267 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
268 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
269 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
270 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
271 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
272 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
273 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
274 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
275 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
276 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
277 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
278 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
279 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
281 /*===========================================================================================
283 | FUNCTION DEFINITIONS |
285 ========================================================================================== */
289 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
293 count = gst_tag_list_get_tag_size(list, tag);
295 LOGD("count = %d", count);
297 for (i = 0; i < count; i++) {
300 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
301 if (!gst_tag_list_get_string_index(list, tag, i, &str))
302 g_assert_not_reached();
304 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
307 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
309 g_print(" : %s\n", str);
316 /* This function should be called after the pipeline goes PAUSED or higher
319 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
321 static gboolean has_duration = FALSE;
322 static gboolean has_video_attrs = FALSE;
323 static gboolean has_audio_attrs = FALSE;
324 static gboolean has_bitrate = FALSE;
325 gboolean missing_only = FALSE;
326 gboolean all = FALSE;
328 GstStructure* p = NULL;
329 MMHandleType attrs = 0;
331 gint stream_service_type = STREAMING_SERVICE_NONE;
336 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
338 /* check player state here */
339 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
340 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
341 /* give warning now only */
342 LOGW("be careful. content attributes may not available in this state ");
345 /* get content attribute first */
346 attrs = MMPLAYER_GET_ATTRS(player);
348 LOGE("cannot get content attribute");
352 /* get update flag */
354 if (flag & ATTR_MISSING_ONLY) {
356 LOGD("updating missed attr only");
359 if (flag & ATTR_ALL) {
361 has_duration = FALSE;
362 has_video_attrs = FALSE;
363 has_audio_attrs = FALSE;
366 LOGD("updating all attrs");
369 if (missing_only && all) {
370 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
371 missing_only = FALSE;
374 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
375 LOGD("try to update duration");
376 has_duration = FALSE;
378 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
379 player->duration = dur_nsec;
380 LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
383 if (player->duration < 0) {
384 LOGW("duration : %lld is Non-Initialized !!! \n",player->duration);
385 player->duration = 0;
388 /* try to get streaming service type */
389 stream_service_type = __mmplayer_get_stream_service_type(player);
390 mm_attrs_set_int_by_name(attrs, "streaming_type", stream_service_type);
392 /* check duration is OK */
393 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
394 /* FIXIT : find another way to get duration here. */
395 LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
398 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
403 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
404 /* update audio params
405 NOTE : We need original audio params and it can be only obtained from src pad of audio
406 decoder. Below code only valid when we are not using 'resampler' just before
409 LOGD("try to update audio attrs");
410 has_audio_attrs = FALSE;
412 if (player->pipeline->audiobin &&
413 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
414 GstCaps *caps_a = NULL;
416 gint samplerate = 0, channels = 0;
418 pad = gst_element_get_static_pad(
419 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
422 caps_a = gst_pad_get_current_caps(pad);
425 p = gst_caps_get_structure(caps_a, 0);
427 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
429 gst_structure_get_int(p, "rate", &samplerate);
430 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
432 gst_structure_get_int(p, "channels", &channels);
433 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
435 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
437 gst_caps_unref(caps_a);
440 has_audio_attrs = TRUE;
442 LOGW("not ready to get audio caps");
444 gst_object_unref(pad);
446 LOGW("failed to get pad from audiosink");
450 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
451 LOGD("try to update video attrs");
452 has_video_attrs = FALSE;
454 if (player->pipeline->videobin &&
455 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
456 GstCaps *caps_v = NULL;
461 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
463 caps_v = gst_pad_get_current_caps(pad);
465 /* Use v_stream_caps, if fail to get video_sink sink pad*/
466 if (!caps_v && player->v_stream_caps) {
467 caps_v = player->v_stream_caps;
468 gst_caps_ref(caps_v);
472 p = gst_caps_get_structure(caps_v, 0);
473 gst_structure_get_int(p, "width", &width);
474 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
476 gst_structure_get_int(p, "height", &height);
477 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
479 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
481 SECURE_LOGD("width : %d height : %d", width, height);
483 gst_caps_unref(caps_v);
487 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
488 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
491 has_video_attrs = TRUE;
493 LOGD("no negitiated caps from videosink");
494 gst_object_unref(pad);
497 LOGD("no videosink sink pad");
502 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
505 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
506 if (player->duration) {
507 guint64 data_size = 0;
509 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
510 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
512 if (stat(path, &sb) == 0)
513 data_size = (guint64)sb.st_size;
514 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
515 data_size = player->http_content_size;
516 LOGD("try to update bitrate : data_size = %lld", data_size);
520 guint64 msec_dur = 0;
522 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
523 bitrate = data_size * 8 * 1000 / msec_dur;
524 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
525 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
530 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
531 if (player->total_bitrate) {
532 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
540 if (mmf_attrs_commit(attrs)) {
541 LOGE("failed to update attributes\n");
550 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player)
552 gint streaming_type = STREAMING_SERVICE_NONE;
556 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
558 player->pipeline->mainbin &&
559 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
562 /* streaming service type if streaming */
563 if (!MMPLAYER_IS_STREAMING(player))
564 return STREAMING_SERVICE_NONE;
566 if (MMPLAYER_IS_HTTP_STREAMING(player))
567 streaming_type = (player->duration == 0) ?
568 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
570 switch (streaming_type) {
571 case STREAMING_SERVICE_LIVE:
572 LOGD("it's live streaming");
574 case STREAMING_SERVICE_VOD:
575 LOGD("it's vod streaming");
578 LOGE("should not get here");
581 player->streaming_type = streaming_type;
584 return streaming_type;
588 /* this function sets the player state and also report
589 * it to applicaton by calling callback function
592 __mmplayer_set_state(mm_player_t* player, int state)
594 MMMessageParamType msg = {0, };
595 int sound_result = MM_ERROR_NONE;
596 gboolean post_bos = FALSE;
597 gboolean interrupted_by_focus = FALSE;
598 gboolean interrupted_by_resource = FALSE;
600 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
602 if (MMPLAYER_CURRENT_STATE(player) == state) {
603 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
604 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
605 return MM_ERROR_NONE;
608 /* update player states */
609 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
610 MMPLAYER_CURRENT_STATE(player) = state;
612 /* FIXIT : it's better to do like below code
613 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player))
614 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
615 and add more code to handling PENDING_STATE.
617 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
618 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
621 MMPLAYER_PRINT_STATE(player);
623 /* do some FSM stuffs before posting new state to application */
624 interrupted_by_focus = player->sound_focus.by_asm_cb;
625 interrupted_by_resource = (player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY].by_rm_cb ||
626 player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER].by_rm_cb);
628 switch (MMPLAYER_CURRENT_STATE(player)) {
629 case MM_PLAYER_STATE_NULL:
630 case MM_PLAYER_STATE_READY:
632 if (player->cmd == MMPLAYER_COMMAND_STOP) {
633 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
634 if (sound_result != MM_ERROR_NONE) {
635 LOGE("failed to release sound focus\n");
636 return MM_ERROR_POLICY_INTERNAL;
642 case MM_PLAYER_STATE_PAUSED:
644 if (!player->sent_bos) {
646 #define MMPLAYER_MAX_SOUND_PRIORITY 3
648 /* rtsp case, get content attrs by GstMessage */
649 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
650 /* it's first time to update all content attrs. */
651 _mmplayer_update_content_attrs( player, ATTR_ALL );
654 /* set max sound priority to keep own sound and not to mute other's one */
655 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
657 mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
659 LOGD("set max audio priority");
660 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
666 /* add audio callback probe if condition is satisfied */
667 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
668 __mmplayer_configure_audio_callback(player);
669 /* FIXIT : handle return value */
671 if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) {
672 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
673 if (sound_result != MM_ERROR_NONE) {
674 LOGE("failed to release sound focus\n");
675 return MM_ERROR_POLICY_INTERNAL;
681 case MM_PLAYER_STATE_PLAYING:
683 /* try to get content metadata */
684 if (!player->sent_bos) {
685 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
686 * c-api since c-api doesn't use _start() anymore. It may not work propery with
687 * legacy mmfw-player api */
688 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
691 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
692 if (!player->sent_bos)
693 __mmplayer_handle_missed_plugin(player);
694 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
695 if (sound_result != MM_ERROR_NONE) {
696 // FIXME : need to check history
697 if (player->pipeline->videobin) {
698 MMMessageParamType msg = {0, };
700 LOGE("failed to go ahead because of video conflict\n");
702 msg.union_type = MM_MSG_UNION_CODE;
703 msg.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
704 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
706 _mmplayer_unrealize((MMHandleType)player);
708 LOGE("failed to play by sound focus error : 0x%X\n", sound_result);
709 _mmplayer_pause((MMHandleType)player);
712 return MM_ERROR_POLICY_INTERNAL;
716 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
717 /* initialize because auto resume is done well. */
718 player->resumed_by_rewind = FALSE;
719 player->playback_rate = 1.0;
722 if (!player->sent_bos) {
723 /* check audio codec field is set or not
724 * we can get it from typefinder or codec's caps.
726 gchar *audio_codec = NULL;
727 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
729 /* The codec format can't be sent for audio only case like amr, mid etc.
730 * Because, parser don't make related TAG.
731 * So, if it's not set yet, fill it with found data.
734 if (g_strrstr(player->type, "audio/midi"))
735 audio_codec = g_strdup("MIDI");
736 else if (g_strrstr(player->type, "audio/x-amr"))
737 audio_codec = g_strdup("AMR");
738 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
739 audio_codec = g_strdup("AAC");
741 audio_codec = g_strdup("unknown");
742 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
744 MMPLAYER_FREEIF(audio_codec);
745 mmf_attrs_commit(player->attrs);
746 LOGD("set audio codec type with caps\n");
754 case MM_PLAYER_STATE_NONE:
756 LOGW("invalid target state, there is nothing to do.\n");
761 /* post message to application */
762 if (MMPLAYER_TARGET_STATE(player) == state) {
763 /* fill the message with state of player */
764 msg.union_type = MM_MSG_UNION_STATE;
765 msg.state.previous = MMPLAYER_PREV_STATE(player);
766 msg.state.current = MMPLAYER_CURRENT_STATE(player);
768 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
770 /* state changed by focus or resource callback */
771 if (interrupted_by_focus || interrupted_by_resource) {
772 if (interrupted_by_focus)
773 msg.state.code = player->sound_focus.focus_changed_msg;
774 else if (interrupted_by_resource)
775 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
776 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
777 } else { /* state changed by usecase */
778 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
781 LOGD("intermediate state, do nothing.\n");
782 MMPLAYER_PRINT_STATE(player);
783 return MM_ERROR_NONE;
787 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
788 player->sent_bos = TRUE;
791 return MM_ERROR_NONE;
794 static gpointer __mmplayer_next_play_thread(gpointer data)
796 mm_player_t* player = (mm_player_t*) data;
797 MMPlayerGstElement *mainbin = NULL;
799 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
801 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
802 while (!player->next_play_thread_exit) {
803 LOGD("next play thread started. waiting for signal.\n");
804 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
806 LOGD("reconfigure pipeline for gapless play.\n");
808 if (player->next_play_thread_exit) {
809 if (player->gapless.reconfigure) {
810 player->gapless.reconfigure = false;
811 MMPLAYER_PLAYBACK_UNLOCK(player);
813 LOGD("exiting gapless play thread\n");
817 mainbin = player->pipeline->mainbin;
819 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
820 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
821 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
822 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
823 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
825 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
827 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
832 static gpointer __mmplayer_repeat_thread(gpointer data)
834 mm_player_t* player = (mm_player_t*) data;
835 gboolean ret_value = FALSE;
836 MMHandleType attrs = 0;
839 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
841 MMPLAYER_REPEAT_THREAD_LOCK(player);
842 while (!player->repeat_thread_exit) {
843 LOGD("repeat thread started. waiting for signal.\n");
844 MMPLAYER_REPEAT_THREAD_WAIT(player);
846 if (player->repeat_thread_exit) {
847 LOGD("exiting repeat thread\n");
853 MMPLAYER_CMD_LOCK(player);
855 attrs = MMPLAYER_GET_ATTRS(player);
857 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) {
858 LOGE("can not get play count\n");
859 MMPLAYER_CMD_UNLOCK(player);
863 if (player->section_repeat) {
864 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
866 if (player->playback_rate < 0.0) {
867 player->resumed_by_rewind = TRUE;
868 _mmplayer_set_mute((MMHandleType)player, 0);
869 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
872 ret_value = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
873 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
874 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
877 player->sent_bos = FALSE;
881 LOGE("failed to set position to zero for rewind\n");
882 MMPLAYER_CMD_UNLOCK(player);
886 /* decrease play count */
888 /* we successeded to rewind. update play count and then wait for next EOS */
891 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
893 /* commit attribute */
894 if (mmf_attrs_commit(attrs))
895 LOGE("failed to commit attribute\n");
899 MMPLAYER_CMD_UNLOCK(player);
902 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
907 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
909 MMHandleType attrs = 0;
910 guint64 data_size = 0;
912 unsigned long pos_msec = 0;
915 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
917 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
919 attrs = MMPLAYER_GET_ATTRS(player);
921 LOGE("fail to get attributes.\n");
925 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
926 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
928 if (stat(path, &sb) == 0)
929 data_size = (guint64)sb.st_size;
930 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
931 data_size = player->http_content_size;
933 __mm_player_streaming_buffering(player->streamer,
936 player->last_position,
939 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
945 __mmplayer_handle_buffering_message(mm_player_t* player)
947 int ret = MM_ERROR_NONE;
948 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
949 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
950 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
951 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
953 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
954 LOGW("do nothing for buffering msg\n");
955 ret = MM_ERROR_PLAYER_INVALID_STATE;
959 prev_state = MMPLAYER_PREV_STATE(player);
960 current_state = MMPLAYER_CURRENT_STATE(player);
961 target_state = MMPLAYER_TARGET_STATE(player);
962 pending_state = MMPLAYER_PENDING_STATE(player);
964 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
965 MMPLAYER_STATE_GET_NAME(prev_state),
966 MMPLAYER_STATE_GET_NAME(current_state),
967 MMPLAYER_STATE_GET_NAME(pending_state),
968 MMPLAYER_STATE_GET_NAME(target_state),
969 player->streamer->is_buffering);
971 if (!player->streamer->is_buffering) {
972 /* NOTE : if buffering has done, player has to go to target state. */
973 switch (target_state) {
974 case MM_PLAYER_STATE_PAUSED:
976 switch (pending_state) {
977 case MM_PLAYER_STATE_PLAYING:
978 __gst_pause(player, TRUE);
981 case MM_PLAYER_STATE_PAUSED:
982 LOGD("player is already going to paused state, there is nothing to do.\n");
985 case MM_PLAYER_STATE_NONE:
986 case MM_PLAYER_STATE_NULL:
987 case MM_PLAYER_STATE_READY:
989 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
995 case MM_PLAYER_STATE_PLAYING:
997 switch (pending_state) {
998 case MM_PLAYER_STATE_NONE:
1000 if (current_state != MM_PLAYER_STATE_PLAYING)
1001 __gst_resume(player, TRUE);
1005 case MM_PLAYER_STATE_PAUSED:
1006 /* NOTE: It should be worked as asynchronously.
1007 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1009 __gst_resume(player, TRUE);
1012 case MM_PLAYER_STATE_PLAYING:
1013 LOGD("player is already going to playing state, there is nothing to do.\n");
1016 case MM_PLAYER_STATE_NULL:
1017 case MM_PLAYER_STATE_READY:
1019 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1025 case MM_PLAYER_STATE_NULL:
1026 case MM_PLAYER_STATE_READY:
1027 case MM_PLAYER_STATE_NONE:
1029 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1033 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1034 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1036 switch (pending_state) {
1037 case MM_PLAYER_STATE_NONE:
1039 if (current_state != MM_PLAYER_STATE_PAUSED) {
1040 /* rtsp streaming pause makes rtsp server stop sending data. */
1041 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1042 LOGD("set pause state during buffering\n");
1043 __gst_pause( player, TRUE );
1049 case MM_PLAYER_STATE_PLAYING:
1050 /* rtsp streaming pause makes rtsp server stop sending data. */
1051 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1052 __gst_pause ( player, TRUE );
1056 case MM_PLAYER_STATE_PAUSED:
1059 case MM_PLAYER_STATE_NULL:
1060 case MM_PLAYER_STATE_READY:
1062 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1072 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1074 MMPlayerGstElement *textbin;
1077 MMPLAYER_RETURN_IF_FAIL(player &&
1079 player->pipeline->textbin);
1081 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1083 textbin = player->pipeline->textbin;
1086 LOGD("Drop subtitle text after getting EOS\n");
1088 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1089 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1091 player->is_subtitle_force_drop = TRUE;
1093 if (player->is_subtitle_force_drop == TRUE) {
1094 LOGD("Enable subtitle data path without drop\n");
1096 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1097 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1099 LOGD("non-connected with external display");
1101 player->is_subtitle_force_drop = FALSE;
1106 static VariantData *
1107 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1109 VariantData *var_info = NULL;
1110 g_return_val_if_fail (self != NULL, NULL);
1112 var_info = g_new0(VariantData, 1);
1113 if (!var_info) return NULL;
1114 var_info->bandwidth = self->bandwidth;
1115 var_info->width = self->width;
1116 var_info->height = self->height;
1121 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data)
1123 mm_player_t* player = (mm_player_t*) data;
1124 gboolean ret = TRUE;
1125 static gboolean async_done = FALSE;
1127 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1128 MMPLAYER_RETURN_VAL_IF_FAIL(msg && GST_IS_MESSAGE(msg), FALSE);
1130 switch (GST_MESSAGE_TYPE(msg)) {
1131 case GST_MESSAGE_UNKNOWN:
1132 LOGD("unknown message received\n");
1135 case GST_MESSAGE_EOS:
1137 MMHandleType attrs = 0;
1140 LOGD("GST_MESSAGE_EOS received\n");
1142 /* NOTE : EOS event is comming multiple time. watch out it */
1143 /* check state. we only process EOS when pipeline state goes to PLAYING */
1144 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1145 LOGD("EOS received on non-playing state. ignoring it\n");
1149 if (player->pipeline) {
1150 if (player->pipeline->textbin)
1151 __mmplayer_drop_subtitle(player, TRUE);
1153 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1156 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1158 LOGD("release audio callback\n");
1160 /* release audio callback */
1161 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1162 player->audio_cb_probe_id = 0;
1163 /* audio callback should be free because it can be called even though probe remove.*/
1164 player->audio_stream_cb = NULL;
1165 player->audio_stream_cb_user_param = NULL;
1169 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1170 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1172 /* rewind if repeat count is greater then zero */
1173 /* get play count */
1174 attrs = MMPLAYER_GET_ATTRS(player);
1177 gboolean smooth_repeat = FALSE;
1179 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1180 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1182 player->play_count = count;
1184 LOGD("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1186 if (count > 1 || count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1187 if (smooth_repeat) {
1188 LOGD("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1190 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
1196 if (player->section_repeat) {
1197 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1199 if (player->playback_rate < 0.0) {
1200 player->resumed_by_rewind = TRUE;
1201 _mmplayer_set_mute((MMHandleType)player, 0);
1202 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1205 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1208 player->sent_bos = FALSE;
1211 if (MM_ERROR_NONE != ret_value)
1212 LOGE("failed to set position to zero for rewind\n");
1214 /* not posting eos when repeating */
1220 if (player->pipeline)
1221 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1223 /* post eos message to application */
1224 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1226 /* reset last position */
1227 player->last_position = 0;
1231 case GST_MESSAGE_ERROR:
1233 GError *error = NULL;
1234 gchar* debug = NULL;
1236 /* generating debug info before returning error */
1237 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1239 /* get error code */
1240 gst_message_parse_error(msg, &error, &debug);
1242 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1243 /* Note : the streaming error from the streaming source is handled
1244 * using __mmplayer_handle_streaming_error.
1246 __mmplayer_handle_streaming_error(player, msg);
1248 /* dump state of all element */
1249 __mmplayer_dump_pipeline_state(player);
1251 /* traslate gst error code to msl error code. then post it
1252 * to application if needed
1254 __mmplayer_handle_gst_error(player, msg, error);
1257 LOGE("error debug : %s", debug);
1260 if (MMPLAYER_IS_HTTP_PD(player))
1261 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1263 MMPLAYER_FREEIF(debug);
1264 g_error_free(error);
1268 case GST_MESSAGE_WARNING:
1271 GError* error = NULL;
1273 gst_message_parse_warning(msg, &error, &debug);
1275 LOGD("warning : %s\n", error->message);
1276 LOGD("debug : %s\n", debug);
1278 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1280 MMPLAYER_FREEIF(debug);
1281 g_error_free(error);
1285 case GST_MESSAGE_TAG:
1287 LOGD("GST_MESSAGE_TAG\n");
1288 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1289 LOGW("failed to extract tags from gstmessage\n");
1293 case GST_MESSAGE_BUFFERING:
1295 MMMessageParamType msg_param = {0, };
1296 int bRet = MM_ERROR_NONE;
1298 if (!MMPLAYER_IS_STREAMING(player))
1301 /* ignore the prev buffering message */
1302 if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE)) {
1303 gint buffer_percent = 0;
1305 gst_message_parse_buffering(msg, &buffer_percent);
1307 if (buffer_percent == MAX_BUFFER_PERCENT) {
1308 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1309 player->streamer->is_buffering_done = FALSE;
1315 MMPLAYER_CMD_LOCK(player);
1316 __mmplayer_update_buffer_setting(player, msg);
1318 bRet = __mmplayer_handle_buffering_message(player);
1320 if (bRet == MM_ERROR_NONE) {
1321 msg_param.connection.buffering = player->streamer->buffering_percent;
1322 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1324 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1325 player->pending_resume &&
1326 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1328 player->is_external_subtitle_added_now = FALSE;
1329 player->pending_resume = FALSE;
1330 _mmplayer_resume((MMHandleType)player);
1333 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1334 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1336 if (player->doing_seek) {
1337 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1338 player->doing_seek = FALSE;
1339 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1340 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1345 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1346 if (!player->streamer) {
1347 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1348 MMPLAYER_CMD_UNLOCK(player);
1352 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1354 LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1355 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1357 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1358 msg_param.connection.buffering = player->streamer->buffering_percent;
1359 MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1361 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1364 msg_param.connection.buffering = player->streamer->buffering_percent;
1365 MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1368 MMPLAYER_CMD_UNLOCK(player);
1372 case GST_MESSAGE_STATE_CHANGED:
1374 MMPlayerGstElement *mainbin;
1375 const GValue *voldstate, *vnewstate, *vpending;
1376 GstState oldstate = GST_STATE_NULL;
1377 GstState newstate = GST_STATE_NULL;
1378 GstState pending = GST_STATE_NULL;
1380 if (!(player->pipeline && player->pipeline->mainbin)) {
1381 LOGE("player pipeline handle is null");
1385 mainbin = player->pipeline->mainbin;
1387 /* we only handle messages from pipeline */
1388 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1391 /* get state info from msg */
1392 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1393 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1394 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1396 if (!voldstate || !vnewstate) {
1397 LOGE("received msg has wrong format.");
1401 oldstate = (GstState)voldstate->data[0].v_int;
1402 newstate = (GstState)vnewstate->data[0].v_int;
1404 pending = (GstState)vpending->data[0].v_int;
1406 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1407 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1408 gst_element_state_get_name((GstState)oldstate),
1409 gst_element_state_get_name((GstState)newstate),
1410 gst_element_state_get_name((GstState)pending));
1412 if (newstate == GST_STATE_PLAYING) {
1413 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1415 int retVal = MM_ERROR_NONE;
1416 LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1418 retVal = __gst_set_position( player, player->pending_seek.format, player->pending_seek.pos, TRUE );
1420 if (MM_ERROR_NONE != retVal)
1421 LOGE("failed to seek pending postion. just keep staying current position.\n");
1423 player->pending_seek.is_pending = FALSE;
1427 if (oldstate == newstate) {
1428 LOGD("pipeline reports state transition to old state");
1433 case GST_STATE_VOID_PENDING:
1436 case GST_STATE_NULL:
1439 case GST_STATE_READY:
1442 case GST_STATE_PAUSED:
1444 gboolean prepare_async = FALSE;
1446 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1447 __mmplayer_configure_audio_callback(player);
1449 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1450 // managed prepare async case
1451 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1452 LOGD("checking prepare mode for async transition - %d", prepare_async);
1455 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1456 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1458 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1459 __mm_player_streaming_set_content_bitrate(player->streamer,
1460 player->total_maximum_bitrate, player->total_bitrate);
1465 case GST_STATE_PLAYING:
1467 if (MMPLAYER_IS_STREAMING(player)) {
1468 // managed prepare async case when buffering is completed
1469 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1470 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1471 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1472 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1474 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1476 LOGD("Current Buffering Percent = %d",player->streamer->buffering_percent);
1477 if (player->streamer->buffering_percent < 100) {
1479 MMMessageParamType msg_param = {0, };
1480 LOGW("Posting Buffering Completed Message to Application !!!");
1482 msg_param.connection.buffering = 100;
1483 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1488 if (player->gapless.stream_changed) {
1489 _mmplayer_update_content_attrs(player, ATTR_ALL);
1490 player->gapless.stream_changed = FALSE;
1493 if (player->doing_seek && async_done) {
1494 player->doing_seek = FALSE;
1496 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1507 case GST_MESSAGE_CLOCK_LOST:
1509 GstClock *clock = NULL;
1510 gboolean need_new_clock = FALSE;
1512 gst_message_parse_clock_lost(msg, &clock);
1513 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1515 if (!player->videodec_linked)
1516 need_new_clock = TRUE;
1517 else if (!player->ini.use_system_clock)
1518 need_new_clock = TRUE;
1520 if (need_new_clock) {
1521 LOGD("Provide clock is TRUE, do pause->resume\n");
1522 __gst_pause(player, FALSE);
1523 __gst_resume(player, FALSE);
1528 case GST_MESSAGE_NEW_CLOCK:
1530 GstClock *clock = NULL;
1531 gst_message_parse_new_clock(msg, &clock);
1532 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1536 case GST_MESSAGE_ELEMENT:
1538 const gchar *structure_name;
1539 gint count = 0, idx = 0;
1540 MMHandleType attrs = 0;
1542 attrs = MMPLAYER_GET_ATTRS(player);
1544 LOGE("cannot get content attribute");
1549 if (gst_message_get_structure(msg) == NULL)
1552 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1553 if (!structure_name)
1556 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1558 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1559 const GValue *var_info = NULL;
1561 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1562 if (var_info != NULL) {
1563 if (player->adaptive_info.var_list)
1564 g_list_free_full(player->adaptive_info.var_list, g_free);
1566 /* share addr or copy the list */
1567 player->adaptive_info.var_list =
1568 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1570 count = g_list_length(player->adaptive_info.var_list);
1572 VariantData *temp = NULL;
1574 /* print out for debug */
1575 LOGD("num of variant_info %d", count);
1576 for (idx = 0; idx < count; idx++) {
1577 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1579 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1585 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1586 gint num_buffers = 0;
1587 gint extra_num_buffers = 0;
1589 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1590 player->video_num_buffers = num_buffers;
1591 LOGD("video_num_buffers : %d", player->video_num_buffers);
1594 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1595 player->video_extra_num_buffers = extra_num_buffers;
1596 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1601 if (!strcmp(structure_name, "Language_list")) {
1602 const GValue *lang_list = NULL;
1603 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1604 if (lang_list != NULL) {
1605 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1607 LOGD("Total audio tracks(from parser) = %d \n", count);
1611 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1612 const GValue *lang_list = NULL;
1613 MMPlayerLangStruct *temp = NULL;
1615 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1616 if (lang_list != NULL) {
1617 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1619 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1620 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1621 if (mmf_attrs_commit(attrs))
1622 LOGE("failed to commit.\n");
1623 LOGD("Total subtitle tracks = %d \n", count);
1626 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1628 LOGD("value of lang_key is %s and lang_code is %s",
1629 temp->language_key, temp->language_code);
1635 /* custom message */
1636 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1637 MMMessageParamType msg_param = {0,};
1638 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1639 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1642 /* custom message for RTSP attribute :
1643 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1644 sdp which has contents info is received when rtsp connection is opened.
1645 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1646 if (!strcmp(structure_name, "rtspsrc_properties")) {
1648 gchar *audio_codec = NULL;
1649 gchar *video_codec = NULL;
1650 gchar *video_frame_size = NULL;
1652 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1653 LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1654 __mmplayer_get_stream_service_type(player);
1655 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1657 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1658 LOGD("rtsp_audio_codec : %s", audio_codec);
1660 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1662 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1663 LOGD("rtsp_video_codec : %s", video_codec);
1665 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1667 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1668 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1669 if (video_frame_size) {
1671 char *seperator = strchr(video_frame_size, '-');
1674 char video_width[10]={0,};
1675 int frame_size_len = strlen(video_frame_size);
1676 int separtor_len = strlen(seperator);
1678 strncpy(video_width,video_frame_size,(frame_size_len-separtor_len));
1679 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1682 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1686 if (mmf_attrs_commit(attrs))
1687 LOGE("failed to commit.\n");
1692 case GST_MESSAGE_DURATION_CHANGED:
1694 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1695 ret = __mmplayer_gst_handle_duration(player, msg);
1697 LOGW("failed to update duration");
1702 case GST_MESSAGE_ASYNC_START:
1703 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1706 case GST_MESSAGE_ASYNC_DONE:
1708 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1710 /* we only handle messages from pipeline */
1711 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1714 if (player->doing_seek) {
1715 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1716 player->doing_seek = FALSE;
1717 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1718 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1719 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1720 (player->streamer) &&
1721 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1722 (player->streamer->is_buffering == FALSE)) {
1723 GstQuery *query = NULL;
1724 gboolean busy = FALSE;
1727 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1728 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1729 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1730 gst_query_parse_buffering_percent(query, &busy, &percent);
1731 gst_query_unref(query);
1733 LOGD("buffered percent(%s): %d\n",
1734 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1737 if (percent >= 100) {
1738 player->streamer->is_buffering = FALSE;
1739 __mmplayer_handle_buffering_message(player);
1749 #if 0 /* delete unnecessary logs */
1750 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1751 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1752 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1753 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1754 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1755 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1756 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1757 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1758 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1759 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1760 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1761 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1762 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1763 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1764 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1771 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1772 * gst_element_post_message api takes ownership of the message.
1774 //gst_message_unref(msg);
1780 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1786 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1787 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1789 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1790 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1791 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1793 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1794 LOGD("data total size of http content: %lld", bytes);
1795 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1798 /* handling audio clip which has vbr. means duration is keep changing */
1799 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1808 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1811 /* macro for better code readability */
1812 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1813 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1814 if (string != NULL) {\
1815 SECURE_LOGD("update tag string : %s\n", string); \
1816 mm_attrs_set_string_by_name(attribute, playertag, string); \
1822 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1824 GstSample *sample = NULL;\
1825 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1826 GstMapInfo info = GST_MAP_INFO_INIT;\
1827 buffer = gst_sample_get_buffer(sample);\
1828 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1829 LOGD("failed to get image data from tag");\
1832 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1833 MMPLAYER_FREEIF(player->album_art);\
1834 player->album_art = (gchar *)g_malloc(info.size);\
1835 if (player->album_art) {\
1836 memcpy(player->album_art, info.data, info.size);\
1837 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1838 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1839 msg_param.data = (void *)player->album_art;\
1840 msg_param.size = info.size;\
1841 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1842 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1845 gst_buffer_unmap(buffer, &info);\
1849 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1850 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) {\
1852 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) {\
1853 if (player->updated_bitrate_count == 0) \
1854 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1855 if (player->updated_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1856 player->bitrate[player->updated_bitrate_count] = v_uint;\
1857 player->total_bitrate += player->bitrate[player->updated_bitrate_count]; \
1858 player->updated_bitrate_count++; \
1859 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1860 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1863 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) {\
1864 if (player->updated_maximum_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1865 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1866 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1867 player->updated_maximum_bitrate_count++; \
1868 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1869 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1872 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1877 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1878 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1879 if (date != NULL) {\
1880 string = g_strdup_printf("%d", g_date_get_year(date));\
1881 mm_attrs_set_string_by_name(attribute, playertag, string);\
1882 SECURE_LOGD("metainfo year : %s\n", string);\
1883 MMPLAYER_FREEIF(string);\
1888 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1889 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1890 if (datetime != NULL) {\
1891 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1892 mm_attrs_set_string_by_name(attribute, playertag, string);\
1893 SECURE_LOGD("metainfo year : %s\n", string);\
1894 MMPLAYER_FREEIF(string);\
1895 gst_date_time_unref(datetime);\
1899 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1900 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1902 /* FIXIT : don't know how to store date */\
1908 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1909 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1911 /* FIXIT : don't know how to store date */\
1917 /* function start */
1918 GstTagList* tag_list = NULL;
1920 MMHandleType attrs = 0;
1922 char *string = NULL;
1925 GstDateTime *datetime = NULL;
1927 GstBuffer *buffer = NULL;
1929 MMMessageParamType msg_param = {0, };
1931 /* currently not used. but those are needed for above macro */
1932 //guint64 v_uint64 = 0;
1933 //gdouble v_double = 0;
1935 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1937 attrs = MMPLAYER_GET_ATTRS(player);
1939 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1941 /* get tag list from gst message */
1942 gst_message_parse_tag(msg, &tag_list);
1944 /* store tags to player attributes */
1945 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1946 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1947 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1948 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1949 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1950 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1951 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1952 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1953 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1954 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1955 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1956 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1957 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1958 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1959 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1960 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1961 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1962 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1963 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1964 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1965 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1966 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1967 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1968 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1969 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1970 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1971 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1972 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1973 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1974 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1975 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1976 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1977 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1978 MMPLAYER_UPDATE_TAG_LOCK(player);
1979 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1980 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1981 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1982 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1983 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1984 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1985 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1986 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1987 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1988 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1989 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1990 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1991 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1992 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1993 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1995 if (mmf_attrs_commit(attrs))
1996 LOGE("failed to commit.\n");
1998 gst_tag_list_free(tag_list);
2004 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2006 mm_player_t* player = (mm_player_t*) data;
2010 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2011 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2012 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2013 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2015 * [1] audio and video will be dumped with filesink.
2016 * [2] autoplugging is done by just using pad caps.
2017 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2018 * and the video will be dumped via filesink.
2020 if (player->num_dynamic_pad == 0) {
2021 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2023 if (!__mmplayer_gst_remove_fakesink(player,
2024 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2025 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2026 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2027 * source element are not same. To overcome this situation, this function will called
2028 * several places and several times. Therefore, this is not an error case.
2033 /* create dot before error-return. for debugging */
2034 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2036 player->no_more_pad = TRUE;
2042 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2044 GstElement* parent = NULL;
2046 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2048 /* if we have no fakesink. this meas we are using decodebin which doesn'
2049 t need to add extra fakesink */
2050 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2053 MMPLAYER_FSINK_LOCK(player);
2058 /* get parent of fakesink */
2059 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2061 LOGD("fakesink already removed\n");
2065 gst_element_set_locked_state(fakesink->gst, TRUE);
2067 /* setting the state to NULL never returns async
2068 * so no need to wait for completion of state transiton
2070 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2071 LOGE("fakesink state change failure!\n");
2072 /* FIXIT : should I return here? or try to proceed to next? */
2075 /* remove fakesink from it's parent */
2076 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2077 LOGE("failed to remove fakesink\n");
2079 gst_object_unref(parent);
2084 gst_object_unref(parent);
2086 LOGD("state-holder removed\n");
2088 gst_element_set_locked_state(fakesink->gst, FALSE);
2090 MMPLAYER_FSINK_UNLOCK(player);
2095 gst_element_set_locked_state(fakesink->gst, FALSE);
2097 MMPLAYER_FSINK_UNLOCK(player);
2103 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2105 GstPad *sinkpad = NULL;
2106 GstCaps* caps = NULL;
2107 GstElement* new_element = NULL;
2108 GstStructure* str = NULL;
2109 const gchar* name = NULL;
2111 mm_player_t* player = (mm_player_t*) data;
2115 MMPLAYER_RETURN_IF_FAIL(element && pad);
2116 MMPLAYER_RETURN_IF_FAIL(player &&
2118 player->pipeline->mainbin);
2121 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2122 * num_dynamic_pad will decreased after creating a sinkbin.
2124 player->num_dynamic_pad++;
2125 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2127 caps = gst_pad_query_caps(pad, NULL);
2129 MMPLAYER_CHECK_NULL(caps);
2131 /* clear previous result*/
2132 player->have_dynamic_pad = FALSE;
2134 str = gst_caps_get_structure(caps, 0);
2137 LOGE("cannot get structure from caps.\n");
2141 name = gst_structure_get_name(str);
2143 LOGE("cannot get mimetype from structure.\n");
2147 if (strstr(name, "video")) {
2149 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2151 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2152 if (player->v_stream_caps) {
2153 gst_caps_unref(player->v_stream_caps);
2154 player->v_stream_caps = NULL;
2157 new_element = gst_element_factory_make("fakesink", NULL);
2158 player->num_dynamic_pad--;
2163 /* clear previous result*/
2164 player->have_dynamic_pad = FALSE;
2166 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2167 LOGE("failed to autoplug for caps");
2171 /* check if there's dynamic pad*/
2172 if (player->have_dynamic_pad) {
2173 LOGE("using pad caps assums there's no dynamic pad !\n");
2177 gst_caps_unref(caps);
2182 /* excute new_element if created*/
2184 LOGD("adding new element to pipeline\n");
2186 /* set state to READY before add to bin */
2187 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2189 /* add new element to the pipeline */
2190 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2191 LOGE("failed to add autoplug element to bin\n");
2195 /* get pad from element */
2196 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2198 LOGE("failed to get sinkpad from autoplug element\n");
2203 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2204 LOGE("failed to link autoplug element\n");
2208 gst_object_unref(sinkpad);
2211 /* run. setting PLAYING here since streamming source is live source */
2212 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2219 STATE_CHANGE_FAILED:
2221 /* FIXIT : take care if new_element has already added to pipeline */
2223 gst_object_unref(GST_OBJECT(new_element));
2226 gst_object_unref(GST_OBJECT(sinkpad));
2229 gst_object_unref(GST_OBJECT(caps));
2231 /* FIXIT : how to inform this error to MSL ????? */
2232 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2233 * then post an error to application
2239 /* FIXIT : check indent */
2242 __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2244 GstPad *sinkpad = NULL;
2245 GstCaps* caps = NULL;
2246 GstElement* new_element = NULL;
2247 enum MainElementID element_id = MMPLAYER_M_NUM;
2249 mm_player_t* player = (mm_player_t*) data;
2253 MMPLAYER_RETURN_IF_FAIL(element && pad);
2254 MMPLAYER_RETURN_IF_FAIL(player &&
2256 player->pipeline->mainbin);
2258 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2261 LOGD("using pad caps to autopluging instead of doing typefind\n");
2262 caps = gst_pad_query_caps(pad);
2263 MMPLAYER_CHECK_NULL(caps);
2264 /* clear previous result*/
2265 player->have_dynamic_pad = FALSE;
2266 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2268 LOGE("failed to create wfd rtp depay element\n");
2271 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2272 /* add new element to the pipeline */
2273 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2274 LOGD("failed to add autoplug element to bin\n");
2277 /* get pad from element */
2278 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2280 LOGD("failed to get sinkpad from autoplug element\n");
2284 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2285 LOGD("failed to link autoplug element\n");
2288 gst_object_unref(sinkpad);
2290 pad = gst_element_get_static_pad(GST_ELEMENT(new_element), "src");
2291 caps = gst_pad_query_caps(pad);
2292 MMPLAYER_CHECK_NULL(caps);
2293 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2294 /* create typefind */
2295 new_element = gst_element_factory_make("typefind", NULL);
2297 LOGD("failed to create typefind\n");
2301 MMPLAYER_SIGNAL_CONNECT(player,
2302 G_OBJECT(new_element),
2303 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2305 G_CALLBACK(__mmplayer_typefind_have_type),
2308 player->have_dynamic_pad = FALSE;
2311 /* excute new_element if created*/
2313 LOGD("adding new element to pipeline\n");
2315 /* set state to READY before add to bin */
2316 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2318 /* add new element to the pipeline */
2319 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2320 LOGD("failed to add autoplug element to bin\n");
2324 /* get pad from element */
2325 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2327 LOGD("failed to get sinkpad from autoplug element\n");
2332 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2333 LOGD("failed to link autoplug element\n");
2337 gst_object_unref(sinkpad);
2340 /* run. setting PLAYING here since streamming source is live source */
2341 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2344 /* store handle to futher manipulation */
2345 player->pipeline->mainbin[element_id].id = element_id;
2346 player->pipeline->mainbin[element_id].gst = new_element;
2352 STATE_CHANGE_FAILED:
2354 /* FIXIT : take care if new_element has already added to pipeline */
2356 gst_object_unref(GST_OBJECT(new_element));
2359 gst_object_unref(GST_OBJECT(sinkpad));
2362 gst_object_unref(GST_OBJECT(caps));
2364 /* FIXIT : how to inform this error to MSL ????? */
2365 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2366 * then post an error to application
2371 static GstPadProbeReturn
2372 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2374 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2375 return GST_PAD_PROBE_OK;
2378 static GstPadProbeReturn
2379 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2381 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2382 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2383 mm_player_t* player = (mm_player_t*)data;
2384 GstCaps* caps = NULL;
2385 GstStructure* str = NULL;
2386 const gchar* name = NULL;
2387 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2390 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2391 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2392 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2393 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2394 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2396 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2397 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2401 caps = gst_pad_query_caps(pad, NULL);
2403 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2407 str = gst_caps_get_structure(caps, 0);
2409 LOGE("failed to get structure from caps");
2413 name = gst_structure_get_name(str);
2415 LOGE("failed to get name from str");
2419 if (strstr(name, "audio")) {
2420 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2421 } else if (strstr(name, "video")) {
2422 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2424 /* text track is not supportable */
2425 LOGE("invalid name %s", name);
2429 switch (GST_EVENT_TYPE(event)) {
2432 /* in case of gapless, drop eos event not to send it to sink */
2433 if (player->gapless.reconfigure && !player->msg_posted) {
2434 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2435 ret = GST_PAD_PROBE_DROP;
2439 case GST_EVENT_STREAM_START:
2441 gint64 stop_running_time = 0;
2442 gint64 position_running_time = 0;
2443 gint64 position = 0;
2446 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2447 if ((player->gapless.update_segment[idx] == TRUE) ||
2448 !(player->selector[idx].event_probe_id)) {
2449 /* LOGW("[%d] skip", idx); */
2453 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2455 gst_segment_to_running_time(&player->gapless.segment[idx],
2456 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2457 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2459 gst_segment_to_running_time(&player->gapless.segment[idx],
2460 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2462 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2464 gst_segment_to_running_time(&player->gapless.segment[idx],
2465 GST_FORMAT_TIME, player->duration);
2468 position_running_time =
2469 gst_segment_to_running_time(&player->gapless.segment[idx],
2470 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2472 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2473 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2475 GST_TIME_ARGS(stop_running_time),
2476 GST_TIME_ARGS(position_running_time),
2477 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2478 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2480 position_running_time = MAX(position_running_time, stop_running_time);
2481 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2482 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2483 position_running_time = MAX(0, position_running_time);
2484 position = MAX(position, position_running_time);
2487 if (position != 0) {
2488 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2489 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2490 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2492 player->gapless.start_time[stream_type] += position;
2496 case GST_EVENT_FLUSH_STOP:
2498 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2499 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2500 player->gapless.start_time[stream_type] = 0;
2503 case GST_EVENT_SEGMENT:
2508 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2509 gst_event_copy_segment(event, &segment);
2511 if (segment.format == GST_FORMAT_TIME) {
2512 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2513 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2514 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2515 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2516 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2517 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2519 /* keep the all the segment ev to cover the seeking */
2520 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2521 player->gapless.update_segment[stream_type] = TRUE;
2523 if (!player->gapless.running)
2526 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2528 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2530 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2531 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2532 gst_event_unref(event);
2533 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2539 gdouble proportion = 0.0;
2540 GstClockTimeDiff diff = 0;
2541 GstClockTime timestamp = 0;
2542 gint64 running_time_diff = -1;
2543 GstQOSType type = 0;
2544 GstEvent *tmpev = NULL;
2546 running_time_diff = player->gapless.segment[stream_type].base;
2548 if (running_time_diff <= 0) /* don't need to adjust */
2551 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2552 gst_event_unref(event);
2554 if (timestamp < running_time_diff) {
2555 LOGW("QOS event from previous group");
2556 ret = GST_PAD_PROBE_DROP;
2560 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2561 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2562 stream_type, GST_TIME_ARGS(timestamp),
2563 GST_TIME_ARGS(running_time_diff),
2564 GST_TIME_ARGS(timestamp - running_time_diff));
2566 timestamp -= running_time_diff;
2568 /* That case is invalid for QoS events */
2569 if (diff < 0 && -diff > timestamp) {
2570 LOGW("QOS event from previous group");
2571 ret = GST_PAD_PROBE_DROP;
2575 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2576 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2586 gst_caps_unref(caps);
2591 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2593 mm_player_t* player = NULL;
2594 GstElement* pipeline = NULL;
2595 GstElement* selector = NULL;
2596 GstElement* fakesink = NULL;
2597 GstCaps* caps = NULL;
2598 GstStructure* str = NULL;
2599 const gchar* name = NULL;
2600 GstPad* sinkpad = NULL;
2601 GstPad* srcpad = NULL;
2602 gboolean first_track = FALSE;
2604 enum MainElementID elemId = MMPLAYER_M_NUM;
2605 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2608 player = (mm_player_t*)data;
2610 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2611 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2613 //LOGD("pad-added signal handling\n");
2615 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2617 /* get mimetype from caps */
2618 caps = gst_pad_query_caps(pad, NULL);
2620 LOGE("cannot get caps from pad.\n");
2624 str = gst_caps_get_structure(caps, 0);
2626 LOGE("cannot get structure from caps.\n");
2630 name = gst_structure_get_name(str);
2632 LOGE("cannot get mimetype from structure.\n");
2636 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2637 //LOGD("detected mimetype : %s\n", name);
2639 if (strstr(name, "video")) {
2642 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2643 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2645 /* don't make video because of not required, and not support multiple track */
2646 if (stype == MM_DISPLAY_SURFACE_NULL) {
2647 LOGD("no video sink by null surface");
2649 gchar *caps_str = gst_caps_to_string(caps);
2650 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12")))
2651 player->set_mode.video_zc = TRUE;
2653 MMPLAYER_FREEIF(caps_str);
2655 if (player->v_stream_caps) {
2656 gst_caps_unref(player->v_stream_caps);
2657 player->v_stream_caps = NULL;
2660 LOGD("create fakesink instead of videobin");
2663 fakesink = gst_element_factory_make("fakesink", NULL);
2664 if (fakesink == NULL) {
2665 LOGE("ERROR : fakesink create error\n");
2669 if (player->ini.set_dump_element_flag)
2670 __mmplayer_add_dump_buffer_probe(player, fakesink);
2672 player->video_fakesink = fakesink;
2674 /* store it as it's sink element */
2675 __mmplayer_add_sink(player, player->video_fakesink);
2677 gst_bin_add(GST_BIN(pipeline), fakesink);
2680 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2682 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2683 LOGW("failed to link fakesink\n");
2684 gst_object_unref(GST_OBJECT(fakesink));
2688 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2689 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2690 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2693 if (player->set_mode.media_packet_video_stream) {
2694 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2696 MMPLAYER_SIGNAL_CONNECT(player,
2698 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2700 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2703 MMPLAYER_SIGNAL_CONNECT(player,
2705 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2707 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2711 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2712 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2716 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2717 __mmplayer_gst_decode_callback(elem, pad, player);
2721 LOGD("video selector \n");
2722 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2723 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2725 if (strstr(name, "audio")) {
2726 gint samplerate = 0;
2729 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2730 __mmplayer_gst_decode_callback(elem, pad, player);
2734 LOGD("audio selector \n");
2735 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2736 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2738 gst_structure_get_int(str, "rate", &samplerate);
2739 gst_structure_get_int(str, "channels", &channels);
2741 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2743 fakesink = gst_element_factory_make("fakesink", NULL);
2744 if (fakesink == NULL) {
2745 LOGE("ERROR : fakesink create error\n");
2749 gst_bin_add(GST_BIN(pipeline), fakesink);
2752 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2754 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2755 LOGW("failed to link fakesink\n");
2756 gst_object_unref(GST_OBJECT(fakesink));
2760 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2761 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2762 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2766 } else if (strstr(name, "text")) {
2767 LOGD("text selector \n");
2768 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2769 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2771 LOGE("wrong elem id \n");
2776 selector = player->pipeline->mainbin[elemId].gst;
2777 if (selector == NULL) {
2778 selector = gst_element_factory_make("input-selector", NULL);
2779 LOGD("Creating input-selector\n");
2780 if (selector == NULL) {
2781 LOGE("ERROR : input-selector create error\n");
2784 g_object_set(selector, "sync-streams", TRUE, NULL);
2786 player->pipeline->mainbin[elemId].id = elemId;
2787 player->pipeline->mainbin[elemId].gst = selector;
2790 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2792 srcpad = gst_element_get_static_pad(selector, "src");
2794 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2795 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2796 __mmplayer_gst_selector_blocked, NULL, NULL);
2797 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2798 __mmplayer_gst_selector_event_probe, player, NULL);
2800 gst_element_set_state(selector, GST_STATE_PAUSED);
2801 gst_bin_add(GST_BIN(pipeline), selector);
2803 LOGD("input-selector is already created.\n");
2806 LOGD("Calling request pad with selector %p \n", selector);
2807 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2809 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2811 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2812 LOGW("failed to link selector\n");
2813 gst_object_unref(GST_OBJECT(selector));
2818 LOGD("this is first track --> active track \n");
2819 g_object_set(selector, "active-pad", sinkpad, NULL);
2822 _mmplayer_track_update_info(player, stream_type, sinkpad);
2829 gst_caps_unref(caps);
2832 gst_object_unref(GST_OBJECT(sinkpad));
2837 gst_object_unref(GST_OBJECT(srcpad));
2844 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2846 GstPad* srcpad = NULL;
2847 MMHandleType attrs = 0;
2848 gint active_index = 0;
2850 // [link] input-selector :: textbin
2851 srcpad = gst_element_get_static_pad(text_selector, "src");
2853 LOGE("failed to get srcpad from selector\n");
2857 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2859 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2860 if ((active_index != DEFAULT_TRACK) &&
2861 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2862 LOGW("failed to change text track\n");
2863 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2866 player->no_more_pad = TRUE;
2867 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2869 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2870 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2871 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2872 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2875 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2877 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2878 player->has_closed_caption = TRUE;
2880 attrs = MMPLAYER_GET_ATTRS(player);
2882 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2883 if (mmf_attrs_commit(attrs))
2884 LOGE("failed to commit.\n");
2886 LOGE("cannot get content attribute");
2889 gst_object_unref(GST_OBJECT(srcpad));
2895 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2897 mm_player_t* player = (mm_player_t*)data;
2898 GstElement* selector = NULL;
2899 GstElement* queue = NULL;
2901 GstPad* srcpad = NULL;
2902 GstPad* sinkpad = NULL;
2903 gchar* caps_str = NULL;
2906 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2908 caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad));
2909 LOGD("deinterleave new caps : %s\n", caps_str);
2910 MMPLAYER_FREEIF(caps_str);
2912 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2913 LOGE("ERROR : queue create error\n");
2917 g_object_set(G_OBJECT(queue),
2918 "max-size-buffers", 10,
2919 "max-size-bytes", 0,
2920 "max-size-time", (guint64)0,
2923 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2926 LOGE("there is no audio channel selector.\n");
2930 srcpad = gst_element_get_static_pad(queue, "src");
2931 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2933 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2935 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2936 LOGW("failed to link deinterleave - selector\n");
2940 gst_element_set_state(queue, GST_STATE_PAUSED);
2941 player->audio_mode.total_track_num++;
2946 gst_object_unref(GST_OBJECT(srcpad));
2951 gst_object_unref(GST_OBJECT(sinkpad));
2960 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2962 mm_player_t* player = NULL;
2963 GstElement* selector = NULL;
2964 GstPad* sinkpad = NULL;
2965 gint active_index = 0;
2966 gchar* change_pad_name = NULL;
2967 GstCaps* caps = NULL; // no need to unref
2968 gint default_audio_ch = 0;
2971 player = (mm_player_t*) data;
2973 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2976 LOGE("there is no audio channel selector.\n");
2980 active_index = player->audio_mode.active_pad_index;
2982 if (active_index != default_audio_ch) {
2983 gint audio_ch = default_audio_ch;
2985 /*To get the new pad from the selector*/
2986 change_pad_name = g_strdup_printf("sink%d", active_index);
2987 if (change_pad_name != NULL) {
2988 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2989 if (sinkpad != NULL) {
2990 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2991 g_object_set(selector, "active-pad", sinkpad, NULL);
2993 audio_ch = active_index;
2995 caps = gst_pad_get_current_caps(sinkpad);
2996 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2998 __mmplayer_set_audio_attrs(player, caps);
3000 MMPLAYER_FREEIF(change_pad_name);
3003 player->audio_mode.active_pad_index = audio_ch;
3004 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
3010 gst_object_unref(sinkpad);
3017 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
3019 mm_player_t* player = NULL;
3020 MMPlayerGstElement *mainbin = NULL;
3022 GstElement* tee = NULL;
3023 GstElement* stereo_queue = NULL;
3024 GstElement* mono_queue = NULL;
3025 GstElement* conv = NULL;
3026 GstElement* filter = NULL;
3027 GstElement* deinterleave = NULL;
3028 GstElement* selector = NULL;
3030 GstPad* srcpad = NULL;
3031 GstPad* selector_srcpad = NULL;
3032 GstPad* sinkpad = NULL;
3033 GstCaps* caps = NULL;
3034 gulong block_id = 0;
3039 player = (mm_player_t*) data;
3041 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3042 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3044 mainbin = player->pipeline->mainbin;
3047 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
3048 LOGE("ERROR : tee create error\n");
3052 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3053 mainbin[MMPLAYER_M_A_TEE].gst = tee;
3055 gst_element_set_state(tee, GST_STATE_PAUSED);
3058 srcpad = gst_element_get_request_pad(tee, "src_%u");
3059 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3060 LOGE("ERROR : stereo queue create error\n");
3064 g_object_set(G_OBJECT(stereo_queue),
3065 "max-size-buffers", 10,
3066 "max-size-bytes", 0,
3067 "max-size-time", (guint64)0,
3070 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3071 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3074 gst_object_unref(GST_OBJECT(srcpad));
3078 srcpad = gst_element_get_request_pad(tee, "src_%u");
3080 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3081 LOGE("ERROR : mono queue create error\n");
3085 g_object_set(G_OBJECT(mono_queue),
3086 "max-size-buffers", 10,
3087 "max-size-bytes", 0,
3088 "max-size-time", (guint64)0,
3091 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3092 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3094 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3095 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3098 srcpad = gst_element_get_static_pad(mono_queue, "src");
3099 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3100 LOGE("ERROR : audioconvert create error\n");
3104 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3105 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3109 gst_object_unref(GST_OBJECT(srcpad));
3112 srcpad = gst_element_get_static_pad(conv, "src");
3114 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3115 LOGE("ERROR : capsfilter create error\n");
3119 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3120 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3122 caps = gst_caps_from_string("audio/x-raw-int, "
3123 "width = (int) 16, "
3124 "depth = (int) 16, "
3125 "channels = (int) 2");
3127 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3128 gst_caps_unref(caps);
3130 gst_element_set_state(conv, GST_STATE_PAUSED);
3131 gst_element_set_state(filter, GST_STATE_PAUSED);
3135 gst_object_unref(GST_OBJECT(srcpad));
3138 srcpad = gst_element_get_static_pad(filter, "src");
3140 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3141 LOGE("ERROR : deinterleave create error\n");
3145 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3147 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3148 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3150 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3151 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3153 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3154 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3157 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3158 if (selector == NULL) {
3159 LOGE("ERROR : audio-selector create error\n");
3163 g_object_set(selector, "sync-streams", TRUE, NULL);
3164 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3166 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3167 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3169 selector_srcpad = gst_element_get_static_pad(selector, "src");
3171 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3173 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3174 __mmplayer_gst_selector_blocked, NULL, NULL);
3177 gst_object_unref(GST_OBJECT(srcpad));
3181 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3182 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3184 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3185 LOGW("failed to link queue_stereo - selector\n");
3189 player->audio_mode.total_track_num++;
3191 g_object_set(selector, "active-pad", sinkpad, NULL);
3192 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3193 gst_element_set_state(selector, GST_STATE_PAUSED);
3195 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3199 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3200 if (block_id != 0) {
3201 gst_pad_remove_probe(selector_srcpad, block_id);
3206 gst_object_unref(GST_OBJECT(sinkpad));
3211 gst_object_unref(GST_OBJECT(srcpad));
3215 if (selector_srcpad) {
3216 gst_object_unref(GST_OBJECT(selector_srcpad));
3217 selector_srcpad = NULL;
3225 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3227 mm_player_t* player = NULL;
3228 GstPad* srcpad = NULL;
3229 GstElement* video_selector = NULL;
3230 GstElement* audio_selector = NULL;
3231 GstElement* text_selector = NULL;
3232 MMHandleType attrs = 0;
3233 gint active_index = 0;
3234 gint64 dur_bytes = 0L;
3236 player = (mm_player_t*) data;
3238 LOGD("no-more-pad signal handling\n");
3240 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3241 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3242 LOGW("no need to go more");
3244 if (player->gapless.reconfigure) {
3245 player->gapless.reconfigure = FALSE;
3246 MMPLAYER_PLAYBACK_UNLOCK(player);
3252 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3253 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3254 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3255 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3256 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3258 if (NULL == player->streamer) {
3259 LOGW("invalid state for buffering");
3263 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
3264 guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT;
3266 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3267 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes);
3269 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3271 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3272 LOGE("fail to get duration.\n");
3274 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3275 // use file information was already set on Q2 when it was created.
3276 __mm_player_streaming_set_queue2(player->streamer,
3277 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3278 TRUE, // use_buffering
3280 init_buffering_time,
3282 player->ini.http_buffering_limit, // high percent
3283 MUXED_BUFFER_TYPE_MEM_QUEUE,
3285 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3288 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3289 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3290 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3291 if (video_selector) {
3292 // [link] input-selector :: videobin
3293 srcpad = gst_element_get_static_pad(video_selector, "src");
3295 LOGE("failed to get srcpad from video selector\n");
3299 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3300 if (!text_selector && !audio_selector)
3301 player->no_more_pad = TRUE;
3303 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3305 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3306 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3307 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3308 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3312 if (audio_selector) {
3313 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3314 if ((active_index != DEFAULT_TRACK) &&
3315 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3316 LOGW("failed to change audio track\n");
3317 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3320 // [link] input-selector :: audiobin
3321 srcpad = gst_element_get_static_pad(audio_selector, "src");
3323 LOGE("failed to get srcpad from selector\n");
3327 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3329 player->no_more_pad = TRUE;
3331 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3332 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3333 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3334 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3335 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3338 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3340 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3342 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3343 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3344 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3345 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3349 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3351 attrs = MMPLAYER_GET_ATTRS(player);
3353 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3354 if (mmf_attrs_commit(attrs))
3355 LOGE("failed to commit.\n");
3357 LOGE("cannot get content attribute");
3359 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3360 LOGD("There is no audio track : remove audiobin");
3362 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3363 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3365 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3366 MMPLAYER_FREEIF(player->pipeline->audiobin);
3369 if (player->num_dynamic_pad == 0)
3370 __mmplayer_pipeline_complete(NULL, player);
3373 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3375 __mmplayer_handle_text_decode_path(player, text_selector);
3382 gst_object_unref(GST_OBJECT(srcpad));
3386 if (player->gapless.reconfigure) {
3387 player->gapless.reconfigure = FALSE;
3388 MMPLAYER_PLAYBACK_UNLOCK(player);
3393 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3395 mm_player_t* player = NULL;
3396 MMHandleType attrs = 0;
3397 GstElement* pipeline = NULL;
3398 GstCaps* caps = NULL;
3399 gchar* caps_str = NULL;
3400 GstStructure* str = NULL;
3401 const gchar* name = NULL;
3402 GstPad* sinkpad = NULL;
3403 GstElement* sinkbin = NULL;
3404 gboolean reusing = FALSE;
3405 GstElement *text_selector = NULL;
3406 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
3409 player = (mm_player_t*) data;
3411 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3412 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3414 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3416 attrs = MMPLAYER_GET_ATTRS(player);
3418 LOGE("cannot get content attribute\n");
3422 /* get mimetype from caps */
3423 caps = gst_pad_query_caps(pad, NULL);
3425 LOGE("cannot get caps from pad.\n");
3428 caps_str = gst_caps_to_string(caps);
3430 str = gst_caps_get_structure(caps, 0);
3432 LOGE("cannot get structure from caps.\n");
3436 name = gst_structure_get_name(str);
3438 LOGE("cannot get mimetype from structure.\n");
3442 //LOGD("detected mimetype : %s\n", name);
3444 if (strstr(name, "audio")) {
3445 if (player->pipeline->audiobin == NULL) {
3446 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3447 LOGE("failed to create audiobin. continuing without audio\n");
3451 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3452 LOGD("creating audiosink bin success\n");
3455 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3456 LOGD("reusing audiobin\n");
3457 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3460 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3461 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3463 player->audiosink_linked = 1;
3465 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3467 LOGE("failed to get pad from sinkbin\n");
3470 } else if (strstr(name, "video")) {
3471 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12")))
3472 player->set_mode.video_zc = TRUE;
3474 if (player->pipeline->videobin == NULL) {
3475 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3476 /* get video surface type */
3477 int surface_type = 0;
3478 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3479 LOGD("display_surface_type(%d)\n", surface_type);
3481 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3482 LOGD("not make videobin because it dose not want\n");
3486 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3487 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
3488 /* prepare resource manager for video overlay */
3489 if (resource_state >= RESOURCE_STATE_INITIALIZED) {
3490 if (_mmplayer_resource_manager_prepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], RESOURCE_TYPE_VIDEO_OVERLAY)
3492 LOGE("could not prepare for video_overlay resource\n");
3499 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
3500 /* acquire resources for video overlay */
3501 if (resource_state == RESOURCE_STATE_PREPARED) {
3502 if (_mmplayer_resource_manager_acquire(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]) != MM_ERROR_NONE) {
3503 LOGE("could not acquire resources for video playing\n");
3504 _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
3510 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3511 LOGE("failed to create videobin. continuing without video\n");
3515 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3516 LOGD("creating videosink bin success\n");
3519 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3520 LOGD("re-using videobin\n");
3521 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3524 /* FIXIT : track number shouldn't be hardcoded */
3525 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3526 player->videosink_linked = 1;
3528 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3530 LOGE("failed to get pad from sinkbin\n");
3533 } else if (strstr(name, "text")) {
3534 if (player->pipeline->textbin == NULL) {
3535 MMPlayerGstElement* mainbin = NULL;
3537 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3538 LOGE("failed to create text sink bin. continuing without text\n");
3542 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3543 LOGD("creating textsink bin success\n");
3545 /* FIXIT : track number shouldn't be hardcoded */
3546 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3548 player->textsink_linked = 1;
3549 LOGI("player->textsink_linked set to 1\n");
3551 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3553 LOGE("failed to get pad from sinkbin\n");
3557 mainbin = player->pipeline->mainbin;
3559 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3560 /* input selector */
3561 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3562 if (!text_selector) {
3563 LOGE("failed to create subtitle input selector element\n");
3566 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3568 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3569 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3572 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3573 LOGE("failed to set state(READY) to sinkbin\n");
3577 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3578 LOGW("failed to add subtitle input selector\n");
3582 LOGD("created element input-selector");
3585 LOGD("already having subtitle input selector");
3586 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3589 if (!player->textsink_linked) {
3590 LOGD("re-using textbin\n");
3593 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3595 player->textsink_linked = 1;
3596 LOGI("player->textsink_linked set to 1\n");
3598 LOGD("ignoring internal subtutle since external subtitle is available");
3601 LOGW("unknown type of elementary stream!ignoring it...\n");
3608 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3609 LOGE("failed to set state(READY) to sinkbin\n");
3613 /* Added for multi audio support to avoid adding audio bin again*/
3615 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3616 LOGE("failed to add sinkbin to pipeline\n");
3622 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3623 LOGE("failed to get pad from sinkbin\n");
3629 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3630 LOGE("failed to set state(PAUSED) to sinkbin\n");
3634 if (text_selector) {
3635 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3636 LOGE("failed to set state(PAUSED) to sinkbin\n");
3642 gst_object_unref(sinkpad);
3646 LOGD("linking sink bin success\n");
3648 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3649 * streaming task. if the task blocked, then buffer will not flow to the next element
3650 *(autoplugging element). so this is special hack for streaming. please try to remove it
3652 /* dec stream count. we can remove fakesink if it's zero */
3653 if (player->num_dynamic_pad)
3654 player->num_dynamic_pad--;
3656 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3658 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3659 __mmplayer_pipeline_complete(NULL, player);
3661 /* FIXIT : please leave a note why this code is needed */
3662 if (MMPLAYER_IS_WFD_STREAMING(player))
3663 player->no_more_pad = TRUE;
3667 MMPLAYER_FREEIF(caps_str);
3670 gst_caps_unref(caps);
3673 gst_object_unref(GST_OBJECT(sinkpad));
3675 /* flusing out new attributes */
3676 if (mmf_attrs_commit(attrs))
3677 LOGE("failed to comit attributes\n");
3683 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3685 int pro_value = 0; // in the case of expection, default will be returned.
3686 int dest_angle = rotation_angle;
3687 int rotation_type = -1;
3689 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3690 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3691 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3693 if (rotation_angle >= 360)
3694 dest_angle = rotation_angle - 360;
3696 /* chech if supported or not */
3697 if (dest_angle % 90) {
3698 LOGD("not supported rotation angle = %d", rotation_angle);
3704 * custom_convert - none (B)
3705 * videoflip - none (C)
3707 if (player->set_mode.video_zc) {
3708 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3709 rotation_type = ROTATION_USING_CUSTOM;
3711 rotation_type = ROTATION_USING_SINK;
3713 int surface_type = 0;
3714 rotation_type = ROTATION_USING_FLIP;
3716 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3717 LOGD("check display surface type attribute: %d", surface_type);
3719 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3720 rotation_type = ROTATION_USING_SINK;
3722 rotation_type = ROTATION_USING_FLIP; //C
3724 LOGD("using %d type for rotation", rotation_type);
3727 /* get property value for setting */
3728 switch (rotation_type) {
3729 case ROTATION_USING_SINK: // waylandsink
3731 switch (dest_angle) {
3735 pro_value = 3; // clockwise 90
3741 pro_value = 1; // counter-clockwise 90
3746 case ROTATION_USING_CUSTOM:
3748 gchar *ename = NULL;
3749 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3751 if (g_strrstr(ename, "fimcconvert")) {
3752 switch (dest_angle) {
3756 pro_value = 90; // clockwise 90
3762 pro_value = 270; // counter-clockwise 90
3768 case ROTATION_USING_FLIP: // videoflip
3770 switch (dest_angle) {
3774 pro_value = 1; // clockwise 90
3780 pro_value = 3; // counter-clockwise 90
3787 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3795 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3797 /* check video sinkbin is created */
3798 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3800 player->pipeline->videobin &&
3801 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3802 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3803 MM_ERROR_PLAYER_NOT_INITIALIZED);
3805 return MM_ERROR_NONE;
3809 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3811 int rotation_value = 0;
3812 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3816 /* check video sinkbin is created */
3817 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3820 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3822 /* get rotation value to set */
3823 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3824 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3825 LOGD("set video param : rotate %d", rotation_value);
3829 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3831 MMHandleType attrs = 0;
3835 /* check video sinkbin is created */
3836 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3839 attrs = MMPLAYER_GET_ATTRS(player);
3840 MMPLAYER_RETURN_IF_FAIL(attrs);
3842 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3843 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3844 LOGD("set video param : visible %d", visible);
3848 __mmplayer_video_param_set_display_method(mm_player_t* player)
3850 MMHandleType attrs = 0;
3851 int display_method = 0;
3854 /* check video sinkbin is created */
3855 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3858 attrs = MMPLAYER_GET_ATTRS(player);
3859 MMPLAYER_RETURN_IF_FAIL(attrs);
3861 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3862 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3863 LOGD("set video param : method %d", display_method);
3867 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3869 MMHandleType attrs = 0;
3870 int display_method = 0;
3871 void *handle = NULL;
3873 int wl_window_x = 0;
3874 int wl_window_y = 0;
3875 int wl_window_width = 0;
3876 int wl_window_height = 0;
3879 /* check video sinkbin is created */
3880 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3883 attrs = MMPLAYER_GET_ATTRS(player);
3884 MMPLAYER_RETURN_IF_FAIL(attrs);
3886 /* check roi mode is set */
3887 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3888 if (display_method != PLAYER_DISPLAY_MODE_DST_ROI) {
3889 LOGE("must be set display-geometry-method to DISP_GEO_METHOD_CUSTOM_ROI before setting render rectangle");
3892 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3895 /*It should be set after setting window*/
3896 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3897 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3898 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3899 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3901 /* After setting window handle, set render rectangle */
3902 gst_video_overlay_set_render_rectangle(
3903 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3904 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3905 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3906 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3911 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3913 MMHandleType attrs = 0;
3914 void *handle = NULL;
3916 /* check video sinkbin is created */
3917 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3920 attrs = MMPLAYER_GET_ATTRS(player);
3921 MMPLAYER_RETURN_IF_FAIL(attrs);
3923 /* common case if using overlay surface */
3924 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3927 /* default is using wl_surface_id */
3928 unsigned int wl_surface_id = 0;
3929 wl_surface_id = *(int*)handle;
3930 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3931 gst_video_overlay_set_wl_window_wl_surface_id(
3932 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3935 /* FIXIT : is it error case? */
3936 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3941 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3943 bool update_all_param = FALSE;
3946 /* check video sinkbin is created */
3947 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3948 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3950 if (strcmp(player->ini.videosink_element_overlay, "waylandsink")) {
3951 LOGE("can not find waylandsink");
3952 return MM_ERROR_PLAYER_INTERNAL;
3955 LOGD("param_name : %s", param_name);
3956 if (!g_strcmp0(param_name, "update_all_param"))
3957 update_all_param = TRUE;
3959 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3960 __mmplayer_video_param_set_display_overlay(player);
3961 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3962 __mmplayer_video_param_set_display_method(player);
3963 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3964 __mmplayer_video_param_set_render_rectangle(player);
3965 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3966 __mmplayer_video_param_set_display_visible(player);
3967 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3968 __mmplayer_video_param_set_display_rotation(player);
3970 return MM_ERROR_NONE;
3974 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3976 MMHandleType attrs = 0;
3977 int surface_type = 0;
3978 int ret = MM_ERROR_NONE;
3982 /* check video sinkbin is created */
3983 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3984 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3986 attrs = MMPLAYER_GET_ATTRS(player);
3988 LOGE("cannot get content attribute");
3989 return MM_ERROR_PLAYER_INTERNAL;
3991 LOGD("param_name : %s", param_name);
3993 /* update display surface */
3994 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3995 LOGD("check display surface type attribute: %d", surface_type);
3997 /* configuring display */
3998 switch (surface_type) {
3999 case MM_DISPLAY_SURFACE_OVERLAY:
4001 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
4002 if (ret != MM_ERROR_NONE)
4010 return MM_ERROR_NONE;
4014 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
4016 gboolean disable_overlay = FALSE;
4017 mm_player_t* player = (mm_player_t*) hplayer;
4018 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
4019 int ret = MM_ERROR_NONE;
4022 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4023 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4024 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4025 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4027 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4028 LOGW("Display control is not supported");
4029 return MM_ERROR_PLAYER_INTERNAL;
4032 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4034 if (audio_only == (bool)disable_overlay) {
4035 LOGE("It's the same with current setting: (%d)", audio_only);
4036 return MM_ERROR_NONE;
4040 LOGE("disable overlay");
4041 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
4043 /* release overlay resource */
4044 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
4045 if (resource_state >= RESOURCE_STATE_ACQUIRED) {
4046 ret = _mmplayer_resource_manager_release(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
4047 if (ret != MM_ERROR_NONE) {
4048 LOGE("failed to release overlay resource, ret(0x%x)\n", ret);
4054 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
4055 if (resource_state == RESOURCE_STATE_PREPARED) {
4056 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
4057 if (ret != MM_ERROR_NONE) {
4058 LOGE("failed to unprepare overlay resource, ret(0x%x)\n", ret);
4064 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
4065 /* prepare resource manager for video overlay */
4066 if (resource_state >= RESOURCE_STATE_INITIALIZED) {
4067 ret = _mmplayer_resource_manager_prepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], RESOURCE_TYPE_VIDEO_OVERLAY);
4068 if (ret != MM_ERROR_NONE) {
4069 LOGE("could not prepare for video_overlay resource\n");
4075 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
4076 /* acquire resources for video overlay */
4077 if (resource_state == RESOURCE_STATE_PREPARED) {
4078 ret = _mmplayer_resource_manager_acquire(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
4079 if (ret != MM_ERROR_NONE) {
4080 LOGE("could not acquire resources for video playing\n");
4081 _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
4087 LOGD("enable overlay");
4088 __mmplayer_video_param_set_display_overlay(player);
4089 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
4094 return MM_ERROR_NONE;
4098 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
4100 mm_player_t* player = (mm_player_t*) hplayer;
4101 gboolean disable_overlay = FALSE;
4105 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4106 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
4107 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4108 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4109 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4111 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4112 LOGW("Display control is not supported");
4113 return MM_ERROR_PLAYER_INTERNAL;
4116 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4118 *paudio_only = (bool)(disable_overlay);
4120 LOGD("audio_only : %d", *paudio_only);
4124 return MM_ERROR_NONE;
4128 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4130 GList* bucket = element_bucket;
4131 MMPlayerGstElement* element = NULL;
4132 MMPlayerGstElement* prv_element = NULL;
4133 gint successful_link_count = 0;
4137 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4139 prv_element = (MMPlayerGstElement*)bucket->data;
4140 bucket = bucket->next;
4142 for (; bucket; bucket = bucket->next) {
4143 element = (MMPlayerGstElement*)bucket->data;
4145 if (element && element->gst) {
4146 /* If next element is audio appsrc then make a separate audio pipeline */
4147 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4148 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4149 prv_element = element;
4153 if (prv_element && prv_element->gst) {
4154 if (GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4155 LOGD("linking [%s] to [%s] success\n",
4156 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4157 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4158 successful_link_count++;
4160 LOGD("linking [%s] to [%s] failed\n",
4161 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4162 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4168 prv_element = element;
4173 return successful_link_count;
4177 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4179 GList* bucket = element_bucket;
4180 MMPlayerGstElement* element = NULL;
4181 int successful_add_count = 0;
4185 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4186 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4188 for (; bucket; bucket = bucket->next) {
4189 element = (MMPlayerGstElement*)bucket->data;
4191 if (element && element->gst) {
4192 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4193 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4194 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4195 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4198 successful_add_count++;
4204 return successful_add_count;
4207 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4209 mm_player_t* player = (mm_player_t*) data;
4210 GstCaps *caps = NULL;
4211 GstStructure *str = NULL;
4216 MMPLAYER_RETURN_IF_FAIL(pad)
4217 MMPLAYER_RETURN_IF_FAIL(unused)
4218 MMPLAYER_RETURN_IF_FAIL(data)
4220 caps = gst_pad_get_current_caps(pad);
4224 str = gst_caps_get_structure(caps, 0);
4228 name = gst_structure_get_name(str);
4232 LOGD("name = %s\n", name);
4234 if (strstr(name, "audio")) {
4235 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4237 if (player->audio_stream_changed_cb) {
4238 LOGE("call the audio stream changed cb\n");
4239 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4241 } else if (strstr(name, "video")) {
4242 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4244 if (player->video_stream_changed_cb) {
4245 LOGE("call the video stream changed cb\n");
4246 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4253 gst_caps_unref(caps);
4263 * This function is to create audio pipeline for playing.
4265 * @param player [in] handle of player
4267 * @return This function returns zero on success.
4269 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4271 /* macro for code readability. just for sinkbin-creation functions */
4272 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4274 x_bin[x_id].id = x_id;\
4275 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4276 if (!x_bin[x_id].gst) {\
4277 LOGE("failed to create %s \n", x_factory);\
4280 if (x_player->ini.set_dump_element_flag)\
4281 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4284 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4288 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4293 MMPLAYER_RETURN_IF_FAIL(player);
4295 if (player->audio_stream_buff_list) {
4296 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4297 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4300 LOGD("[%lld] send remained data.", tmp->channel_mask);
4301 __mmplayer_audio_stream_send_data(player, tmp);
4304 g_free(tmp->pcm_data);
4308 g_list_free(player->audio_stream_buff_list);
4309 player->audio_stream_buff_list = NULL;
4316 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4318 MMPlayerAudioStreamDataType audio_stream = { 0, };
4321 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4323 audio_stream.bitrate = a_buffer->bitrate;
4324 audio_stream.channel = a_buffer->channel;
4325 audio_stream.depth = a_buffer->depth;
4326 audio_stream.is_little_endian = a_buffer->is_little_endian;
4327 audio_stream.channel_mask = a_buffer->channel_mask;
4328 audio_stream.data_size = a_buffer->data_size;
4329 audio_stream.data = a_buffer->pcm_data;
4331 /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4332 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4338 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4340 mm_player_t* player = (mm_player_t*) data;
4345 gint endianness = 0;
4346 guint64 channel_mask = 0;
4347 void *a_data = NULL;
4349 mm_player_audio_stream_buff_t *a_buffer = NULL;
4350 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4354 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4356 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4357 a_data = mapinfo.data;
4358 a_size = mapinfo.size;
4360 GstCaps *caps = gst_pad_get_current_caps(pad);
4361 GstStructure *structure = gst_caps_get_structure(caps, 0);
4363 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4364 gst_structure_get_int(structure, "rate", &rate);
4365 gst_structure_get_int(structure, "channels", &channel);
4366 gst_structure_get_int(structure, "depth", &depth);
4367 gst_structure_get_int(structure, "endianness", &endianness);
4368 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4369 gst_caps_unref(GST_CAPS(caps));
4371 /* In case of the sync is false, use buffer list. *
4372 * The num of buffer list depends on the num of audio channels */
4373 if (player->audio_stream_buff_list) {
4374 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4375 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4377 if (channel_mask == tmp->channel_mask) {
4378 /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4379 if (tmp->data_size + a_size < tmp->buff_size) {
4380 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4381 tmp->data_size += a_size;
4383 /* send data to client */
4384 __mmplayer_audio_stream_send_data(player, tmp);
4386 if (a_size > tmp->buff_size) {
4387 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4388 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4389 if (tmp->pcm_data == NULL) {
4390 LOGE("failed to realloc data.");
4393 tmp->buff_size = a_size;
4395 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4396 memcpy(tmp->pcm_data, a_data, a_size);
4397 tmp->data_size = a_size;
4402 LOGE("data is empty in list.");
4408 /* create new audio stream data */
4409 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4410 if (a_buffer == NULL) {
4411 LOGE("failed to alloc data.");
4414 a_buffer->bitrate = rate;
4415 a_buffer->channel = channel;
4416 a_buffer->depth = depth;
4417 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4418 a_buffer->channel_mask = channel_mask;
4419 a_buffer->data_size = a_size;
4421 if (!player->audio_stream_sink_sync) {
4422 /* If sync is FALSE, use buffer list to reduce the IPC. */
4423 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4424 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4425 if (a_buffer->pcm_data == NULL) {
4426 LOGE("failed to alloc data.");
4430 memcpy(a_buffer->pcm_data, a_data, a_size);
4431 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4432 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4434 /* If sync is TRUE, send data directly. */
4435 a_buffer->pcm_data = a_data;
4436 __mmplayer_audio_stream_send_data(player, a_buffer);
4441 gst_buffer_unmap(buffer, &mapinfo);
4446 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4448 mm_player_t* player = (mm_player_t*)data;
4449 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4450 GstPad* sinkpad = NULL;
4451 GstElement *queue = NULL, *sink = NULL;
4454 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4456 queue = gst_element_factory_make("queue", NULL);
4457 if (queue == NULL) {
4458 LOGD("fail make queue\n");
4462 sink = gst_element_factory_make("fakesink", NULL);
4464 LOGD("fail make fakesink\n");
4468 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4470 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4471 LOGW("failed to link queue & sink\n");
4475 sinkpad = gst_element_get_static_pad(queue, "sink");
4477 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4478 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4482 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4484 gst_object_unref(sinkpad);
4485 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4486 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4488 gst_element_set_state(sink, GST_STATE_PAUSED);
4489 gst_element_set_state(queue, GST_STATE_PAUSED);
4491 MMPLAYER_SIGNAL_CONNECT(player,
4493 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4495 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4502 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4504 gst_object_unref(GST_OBJECT(queue));
4508 gst_object_unref(GST_OBJECT(sink));
4512 gst_object_unref(GST_OBJECT(sinkpad));
4519 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4521 #define MAX_PROPS_LEN 128
4522 gint latency_mode = 0;
4523 gchar *stream_type = NULL;
4524 gchar *latency = NULL;
4526 gchar stream_props[MAX_PROPS_LEN] = {0,};
4527 GstStructure *props = NULL;
4530 * It should be set after player creation through attribute.
4531 * But, it can not be changed during playing.
4534 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4535 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4538 LOGE("stream_type is null.\n");
4540 if (player->sound_focus.focus_id)
4541 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d, mused.client_pid=%d",
4542 stream_type, stream_id, player->sound_focus.focus_id, player->sound_focus.pid);
4544 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, mused.client_pid=%d",
4545 stream_type, stream_id, player->sound_focus.pid);
4546 props = gst_structure_from_string(stream_props, NULL);
4547 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4548 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], client_pid[%d], result[%s].\n",
4549 stream_type, stream_id, player->sound_focus.focus_id, player->sound_focus.pid, stream_props);
4552 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4554 switch (latency_mode) {
4555 case AUDIO_LATENCY_MODE_LOW:
4556 latency = g_strndup("low", 3);
4558 case AUDIO_LATENCY_MODE_MID:
4559 latency = g_strndup("mid", 3);
4561 case AUDIO_LATENCY_MODE_HIGH:
4562 latency = g_strndup("high", 4);
4566 #if 0 //need to check
4567 if (player->sound_focus.user_route_policy != 0)
4568 route_path = player->sound_focus.user_route_policy;
4570 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4571 "latency", latency_mode,
4574 LOGD("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4575 volume_type, route_path, latency_mode);
4580 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4584 LOGD("audiosink property - latency=%s \n", latency);
4592 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4594 MMPlayerGstElement* first_element = NULL;
4595 MMPlayerGstElement* audiobin = NULL;
4596 MMHandleType attrs = 0;
4598 GstPad *ghostpad = NULL;
4599 GList* element_bucket = NULL;
4600 gboolean link_audio_sink_now = TRUE;
4605 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4608 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4610 LOGE("failed to allocate memory for audiobin\n");
4611 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4614 attrs = MMPLAYER_GET_ATTRS(player);
4617 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4618 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4619 if (!audiobin[MMPLAYER_A_BIN].gst) {
4620 LOGE("failed to create audiobin\n");
4625 player->pipeline->audiobin = audiobin;
4627 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4629 /* Adding audiotp plugin for reverse trickplay feature */
4630 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4633 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4636 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4638 if (player->set_mode.pcm_extraction) {
4639 // pcm extraction only and no sound output
4640 if (player->audio_stream_render_cb_ex) {
4641 char *caps_str = NULL;
4642 GstCaps* caps = NULL;
4643 gchar *format = NULL;
4646 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4648 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4650 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4652 caps = gst_caps_new_simple("audio/x-raw",
4653 "format", G_TYPE_STRING, format,
4654 "rate", G_TYPE_INT, player->pcm_samplerate,
4655 "channels", G_TYPE_INT, player->pcm_channel,
4657 caps_str = gst_caps_to_string(caps);
4658 LOGD("new caps : %s\n", caps_str);
4660 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4663 gst_caps_unref(caps);
4664 MMPLAYER_FREEIF(caps_str);
4666 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4668 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4669 /* raw pad handling signal */
4670 MMPLAYER_SIGNAL_CONNECT(player,
4671 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4672 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4673 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4675 int dst_samplerate = 0;
4676 int dst_channels = 0;
4678 char *caps_str = NULL;
4679 GstCaps* caps = NULL;
4681 /* get conf. values */
4682 mm_attrs_multiple_get(player->attrs,
4684 "pcm_extraction_samplerate", &dst_samplerate,
4685 "pcm_extraction_channels", &dst_channels,
4686 "pcm_extraction_depth", &dst_depth,
4690 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4691 caps = gst_caps_new_simple("audio/x-raw",
4692 "rate", G_TYPE_INT, dst_samplerate,
4693 "channels", G_TYPE_INT, dst_channels,
4694 "depth", G_TYPE_INT, dst_depth,
4696 caps_str = gst_caps_to_string(caps);
4697 LOGD("new caps : %s\n", caps_str);
4699 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4702 gst_caps_unref(caps);
4703 MMPLAYER_FREEIF(caps_str);
4706 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4709 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4713 //GstCaps* caps = NULL;
4716 /* for logical volume control */
4717 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4718 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4720 if (player->sound.mute) {
4721 LOGD("mute enabled\n");
4722 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4727 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4728 caps = gst_caps_from_string("audio/x-raw-int, "
4729 "endianness = (int) LITTLE_ENDIAN, "
4730 "signed = (boolean) true, "
4731 "width = (int) 16, "
4732 "depth = (int) 16");
4733 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4734 gst_caps_unref(caps);
4737 /* chech if multi-chennels */
4738 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4739 GstPad *srcpad = NULL;
4740 GstCaps *caps = NULL;
4742 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4743 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4744 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4745 GstStructure *str = gst_caps_get_structure(caps, 0);
4747 gst_structure_get_int(str, "channels", &channels);
4748 gst_caps_unref(caps);
4750 gst_object_unref(srcpad);
4754 /* audio effect element. if audio effect is enabled */
4755 if ((strcmp(player->ini.audioeffect_element, ""))
4757 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4758 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4760 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4762 if ((!player->bypass_audio_effect)
4763 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4764 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4765 if (!_mmplayer_audio_effect_custom_apply(player))
4766 LOGI("apply audio effect(custom) setting success\n");
4770 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4771 && (player->set_mode.rich_audio))
4772 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4775 /* create audio sink */
4776 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4779 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4780 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4783 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4784 (player->videodec_linked && player->ini.use_system_clock)) {
4785 LOGD("system clock will be used.\n");
4786 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4789 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4790 __mmplayer_gst_set_audiosink_property(player, attrs);
4793 if (audiobin[MMPLAYER_A_SINK].gst) {
4794 GstPad *sink_pad = NULL;
4795 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4796 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4797 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4798 gst_object_unref(GST_OBJECT(sink_pad));
4801 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4803 /* adding created elements to bin */
4804 LOGD("adding created elements to bin\n");
4805 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4806 LOGE("failed to add elements\n");
4810 /* linking elements in the bucket by added order. */
4811 LOGD("Linking elements in the bucket by added order.\n");
4812 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4813 LOGE("failed to link elements\n");
4817 /* get first element's sinkpad for creating ghostpad */
4818 first_element = (MMPlayerGstElement *)element_bucket->data;
4819 if (!first_element) {
4820 LOGE("failed to get first elem\n");
4824 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4826 LOGE("failed to get pad from first element of audiobin\n");
4830 ghostpad = gst_ghost_pad_new("sink", pad);
4832 LOGE("failed to create ghostpad\n");
4836 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4837 LOGE("failed to add ghostpad to audiobin\n");
4841 gst_object_unref(pad);
4843 g_list_free(element_bucket);
4845 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4849 return MM_ERROR_NONE;
4853 LOGD("ERROR : releasing audiobin\n");
4856 gst_object_unref(GST_OBJECT(pad));
4859 gst_object_unref(GST_OBJECT(ghostpad));
4862 g_list_free(element_bucket);
4864 /* release element which are not added to bin */
4865 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4866 /* NOTE : skip bin */
4867 if (audiobin[i].gst) {
4868 GstObject* parent = NULL;
4869 parent = gst_element_get_parent(audiobin[i].gst);
4872 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4873 audiobin[i].gst = NULL;
4875 gst_object_unref(GST_OBJECT(parent));
4879 /* release audiobin with it's childs */
4880 if (audiobin[MMPLAYER_A_BIN].gst)
4881 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4883 MMPLAYER_FREEIF(audiobin);
4885 player->pipeline->audiobin = NULL;
4887 return MM_ERROR_PLAYER_INTERNAL;
4890 static GstPadProbeReturn
4891 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4893 mm_player_t* player = (mm_player_t*) u_data;
4894 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4895 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4897 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4899 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4900 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4902 return GST_PAD_PROBE_OK;
4905 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4907 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4910 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4912 int ret = MM_ERROR_NONE;
4914 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4915 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4917 MMPLAYER_VIDEO_BO_LOCK(player);
4919 if (player->video_bo_list) {
4920 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4921 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4922 if (tmp && tmp->bo == bo) {
4924 LOGD("release bo %p", bo);
4925 MMPLAYER_VIDEO_BO_UNLOCK(player);
4926 MMPLAYER_VIDEO_BO_SIGNAL(player);
4931 /* hw codec is running or the list was reset for DRC. */
4932 LOGW("there is no bo list.");
4934 MMPLAYER_VIDEO_BO_UNLOCK(player);
4936 LOGW("failed to find bo %p", bo);
4941 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4946 MMPLAYER_RETURN_IF_FAIL(player);
4948 MMPLAYER_VIDEO_BO_LOCK(player);
4949 if (player->video_bo_list) {
4950 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4951 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4952 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4955 tbm_bo_unref(tmp->bo);
4959 g_list_free(player->video_bo_list);
4960 player->video_bo_list = NULL;
4962 player->video_bo_size = 0;
4963 MMPLAYER_VIDEO_BO_UNLOCK(player);
4970 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4973 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4974 gboolean ret = TRUE;
4976 /* check DRC, if it is, destroy the prev bo list to create again */
4977 if (player->video_bo_size != size) {
4978 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4979 __mmplayer_video_stream_destroy_bo_list(player);
4980 player->video_bo_size = size;
4983 MMPLAYER_VIDEO_BO_LOCK(player);
4985 if ((!player->video_bo_list) ||
4986 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4988 /* create bo list */
4990 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4992 if (player->video_bo_list) {
4993 /* if bo list did not created all, try it again. */
4994 idx = g_list_length(player->video_bo_list);
4995 LOGD("bo list exist(len: %d)", idx);
4998 for (; idx < player->ini.num_of_video_bo; idx++) {
4999 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
5001 LOGE("Fail to alloc bo_info.");
5004 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
5006 LOGE("Fail to tbm_bo_alloc.");
5010 bo_info->using = FALSE;
5011 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
5014 /* update video num buffers */
5015 player->video_num_buffers = idx;
5016 if (idx == player->ini.num_of_video_bo)
5017 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
5020 MMPLAYER_VIDEO_BO_UNLOCK(player);
5024 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
5028 /* get bo from list*/
5029 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
5030 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
5031 if (tmp && (tmp->using == FALSE)) {
5032 LOGD("found bo %p to use", tmp->bo);
5034 MMPLAYER_VIDEO_BO_UNLOCK(player);
5039 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5040 MMPLAYER_VIDEO_BO_UNLOCK(player);
5044 if (player->ini.video_bo_timeout <= 0) {
5045 MMPLAYER_VIDEO_BO_WAIT(player);
5047 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5048 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5055 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5057 mm_player_t* player = (mm_player_t*)data;
5059 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5061 /* send prerolled pkt */
5062 player->video_stream_prerolled = FALSE;
5064 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5066 /* not to send prerolled pkt again */
5067 player->video_stream_prerolled = TRUE;
5071 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5073 mm_player_t* player = (mm_player_t*)data;
5074 GstCaps *caps = NULL;
5075 MMPlayerVideoStreamDataType stream;
5076 MMVideoBuffer *video_buffer = NULL;
5077 GstMemory *dataBlock = NULL;
5078 GstMemory *metaBlock = NULL;
5079 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5080 GstStructure *structure = NULL;
5081 const gchar *string_format = NULL;
5082 unsigned int fourcc = 0;
5085 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5087 if (player->video_stream_prerolled) {
5088 player->video_stream_prerolled = FALSE;
5089 LOGD("skip the prerolled pkt not to send it again");
5093 caps = gst_pad_get_current_caps(pad);
5095 LOGE("Caps is NULL.");
5099 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5101 /* clear stream data structure */
5102 memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
5104 structure = gst_caps_get_structure(caps, 0);
5105 gst_structure_get_int(structure, "width", & (stream.width));
5106 gst_structure_get_int(structure, "height", & (stream.height));
5107 string_format = gst_structure_get_string(structure, "format");
5109 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5110 stream.format = util_get_pixtype(fourcc);
5111 gst_caps_unref(caps);
5115 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5116 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5119 if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
5120 LOGE("Wrong condition!!");
5124 /* set size and timestamp */
5125 dataBlock = gst_buffer_peek_memory(buffer, 0);
5126 stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5127 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5129 /* check zero-copy */
5130 if (player->set_mode.video_zc &&
5131 player->set_mode.media_packet_video_stream &&
5132 gst_buffer_n_memory(buffer) > 1) {
5133 metaBlock = gst_buffer_peek_memory(buffer, 1);
5134 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5135 video_buffer = (MMVideoBuffer *)mapinfo.data;
5138 if (video_buffer) { /* hw codec */
5140 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5141 /* copy pointer of tbm bo, stride, elevation */
5142 memcpy(stream.bo, video_buffer->handle.bo,
5143 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5144 } else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
5145 /* FIXME: need to check this path */
5146 memcpy(stream.data, video_buffer->data,
5147 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5149 memcpy(stream.stride, video_buffer->stride_width,
5150 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5151 memcpy(stream.elevation, video_buffer->stride_height,
5152 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5153 /* set gst buffer */
5154 stream.internal_buffer = buffer;
5155 } else { /* sw codec */
5156 tbm_bo_handle thandle;
5157 int stride = GST_ROUND_UP_4(stream.width);
5158 int elevation = stream.height;
5162 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5164 LOGE("fail to gst_memory_map");
5168 stream.stride[0] = stride;
5169 stream.elevation[0] = elevation;
5170 if (stream.format == MM_PIXEL_FORMAT_I420) {
5171 stream.stride[1] = stream.stride[2] = GST_ROUND_UP_4(GST_ROUND_UP_2(stream.width) / 2);
5172 stream.elevation[1] = stream.elevation[2] = stream.height / 2;
5173 size = stream.stride[0] * stream.elevation[0] + stream.stride[1] * stream.elevation[1] + stream.stride[2] * stream.elevation[2];
5174 } else if (stream.format == MM_PIXEL_FORMAT_RGBA) {
5175 stream.stride[0] = stream.width * 4;
5176 size = stream.stride[0] * stream.height;
5178 LOGE("Not support format %d", stream.format);
5179 gst_memory_unmap(dataBlock, &mapinfo);
5182 stream.bo[0] = __mmplayer_video_stream_get_bo(player, size);
5183 if (!stream.bo[0]) {
5184 LOGE("Fail to tbm_bo_alloc!!");
5185 gst_memory_unmap(dataBlock, &mapinfo);
5188 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5189 if (thandle.ptr && mapinfo.data)
5190 memcpy(thandle.ptr, mapinfo.data, size);
5192 LOGE("data pointer is wrong. dest : %p, src : %p",
5193 thandle.ptr, mapinfo.data);
5194 tbm_bo_unmap(stream.bo[0]);
5197 if (player->video_stream_cb)
5198 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
5201 gst_memory_unmap(metaBlock, &mapinfo);
5203 gst_memory_unmap(dataBlock, &mapinfo);
5209 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5211 MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5212 gchar* video_csc = "videoconvert"; // default colorspace converter
5213 GList* element_bucket = *bucket;
5215 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5219 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", (int *)&surface_type);
5221 if (player->set_mode.video_zc) {
5222 video_csc = ""; /* videosinks don't use videoconvert normally */
5224 /* sw codec, if player use libav, waylandsink need videoconvert to render shm wl-buffer which support RGB only */
5225 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (!strncmp(player->ini.videosink_element_overlay, "waylandsink", strlen(player->ini.videosink_element_overlay))))
5226 video_csc = "videoconvert";
5228 if (video_csc && (strcmp(video_csc, ""))) {
5229 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5230 LOGD("using video converter: %s", video_csc);
5233 /* set video rotator */
5234 if (!player->set_mode.video_zc)
5235 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5237 *bucket = element_bucket;
5239 return MM_ERROR_NONE;
5244 return MM_ERROR_PLAYER_INTERNAL;
5248 * This function is to create video pipeline.
5250 * @param player [in] handle of player
5251 * caps [in] src caps of decoder
5252 * surface_type [in] surface type for video rendering
5254 * @return This function returns zero on success.
5256 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5260 * - video overlay surface(arm/x86) : waylandsink
5263 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5267 GList*element_bucket = NULL;
5268 MMPlayerGstElement* first_element = NULL;
5269 MMPlayerGstElement* videobin = NULL;
5270 gchar *videosink_element = NULL;
5274 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5277 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5279 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5281 player->pipeline->videobin = videobin;
5283 attrs = MMPLAYER_GET_ATTRS(player);
5285 LOGE("cannot get content attribute");
5286 return MM_ERROR_PLAYER_INTERNAL;
5290 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5291 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5292 if (!videobin[MMPLAYER_V_BIN].gst) {
5293 LOGE("failed to create videobin");
5297 int enable_video_decoded_cb = 0;
5298 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5300 /* set video sink */
5301 switch (surface_type) {
5302 case MM_DISPLAY_SURFACE_OVERLAY:
5303 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5305 if (strlen(player->ini.videosink_element_overlay) > 0)
5306 videosink_element = player->ini.videosink_element_overlay;
5310 case MM_DISPLAY_SURFACE_NULL:
5311 if (strlen(player->ini.videosink_element_fake) > 0)
5312 videosink_element = player->ini.videosink_element_fake;
5316 case MM_DISPLAY_SURFACE_REMOTE:
5317 if (strlen(player->ini.videosink_element_fake) > 0)
5318 videosink_element = player->ini.videosink_element_fake;
5323 LOGE("unidentified surface type");
5326 LOGD("selected videosink name: %s", videosink_element);
5328 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5330 /* additional setting for sink plug-in */
5331 switch (surface_type) {
5332 case MM_DISPLAY_SURFACE_OVERLAY:
5334 bool use_tbm = player->set_mode.video_zc;
5336 LOGD("selected videosink name: %s", videosink_element);
5338 /* support shard memory with S/W codec on HawkP */
5339 if (strncmp(videosink_element, "waylandsink", strlen(videosink_element)) == 0) {
5340 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5341 "use-tbm", use_tbm, NULL);
5347 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5350 LOGD("disable last-sample");
5351 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5355 if (player->set_mode.media_packet_video_stream) {
5357 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5359 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5361 MMPLAYER_SIGNAL_CONNECT(player,
5362 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5363 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5365 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5368 MMPLAYER_SIGNAL_CONNECT(player,
5369 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5370 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5372 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5377 case MM_DISPLAY_SURFACE_REMOTE:
5379 if (player->set_mode.media_packet_video_stream) {
5380 LOGE("add data probe at videosink");
5381 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5382 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5384 MMPLAYER_SIGNAL_CONNECT(player,
5385 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5386 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5388 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5391 MMPLAYER_SIGNAL_CONNECT(player,
5392 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5393 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5395 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5400 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5403 LOGD("disable last-sample");
5404 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5414 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5417 if (videobin[MMPLAYER_V_SINK].gst) {
5418 GstPad *sink_pad = NULL;
5419 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5421 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5422 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5423 gst_object_unref(GST_OBJECT(sink_pad));
5425 LOGW("failed to get sink pad from videosink\n");
5428 /* store it as it's sink element */
5429 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5431 /* adding created elements to bin */
5432 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5433 LOGE("failed to add elements\n");
5437 /* Linking elements in the bucket by added order */
5438 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5439 LOGE("failed to link elements\n");
5443 /* get first element's sinkpad for creating ghostpad */
5445 first_element = (MMPlayerGstElement *)element_bucket->data;
5446 if (!first_element) {
5447 LOGE("failed to get first element from bucket\n");
5451 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5453 LOGE("failed to get pad from first element\n");
5457 /* create ghostpad */
5458 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5459 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5460 LOGE("failed to add ghostpad to videobin\n");
5463 gst_object_unref(pad);
5465 /* done. free allocated variables */
5467 g_list_free(element_bucket);
5471 return MM_ERROR_NONE;
5474 LOGE("ERROR : releasing videobin\n");
5476 g_list_free(element_bucket);
5479 gst_object_unref(GST_OBJECT(pad));
5481 /* release videobin with it's childs */
5482 if (videobin[MMPLAYER_V_BIN].gst)
5483 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5486 MMPLAYER_FREEIF(videobin);
5488 player->pipeline->videobin = NULL;
5490 return MM_ERROR_PLAYER_INTERNAL;
5493 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5495 GList *element_bucket = NULL;
5496 MMPlayerGstElement *textbin = player->pipeline->textbin;
5498 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5499 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5500 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5501 "signal-handoffs", FALSE,
5504 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5505 MMPLAYER_SIGNAL_CONNECT(player,
5506 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5507 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5509 G_CALLBACK(__mmplayer_update_subtitle),
5512 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5513 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5514 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5516 if (!player->play_subtitle) {
5517 LOGD("add textbin sink as sink element of whole pipeline.\n");
5518 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5521 /* adding created elements to bin */
5522 LOGD("adding created elements to bin\n");
5523 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5524 LOGE("failed to add elements\n");
5528 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5529 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5530 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5532 /* linking elements in the bucket by added order. */
5533 LOGD("Linking elements in the bucket by added order.\n");
5534 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5535 LOGE("failed to link elements\n");
5539 /* done. free allocated variables */
5540 g_list_free(element_bucket);
5542 if (textbin[MMPLAYER_T_QUEUE].gst) {
5544 GstPad *ghostpad = NULL;
5546 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5548 LOGE("failed to get sink pad of text queue");
5552 ghostpad = gst_ghost_pad_new("text_sink", pad);
5553 gst_object_unref(pad);
5556 LOGE("failed to create ghostpad of textbin\n");
5560 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5561 LOGE("failed to add ghostpad to textbin\n");
5562 gst_object_unref(ghostpad);
5567 return MM_ERROR_NONE;
5570 g_list_free(element_bucket);
5572 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5573 LOGE("remove textbin sink from sink list");
5574 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5577 /* release element at __mmplayer_gst_create_text_sink_bin */
5578 return MM_ERROR_PLAYER_INTERNAL;
5581 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5583 MMPlayerGstElement *textbin = NULL;
5584 GList *element_bucket = NULL;
5585 int surface_type = 0;
5590 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5593 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5595 LOGE("failed to allocate memory for textbin\n");
5596 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5600 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5601 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5602 if (!textbin[MMPLAYER_T_BIN].gst) {
5603 LOGE("failed to create textbin\n");
5608 player->pipeline->textbin = textbin;
5611 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5612 LOGD("surface type for subtitle : %d", surface_type);
5613 switch (surface_type) {
5614 case MM_DISPLAY_SURFACE_OVERLAY:
5615 case MM_DISPLAY_SURFACE_NULL:
5616 case MM_DISPLAY_SURFACE_REMOTE:
5617 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5618 LOGE("failed to make plain text elements\n");
5629 return MM_ERROR_NONE;
5633 LOGD("ERROR : releasing textbin\n");
5635 g_list_free(element_bucket);
5637 /* release signal */
5638 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5640 /* release element which are not added to bin */
5641 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5642 /* NOTE : skip bin */
5643 if (textbin[i].gst) {
5644 GstObject* parent = NULL;
5645 parent = gst_element_get_parent(textbin[i].gst);
5648 gst_object_unref(GST_OBJECT(textbin[i].gst));
5649 textbin[i].gst = NULL;
5651 gst_object_unref(GST_OBJECT(parent));
5656 /* release textbin with it's childs */
5657 if (textbin[MMPLAYER_T_BIN].gst)
5658 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5660 MMPLAYER_FREEIF(player->pipeline->textbin);
5661 player->pipeline->textbin = NULL;
5664 return MM_ERROR_PLAYER_INTERNAL;
5669 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5671 MMPlayerGstElement* mainbin = NULL;
5672 MMPlayerGstElement* textbin = NULL;
5673 MMHandleType attrs = 0;
5674 GstElement *subsrc = NULL;
5675 GstElement *subparse = NULL;
5676 gchar *subtitle_uri = NULL;
5677 const gchar *charset = NULL;
5683 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5685 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5687 mainbin = player->pipeline->mainbin;
5689 attrs = MMPLAYER_GET_ATTRS(player);
5691 LOGE("cannot get content attribute\n");
5692 return MM_ERROR_PLAYER_INTERNAL;
5695 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5696 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5697 LOGE("subtitle uri is not proper filepath.\n");
5698 return MM_ERROR_PLAYER_INVALID_URI;
5701 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5702 LOGE("failed to get storage info of subtitle path");
5703 return MM_ERROR_PLAYER_INVALID_URI;
5706 LOGD("subtitle file path is [%s].\n", subtitle_uri);
5708 /* create the subtitle source */
5709 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5711 LOGE("failed to create filesrc element\n");
5714 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5716 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5717 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5719 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5720 LOGW("failed to add queue\n");
5721 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5722 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5723 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5728 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5730 LOGE("failed to create subparse element\n");
5734 charset = util_get_charset(subtitle_uri);
5736 LOGD("detected charset is %s\n", charset);
5737 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5740 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5741 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5743 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5744 LOGW("failed to add subparse\n");
5745 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5746 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5747 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5751 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5752 LOGW("failed to link subsrc and subparse\n");
5756 player->play_subtitle = TRUE;
5757 player->adjust_subtitle_pos = 0;
5759 LOGD("play subtitle using subtitle file\n");
5761 if (player->pipeline->textbin == NULL) {
5762 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5763 LOGE("failed to create text sink bin. continuing without text\n");
5767 textbin = player->pipeline->textbin;
5769 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5770 LOGW("failed to add textbin\n");
5772 /* release signal */
5773 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5775 /* release textbin with it's childs */
5776 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5777 MMPLAYER_FREEIF(player->pipeline->textbin);
5778 player->pipeline->textbin = textbin = NULL;
5782 LOGD("link text input selector and textbin ghost pad");
5784 player->textsink_linked = 1;
5785 player->external_text_idx = 0;
5786 LOGI("player->textsink_linked set to 1\n");
5788 textbin = player->pipeline->textbin;
5789 LOGD("text bin has been created. reuse it.");
5790 player->external_text_idx = 1;
5793 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5794 LOGW("failed to link subparse and textbin\n");
5798 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5800 LOGE("failed to get sink pad from textsink to probe data");
5804 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5805 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5807 gst_object_unref(pad);
5810 /* create dot. for debugging */
5811 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5814 return MM_ERROR_NONE;
5817 /* release text pipeline resource */
5818 player->textsink_linked = 0;
5820 /* release signal */
5821 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5823 if (player->pipeline->textbin) {
5824 LOGE("remove textbin");
5826 /* release textbin with it's childs */
5827 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5828 MMPLAYER_FREEIF(player->pipeline->textbin);
5829 player->pipeline->textbin = NULL;
5833 /* release subtitle elem */
5834 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5835 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5837 return MM_ERROR_PLAYER_INTERNAL;
5841 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5843 mm_player_t* player = (mm_player_t*) data;
5844 MMMessageParamType msg = {0, };
5845 GstClockTime duration = 0;
5846 gpointer text = NULL;
5847 guint text_size = 0;
5848 gboolean ret = TRUE;
5849 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5853 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5854 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5856 if (player->is_subtitle_force_drop)
5858 LOGW("subtitle is dropped forcedly.");
5862 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5863 text = mapinfo.data;
5864 text_size = mapinfo.size;
5865 duration = GST_BUFFER_DURATION(buffer);
5867 if (player->set_mode.subtitle_off) {
5868 LOGD("subtitle is OFF.\n");
5872 if (!text || (text_size == 0)) {
5873 LOGD("There is no subtitle to be displayed.\n");
5877 msg.data = (void *) text;
5878 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5880 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5882 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5883 gst_buffer_unmap(buffer, &mapinfo);
5890 static GstPadProbeReturn
5891 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5894 mm_player_t *player = (mm_player_t *) u_data;
5895 GstClockTime cur_timestamp = 0;
5896 gint64 adjusted_timestamp = 0;
5897 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5899 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5901 if (player->set_mode.subtitle_off) {
5902 LOGD("subtitle is OFF.\n");
5906 if (player->adjust_subtitle_pos == 0) {
5907 LOGD("nothing to do");
5911 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5912 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5914 if (adjusted_timestamp < 0) {
5915 LOGD("adjusted_timestamp under zero");
5920 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5921 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5922 GST_TIME_ARGS(cur_timestamp),
5923 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5925 return GST_PAD_PROBE_OK;
5927 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5931 /* check player and subtitlebin are created */
5932 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5933 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5935 if (position == 0) {
5936 LOGD("nothing to do\n");
5938 return MM_ERROR_NONE;
5942 case MM_PLAYER_POS_FORMAT_TIME:
5944 /* check current postion */
5945 player->adjust_subtitle_pos = position;
5947 LOGD("save adjust_subtitle_pos in player") ;
5953 LOGW("invalid format.\n");
5955 return MM_ERROR_INVALID_ARGUMENT;
5961 return MM_ERROR_NONE;
5963 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5966 LOGD("adjusting video_pos in player") ;
5967 int current_pos = 0;
5968 /* check player and videobin are created */
5969 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5970 if (!player->pipeline->videobin ||
5971 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5972 LOGD("no video pipeline or sink is there");
5973 return MM_ERROR_PLAYER_INVALID_STATE ;
5976 LOGD("nothing to do\n");
5978 return MM_ERROR_NONE;
5980 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
5981 LOGD("failed to get current position");
5982 return MM_ERROR_PLAYER_INTERNAL;
5984 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
5985 LOGD("enter video delay is valid");
5987 LOGD("enter video delay is crossing content boundary");
5988 return MM_ERROR_INVALID_ARGUMENT ;
5990 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
5991 LOGD("video delay has been done");
5994 return MM_ERROR_NONE;
5998 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6000 GstElement *appsrc = element;
6001 tBuffer *buf = (tBuffer *)user_data;
6002 GstBuffer *buffer = NULL;
6003 GstFlowReturn ret = GST_FLOW_OK;
6006 MMPLAYER_RETURN_IF_FAIL(element);
6007 MMPLAYER_RETURN_IF_FAIL(buf);
6009 buffer = gst_buffer_new();
6011 if (buf->offset >= buf->len) {
6012 LOGD("call eos appsrc\n");
6013 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6017 if (buf->len - buf->offset < size)
6018 len = buf->len - buf->offset;
6020 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6021 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6022 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6024 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6025 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6031 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6033 tBuffer *buf = (tBuffer *)user_data;
6035 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6037 buf->offset = (int)size;
6042 static GstBusSyncReply
6043 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6045 mm_player_t *player = (mm_player_t *)data;
6046 GstBusSyncReply reply = GST_BUS_DROP;
6048 if (!(player->pipeline && player->pipeline->mainbin)) {
6049 LOGE("player pipeline handle is null");
6050 return GST_BUS_PASS;
6053 if (!__mmplayer_check_useful_message(player, message)) {
6054 gst_message_unref(message);
6055 return GST_BUS_DROP;
6058 switch (GST_MESSAGE_TYPE(message)) {
6059 case GST_MESSAGE_STATE_CHANGED:
6060 /* post directly for fast launch */
6061 if (player->sync_handler) {
6062 __mmplayer_gst_callback(NULL, message, player);
6063 reply = GST_BUS_DROP;
6065 reply = GST_BUS_PASS;
6067 case GST_MESSAGE_TAG:
6068 __mmplayer_gst_extract_tag_from_msg(player, message);
6072 GstTagList *tags = NULL;
6074 gst_message_parse_tag(message, &tags);
6076 LOGE("TAGS received from element \"%s\".\n",
6077 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6079 gst_tag_list_foreach(tags, print_tag, NULL);
6080 gst_tag_list_free(tags);
6088 case GST_MESSAGE_DURATION_CHANGED:
6089 __mmplayer_gst_handle_duration(player, message);
6091 case GST_MESSAGE_ASYNC_DONE:
6092 /* NOTE:Don't call gst_callback directly
6093 * because previous frame can be showed even though this message is received for seek.
6096 reply = GST_BUS_PASS;
6100 if (reply == GST_BUS_DROP)
6101 gst_message_unref(message);
6107 __mmplayer_gst_create_decoder(mm_player_t *player,
6108 MMPlayerTrackType track,
6110 enum MainElementID elemId,
6113 gboolean ret = TRUE;
6114 GstPad *sinkpad = NULL;
6118 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6120 player->pipeline->mainbin, FALSE);
6121 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6122 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6123 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6125 GstElement *decodebin = NULL;
6126 GstCaps *dec_caps = NULL;
6128 /* create decodebin */
6129 decodebin = gst_element_factory_make("decodebin", name);
6132 LOGE("error : fail to create decodebin for %d decoder\n", track);
6137 /* raw pad handling signal */
6138 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6139 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6141 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6142 before looking for any elements that can handle that stream.*/
6143 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6144 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6146 /* This signal is emitted when a element is added to the bin.*/
6147 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6148 G_CALLBACK(__mmplayer_gst_element_added), player);
6150 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6151 LOGE("failed to add new decodebin\n");
6156 dec_caps = gst_pad_query_caps(srcpad, NULL);
6158 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6159 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6160 gst_caps_unref(dec_caps);
6163 player->pipeline->mainbin[elemId].id = elemId;
6164 player->pipeline->mainbin[elemId].gst = decodebin;
6166 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6168 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6169 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6170 gst_object_unref(GST_OBJECT(decodebin));
6173 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6174 LOGE("failed to sync second level decodebin state with parent\n");
6176 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6180 gst_object_unref(GST_OBJECT(sinkpad));
6189 * This function is to create audio or video pipeline for playing.
6191 * @param player [in] handle of player
6193 * @return This function returns zero on success.
6198 __mmplayer_gst_create_pipeline(mm_player_t* player)
6201 MMPlayerGstElement *mainbin = NULL;
6202 MMHandleType attrs = 0;
6203 GstElement* element = NULL;
6204 GstElement* elem_src_audio = NULL;
6205 GstElement* elem_src_subtitle = NULL;
6206 GstElement* es_video_queue = NULL;
6207 GstElement* es_audio_queue = NULL;
6208 GstElement* es_subtitle_queue = NULL;
6209 GList* element_bucket = NULL;
6210 gboolean need_state_holder = TRUE;
6212 #ifdef SW_CODEC_ONLY
6213 int surface_type = 0;
6217 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6219 /* get profile attribute */
6220 attrs = MMPLAYER_GET_ATTRS(player);
6222 LOGE("cannot get content attribute\n");
6226 /* create pipeline handles */
6227 if (player->pipeline) {
6228 LOGW("pipeline should be released before create new one\n");
6232 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6233 if (player->pipeline == NULL)
6236 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo));
6239 /* create mainbin */
6240 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6241 if (mainbin == NULL)
6244 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6246 /* create pipeline */
6247 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6248 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6249 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6250 LOGE("failed to create pipeline\n");
6253 player->demux_pad_index = 0;
6254 player->subtitle_language_list = NULL;
6256 player->is_subtitle_force_drop = FALSE;
6257 player->last_multiwin_status = FALSE;
6259 _mmplayer_track_initialize(player);
6260 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6262 /* create source element */
6263 switch (player->profile.uri_type) {
6264 /* rtsp streamming */
6265 case MM_PLAYER_URI_TYPE_URL_RTSP:
6267 gint network_bandwidth;
6268 gchar *user_agent, *wap_profile;
6270 element = gst_element_factory_make("rtspsrc", "rtsp source");
6273 LOGE("failed to create streaming source element\n");
6278 network_bandwidth = 0;
6279 user_agent = wap_profile = NULL;
6282 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6283 mm_attrs_get_string_by_name(attrs, "streaming_wap_profile", &wap_profile);
6284 mm_attrs_get_int_by_name(attrs, "streaming_network_bandwidth", &network_bandwidth);
6286 SECURE_LOGD("user_agent : %s\n", user_agent);
6287 SECURE_LOGD("wap_profile : %s\n", wap_profile);
6289 /* setting property to streaming source */
6290 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6292 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6294 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6296 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6297 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6298 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6299 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6301 player->use_decodebin = FALSE;
6306 case MM_PLAYER_URI_TYPE_URL_HTTP:
6308 gchar *user_agent, *proxy, *cookies, **cookie_list;
6309 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6310 user_agent = proxy = cookies = NULL;
6312 gint mode = MM_PLAYER_PD_MODE_NONE;
6314 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6316 player->pd_mode = mode;
6318 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6320 if (!MMPLAYER_IS_HTTP_PD(player)) {
6321 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6323 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6326 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6329 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6330 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6331 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
6332 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6334 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6335 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6336 LOGD("get timeout from ini\n");
6337 http_timeout = player->ini.http_timeout;
6341 SECURE_LOGD("location : %s\n", player->profile.uri);
6342 SECURE_LOGD("cookies : %s\n", cookies);
6343 SECURE_LOGD("proxy : %s\n", proxy);
6344 SECURE_LOGD("user_agent : %s\n", user_agent);
6345 LOGD("timeout : %d\n", http_timeout);
6347 /* setting property to streaming source */
6348 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6349 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6350 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6352 /* check if prosy is vailid or not */
6353 if (util_check_valid_url(proxy))
6354 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6355 /* parsing cookies */
6356 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
6357 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6359 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6361 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6362 LOGW("it's dash. and it's still experimental feature.");
6364 // progressive download
6365 gchar* location = NULL;
6367 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6370 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6372 MMPLAYER_FREEIF(player->pd_file_save_path);
6374 LOGD("PD Location : %s\n", path);
6377 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6378 LOGE("failed to get storage info");
6381 player->pd_file_save_path = g_strdup(path);
6383 LOGE("can't find pd location so, it should be set \n");
6388 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6390 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6394 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6395 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6397 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6398 g_object_get(element, "location", &location, NULL);
6399 LOGD("PD_LOCATION [%s].\n", location);
6407 case MM_PLAYER_URI_TYPE_FILE:
6409 LOGD("using filesrc for 'file://' handler.\n");
6410 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6411 LOGE("failed to get storage info");
6415 element = gst_element_factory_make("filesrc", "source");
6417 LOGE("failed to create filesrc\n");
6421 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6425 case MM_PLAYER_URI_TYPE_SS:
6427 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6428 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6430 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6434 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6436 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6437 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6438 LOGD("get timeout from ini\n");
6439 http_timeout = player->ini.http_timeout;
6442 /* setting property to streaming source */
6443 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6444 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6447 case MM_PLAYER_URI_TYPE_MS_BUFF:
6449 LOGD("MS buff src is selected\n");
6451 if (player->v_stream_caps) {
6452 element = gst_element_factory_make("appsrc", "video_appsrc");
6454 LOGF("failed to create video app source element[appsrc].\n");
6458 if (player->a_stream_caps) {
6459 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6460 if (!elem_src_audio) {
6461 LOGF("failed to create audio app source element[appsrc].\n");
6465 } else if (player->a_stream_caps) {
6466 /* no video, only audio pipeline*/
6467 element = gst_element_factory_make("appsrc", "audio_appsrc");
6469 LOGF("failed to create audio app source element[appsrc].\n");
6474 if (player->s_stream_caps) {
6475 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6476 if (!elem_src_subtitle) {
6477 LOGF("failed to create subtitle app source element[appsrc].\n");
6482 LOGD("setting app sources properties.\n");
6483 LOGD("location : %s\n", player->profile.uri);
6485 if (player->v_stream_caps && element) {
6486 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6487 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6488 "caps", player->v_stream_caps, NULL);
6490 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6491 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6492 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6493 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6495 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6496 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6497 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6498 G_CALLBACK(__gst_seek_video_data), player);
6500 if (player->a_stream_caps && elem_src_audio) {
6501 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6502 "caps", player->a_stream_caps, NULL);
6504 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6505 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6506 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6507 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6509 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6510 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6511 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6512 G_CALLBACK(__gst_seek_audio_data), player);
6514 } else if (player->a_stream_caps && element) {
6515 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6516 "caps", player->a_stream_caps, NULL);
6518 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6519 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6520 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6521 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6523 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6524 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6525 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6526 G_CALLBACK(__gst_seek_audio_data), player);
6529 if (player->s_stream_caps && elem_src_subtitle) {
6530 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6531 "caps", player->s_stream_caps, NULL);
6533 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6534 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6535 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6536 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6538 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6540 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6541 G_CALLBACK(__gst_seek_subtitle_data), player);
6544 if (player->v_stream_caps && element) {
6545 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6546 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6547 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6548 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6550 if (player->a_stream_caps && elem_src_audio) {
6551 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6552 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6553 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6554 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6556 } else if (player->a_stream_caps && element) {
6557 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6558 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6559 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6560 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6563 if (player->s_stream_caps && elem_src_subtitle)
6564 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6565 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6567 need_state_holder = FALSE;
6569 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6570 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6571 LOGE("failed to commit\n");
6575 case MM_PLAYER_URI_TYPE_MEM:
6577 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6579 LOGD("mem src is selected\n");
6581 element = gst_element_factory_make("appsrc", "mem-source");
6583 LOGE("failed to create appsrc element\n");
6587 g_object_set(element, "stream-type", stream_type, NULL);
6588 g_object_set(element, "size", player->mem_buf.len, NULL);
6589 g_object_set(element, "blocksize", (guint64)20480, NULL);
6591 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6592 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf);
6593 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6594 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf);
6597 case MM_PLAYER_URI_TYPE_URL:
6600 case MM_PLAYER_URI_TYPE_TEMP:
6603 case MM_PLAYER_URI_TYPE_NONE:
6608 /* check source element is OK */
6610 LOGE("no source element was created.\n");
6614 /* take source element */
6615 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6616 mainbin[MMPLAYER_M_SRC].gst = element;
6617 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6619 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6620 player->streamer = __mm_player_streaming_create();
6621 __mm_player_streaming_initialize(player->streamer);
6624 if (MMPLAYER_IS_HTTP_PD(player)) {
6625 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
6627 LOGD("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
6628 element = gst_element_factory_make("queue2", "queue2");
6630 LOGE("failed to create http streaming buffer element\n");
6635 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6636 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6637 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6639 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6641 __mm_player_streaming_set_queue2(player->streamer,
6644 player->ini.http_max_size_bytes,
6647 player->ini.http_buffering_limit,
6648 MUXED_BUFFER_TYPE_MEM_QUEUE,
6652 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6653 if (player->v_stream_caps) {
6654 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6655 if (!es_video_queue) {
6656 LOGE("create es_video_queue for es player failed\n");
6659 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6660 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6661 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6662 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6664 /* Adding audio appsrc to bucket */
6665 if (player->a_stream_caps && elem_src_audio) {
6666 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6667 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6668 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6670 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6671 if (!es_audio_queue) {
6672 LOGE("create es_audio_queue for es player failed\n");
6675 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6677 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6678 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6679 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6681 } else if (player->a_stream_caps) {
6682 /* Only audio stream, no video */
6683 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6684 if (!es_audio_queue) {
6685 LOGE("create es_audio_queue for es player failed\n");
6688 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6689 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6690 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6693 if (player->s_stream_caps && elem_src_subtitle) {
6694 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6695 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6696 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6698 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6699 if (!es_subtitle_queue) {
6700 LOGE("create es_subtitle_queue for es player failed\n");
6703 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6704 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6705 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6709 /* create autoplugging element if src element is not a rtsp src */
6710 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6711 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
6712 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6714 enum MainElementID elemId = MMPLAYER_M_NUM;
6716 if ((player->use_decodebin) &&
6717 ((MMPLAYER_IS_HTTP_PD(player)) ||
6718 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6719 elemId = MMPLAYER_M_AUTOPLUG;
6720 element = __mmplayer_create_decodebin(player);
6722 /* default size of mq in decodebin is 2M
6723 * but it can cause blocking issue during seeking depends on content. */
6724 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6726 need_state_holder = FALSE;
6728 elemId = MMPLAYER_M_TYPEFIND;
6729 element = gst_element_factory_make("typefind", "typefinder");
6730 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6731 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6735 /* check autoplug element is OK */
6737 LOGE("can not create element(%d)\n", elemId);
6741 mainbin[elemId].id = elemId;
6742 mainbin[elemId].gst = element;
6744 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6747 /* add elements to pipeline */
6748 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6749 LOGE("Failed to add elements to pipeline\n");
6754 /* linking elements in the bucket by added order. */
6755 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6756 LOGE("Failed to link some elements\n");
6761 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6762 if (need_state_holder) {
6764 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6765 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6767 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6768 LOGE("fakesink element could not be created\n");
6771 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6773 /* take ownership of fakesink. we are reusing it */
6774 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6777 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6778 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6779 LOGE("failed to add fakesink to bin\n");
6784 /* now we have completed mainbin. take it */
6785 player->pipeline->mainbin = mainbin;
6787 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6788 GstPad *srcpad = NULL;
6790 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6791 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6793 __mmplayer_gst_create_decoder(player,
6794 MM_PLAYER_TRACK_TYPE_VIDEO,
6796 MMPLAYER_M_AUTOPLUG_V_DEC,
6799 gst_object_unref(GST_OBJECT(srcpad));
6804 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6805 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6807 __mmplayer_gst_create_decoder(player,
6808 MM_PLAYER_TRACK_TYPE_AUDIO,
6810 MMPLAYER_M_AUTOPLUG_A_DEC,
6813 gst_object_unref(GST_OBJECT(srcpad));
6818 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6819 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6822 /* connect bus callback */
6823 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6825 LOGE("cannot get bus from pipeline.\n");
6829 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
6831 player->context.thread_default = g_main_context_get_thread_default();
6833 if (NULL == player->context.thread_default) {
6834 player->context.thread_default = g_main_context_default();
6835 LOGD("thread-default context is the global default context");
6837 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6839 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6840 if (__mmplayer_check_subtitle(player)) {
6841 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6842 LOGE("fail to create text pipeline");
6845 /* set sync handler to get tag synchronously */
6846 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6849 gst_object_unref(GST_OBJECT(bus));
6850 g_list_free(element_bucket);
6854 return MM_ERROR_NONE;
6858 __mmplayer_gst_destroy_pipeline(player);
6859 g_list_free(element_bucket);
6862 /* release element which are not added to bin */
6863 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6864 /* NOTE : skip pipeline */
6865 if (mainbin[i].gst) {
6866 GstObject* parent = NULL;
6867 parent = gst_element_get_parent(mainbin[i].gst);
6870 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6871 mainbin[i].gst = NULL;
6873 gst_object_unref(GST_OBJECT(parent));
6877 /* release pipeline with it's childs */
6878 if (mainbin[MMPLAYER_M_PIPE].gst)
6879 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6881 MMPLAYER_FREEIF(mainbin);
6884 MMPLAYER_FREEIF(player->pipeline);
6885 return MM_ERROR_PLAYER_INTERNAL;
6889 __mmplayer_reset_gapless_state(mm_player_t* player)
6892 MMPLAYER_RETURN_IF_FAIL(player
6894 && player->pipeline->audiobin
6895 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6897 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6904 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6907 int ret = MM_ERROR_NONE;
6911 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6913 /* cleanup stuffs */
6914 MMPLAYER_FREEIF(player->type);
6915 player->have_dynamic_pad = FALSE;
6916 player->no_more_pad = FALSE;
6917 player->num_dynamic_pad = 0;
6918 player->demux_pad_index = 0;
6919 player->subtitle_language_list = NULL;
6920 player->use_deinterleave = FALSE;
6921 player->max_audio_channels = 0;
6922 player->video_share_api_delta = 0;
6923 player->video_share_clock_delta = 0;
6924 player->video_hub_download_mode = 0;
6925 __mmplayer_reset_gapless_state(player);
6927 if (player->streamer) {
6928 __mm_player_streaming_deinitialize(player->streamer);
6929 __mm_player_streaming_destroy(player->streamer);
6930 player->streamer = NULL;
6933 /* cleanup unlinked mime type */
6934 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6935 MMPLAYER_FREEIF(player->unlinked_video_mime);
6936 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6938 /* cleanup running stuffs */
6939 __mmplayer_cancel_eos_timer(player);
6941 /* cleanup gst stuffs */
6942 if (player->pipeline) {
6943 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6944 GstTagList* tag_list = player->pipeline->tag_list;
6946 /* first we need to disconnect all signal hander */
6947 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6949 /* disconnecting bus watch */
6950 if (player->bus_watcher)
6951 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
6952 player->bus_watcher = 0;
6955 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6956 MMPlayerGstElement* videobin = player->pipeline->videobin;
6957 MMPlayerGstElement* textbin = player->pipeline->textbin;
6958 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6959 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6960 gst_object_unref(bus);
6962 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6963 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6964 if (ret != MM_ERROR_NONE) {
6965 LOGE("fail to change state to NULL\n");
6966 return MM_ERROR_PLAYER_INTERNAL;
6969 LOGW("succeeded in chaning state to NULL\n");
6971 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6974 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6975 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6977 /* free avsysaudiosink
6978 avsysaudiosink should be unref when destory pipeline just after start play with BT.
6979 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6981 MMPLAYER_FREEIF(audiobin);
6982 MMPLAYER_FREEIF(videobin);
6983 MMPLAYER_FREEIF(textbin);
6984 MMPLAYER_FREEIF(mainbin);
6988 gst_tag_list_free(tag_list);
6990 MMPLAYER_FREEIF(player->pipeline);
6992 MMPLAYER_FREEIF(player->album_art);
6994 if (player->v_stream_caps) {
6995 gst_caps_unref(player->v_stream_caps);
6996 player->v_stream_caps = NULL;
6998 if (player->a_stream_caps) {
6999 gst_caps_unref(player->a_stream_caps);
7000 player->a_stream_caps = NULL;
7003 if (player->s_stream_caps) {
7004 gst_caps_unref(player->s_stream_caps);
7005 player->s_stream_caps = NULL;
7007 _mmplayer_track_destroy(player);
7009 if (player->sink_elements)
7010 g_list_free(player->sink_elements);
7011 player->sink_elements = NULL;
7013 if (player->bufmgr) {
7014 tbm_bufmgr_deinit(player->bufmgr);
7015 player->bufmgr = NULL;
7018 LOGW("finished destroy pipeline\n");
7025 static int __gst_realize(mm_player_t* player)
7028 int ret = MM_ERROR_NONE;
7032 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7034 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7036 ret = __mmplayer_gst_create_pipeline(player);
7038 LOGE("failed to create pipeline\n");
7042 /* set pipeline state to READY */
7043 /* NOTE : state change to READY must be performed sync. */
7044 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7045 ret = __mmplayer_gst_set_state(player,
7046 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7048 if (ret != MM_ERROR_NONE) {
7049 /* return error if failed to set state */
7050 LOGE("failed to set READY state");
7054 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7056 /* create dot before error-return. for debugging */
7057 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7064 static int __gst_unrealize(mm_player_t* player)
7066 int ret = MM_ERROR_NONE;
7070 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7072 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7073 MMPLAYER_PRINT_STATE(player);
7075 /* release miscellaneous information */
7076 __mmplayer_release_misc(player);
7078 /* destroy pipeline */
7079 ret = __mmplayer_gst_destroy_pipeline(player);
7080 if (ret != MM_ERROR_NONE) {
7081 LOGE("failed to destory pipeline\n");
7085 /* release miscellaneous information.
7086 these info needs to be released after pipeline is destroyed. */
7087 __mmplayer_release_misc_post(player);
7089 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7096 static int __gst_pending_seek(mm_player_t* player)
7098 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7099 int ret = MM_ERROR_NONE;
7103 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7105 if (!player->pending_seek.is_pending) {
7106 LOGD("pending seek is not reserved. nothing to do.\n");
7110 /* check player state if player could pending seek or not. */
7111 current_state = MMPLAYER_CURRENT_STATE(player);
7113 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7114 LOGW("try to pending seek in %s state, try next time. \n",
7115 MMPLAYER_STATE_GET_NAME(current_state));
7119 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7121 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7123 if (MM_ERROR_NONE != ret)
7124 LOGE("failed to seek pending postion. just keep staying current position.\n");
7126 player->pending_seek.is_pending = FALSE;
7133 static int __gst_start(mm_player_t* player)
7135 gboolean sound_extraction = 0;
7136 int ret = MM_ERROR_NONE;
7137 gboolean async = FALSE;
7141 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7143 /* get sound_extraction property */
7144 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7146 /* NOTE : if SetPosition was called before Start. do it now */
7147 /* streaming doesn't support it. so it should be always sync */
7148 /* !!create one more api to check if there is pending seek rather than checking variables */
7149 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7150 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7151 ret = __gst_pause(player, FALSE);
7152 if (ret != MM_ERROR_NONE) {
7153 LOGE("failed to set state to PAUSED for pending seek\n");
7157 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7159 if (sound_extraction) {
7160 LOGD("setting pcm extraction\n");
7162 ret = __mmplayer_set_pcm_extraction(player);
7163 if (MM_ERROR_NONE != ret) {
7164 LOGW("failed to set pcm extraction\n");
7168 if (MM_ERROR_NONE != __gst_pending_seek(player))
7169 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7173 LOGD("current state before doing transition");
7174 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7175 MMPLAYER_PRINT_STATE(player);
7177 /* set pipeline state to PLAYING */
7178 if (player->es_player_push_mode)
7180 /* set pipeline state to PLAYING */
7181 ret = __mmplayer_gst_set_state(player,
7182 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7184 if (ret == MM_ERROR_NONE) {
7185 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7187 LOGE("failed to set state to PLAYING");
7191 /* generating debug info before returning error */
7192 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7199 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7203 MMPLAYER_RETURN_IF_FAIL(player
7205 && player->pipeline->audiobin
7206 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7208 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", TRUE, NULL);
7215 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
7219 MMPLAYER_RETURN_IF_FAIL(player
7221 && player->pipeline->audiobin
7222 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7224 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", FALSE, NULL);
7229 static int __gst_stop(mm_player_t* player)
7231 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7232 MMHandleType attrs = 0;
7233 gboolean fadedown = FALSE;
7234 gboolean rewind = FALSE;
7236 int ret = MM_ERROR_NONE;
7237 gboolean async = FALSE;
7241 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7242 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7244 LOGD("current state before doing transition");
7245 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7246 MMPLAYER_PRINT_STATE(player);
7248 attrs = MMPLAYER_GET_ATTRS(player);
7250 LOGE("cannot get content attribute\n");
7251 return MM_ERROR_PLAYER_INTERNAL;
7254 mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7256 /* enable fadedown */
7257 if (fadedown || player->sound_focus.by_asm_cb)
7258 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7260 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7261 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7263 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7264 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7267 if (player->es_player_push_mode)
7270 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7272 /* disable fadeout */
7273 if (fadedown || player->sound_focus.by_asm_cb)
7274 __mmplayer_undo_sound_fadedown(player);
7276 /* return if set_state has failed */
7277 if (ret != MM_ERROR_NONE) {
7278 LOGE("failed to set state.\n");
7284 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7285 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7286 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7287 LOGW("failed to rewind\n");
7288 ret = MM_ERROR_PLAYER_SEEK;
7293 player->sent_bos = FALSE;
7295 if (player->es_player_push_mode) //for cloudgame
7298 /* wait for seek to complete */
7299 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7300 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7301 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7303 LOGE("fail to stop player.\n");
7304 ret = MM_ERROR_PLAYER_INTERNAL;
7305 __mmplayer_dump_pipeline_state(player);
7308 /* generate dot file if enabled */
7309 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7316 int __gst_pause(mm_player_t* player, gboolean async)
7318 int ret = MM_ERROR_NONE;
7322 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7323 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7325 LOGD("current state before doing transition");
7326 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7327 MMPLAYER_PRINT_STATE(player);
7329 /* set pipeline status to PAUSED */
7330 player->ignore_asyncdone = TRUE;
7332 ret = __mmplayer_gst_set_state(player,
7333 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7335 player->ignore_asyncdone = FALSE;
7337 if (FALSE == async) {
7338 if (ret != MM_ERROR_NONE) {
7339 GstMessage *msg = NULL;
7340 GTimer *timer = NULL;
7341 gdouble MAX_TIMEOUT_SEC = 3;
7343 LOGE("failed to set state to PAUSED");
7345 if (player->msg_posted) {
7346 LOGE("error msg is already posted.");
7350 timer = g_timer_new();
7351 g_timer_start(timer);
7353 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7356 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7358 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7359 GError *error = NULL;
7361 /* parse error code */
7362 gst_message_parse_error(msg, &error, NULL);
7364 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7365 /* Note : the streaming error from the streaming source is handled
7366 * using __mmplayer_handle_streaming_error.
7368 __mmplayer_handle_streaming_error(player, msg);
7371 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7373 if (error->domain == GST_STREAM_ERROR)
7374 ret = __gst_handle_stream_error(player, error, msg);
7375 else if (error->domain == GST_RESOURCE_ERROR)
7376 ret = __gst_handle_resource_error(player, error->code, NULL);
7377 else if (error->domain == GST_LIBRARY_ERROR)
7378 ret = __gst_handle_library_error(player, error->code);
7379 else if (error->domain == GST_CORE_ERROR)
7380 ret = __gst_handle_core_error(player, error->code);
7382 player->msg_posted = TRUE;
7384 gst_message_unref(msg);
7386 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7388 gst_object_unref(bus);
7389 g_timer_stop(timer);
7390 g_timer_destroy(timer);
7394 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7395 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7397 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7399 } else if (ret == MM_ERROR_NONE) {
7401 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7405 /* generate dot file before returning error */
7406 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7413 int __gst_resume(mm_player_t* player, gboolean async)
7415 int ret = MM_ERROR_NONE;
7420 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7421 MM_ERROR_PLAYER_NOT_INITIALIZED);
7423 LOGD("current state before doing transition");
7424 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7425 MMPLAYER_PRINT_STATE(player);
7427 /* generate dot file before returning error */
7428 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7431 LOGD("do async state transition to PLAYING.\n");
7433 /* set pipeline state to PLAYING */
7434 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7436 ret = __mmplayer_gst_set_state(player,
7437 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7438 if (ret != MM_ERROR_NONE) {
7439 LOGE("failed to set state to PLAYING\n");
7442 if (async == FALSE) {
7443 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7444 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7445 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7449 /* generate dot file before returning error */
7450 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7458 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7460 unsigned long dur_msec = 0;
7461 gint64 dur_nsec = 0;
7462 gint64 pos_nsec = 0;
7463 gboolean ret = TRUE;
7464 gboolean accurated = FALSE;
7465 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7468 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7469 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7471 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7472 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7475 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7476 /* check duration */
7477 /* NOTE : duration cannot be zero except live streaming.
7478 * Since some element could have some timing problemn with quering duration, try again.
7480 if (!player->duration) {
7481 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec))
7483 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7484 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7485 if ((MMPLAYER_IS_RTSP_STREAMING( player )) && (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7486 player->pending_seek.is_pending = TRUE;
7487 player->pending_seek.format = format;
7488 player->pending_seek.pos = position;
7489 player->doing_seek = FALSE;
7490 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
7491 return MM_ERROR_NONE;
7496 player->duration = dur_nsec;
7499 if (player->duration) {
7500 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7502 LOGE("could not get the duration. fail to seek.\n");
7506 LOGD("playback rate: %f\n", player->playback_rate);
7508 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7510 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7512 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7516 case MM_PLAYER_POS_FORMAT_TIME:
7518 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7519 GstQuery *query = NULL;
7520 gboolean seekable = FALSE;
7522 /* check position is valid or not */
7523 if (position > dur_msec)
7526 query = gst_query_new_seeking (GST_FORMAT_TIME);
7527 if (gst_element_query (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7528 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
7529 gst_query_unref (query);
7532 LOGW("non-seekable content");
7533 player->doing_seek = FALSE;
7534 return MM_ERROR_PLAYER_NO_OP;
7537 LOGW("failed to get seeking query");
7538 gst_query_unref (query); /* keep seeking operation */
7541 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7543 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7544 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7545 This causes problem is position calculation during normal pause resume scenarios also.
7546 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7547 if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
7548 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7549 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7550 LOGW("getting current position failed in seek\n");
7552 player->last_position = pos_nsec;
7553 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
7556 if (player->doing_seek) {
7557 LOGD("not completed seek");
7558 return MM_ERROR_PLAYER_DOING_SEEK;
7562 if (!internal_called)
7563 player->doing_seek = TRUE;
7565 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7567 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7568 gint64 cur_time = 0;
7570 /* get current position */
7571 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7574 GstEvent *event = gst_event_new_seek(1.0,
7576 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7577 GST_SEEK_TYPE_SET, cur_time,
7578 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7580 __gst_send_event_to_sink(player, event);
7582 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7583 __gst_pause(player, FALSE);
7586 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7587 that's why set position through property. */
7588 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7589 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7590 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7591 (!player->videodec_linked) && (!player->audiodec_linked)) {
7593 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7594 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7595 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7596 player->doing_seek = FALSE;
7597 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7599 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7600 GST_FORMAT_TIME, seek_flags,
7601 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7605 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7611 case MM_PLAYER_POS_FORMAT_PERCENT:
7613 LOGD("seeking to(%lu)%% \n", position);
7615 if (player->doing_seek) {
7616 LOGD("not completed seek");
7617 return MM_ERROR_PLAYER_DOING_SEEK;
7620 if (!internal_called)
7621 player->doing_seek = TRUE;
7623 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7624 pos_nsec = (gint64)((position * player->duration) / 100);
7625 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7626 GST_FORMAT_TIME, seek_flags,
7627 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7629 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7639 /* NOTE : store last seeking point to overcome some bad operation
7640 * (returning zero when getting current position) of some elements
7642 player->last_position = pos_nsec;
7644 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7645 if (player->playback_rate > 1.0)
7646 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7649 return MM_ERROR_NONE;
7652 player->pending_seek.is_pending = TRUE;
7653 player->pending_seek.format = format;
7654 player->pending_seek.pos = position;
7656 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7657 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7659 return MM_ERROR_NONE;
7662 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7663 return MM_ERROR_INVALID_ARGUMENT;
7666 player->doing_seek = FALSE;
7667 return MM_ERROR_PLAYER_SEEK;
7670 #define TRICKPLAY_OFFSET GST_MSECOND
7673 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7675 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7676 gint64 pos_msec = 0;
7677 gboolean ret = TRUE;
7679 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7680 MM_ERROR_PLAYER_NOT_INITIALIZED);
7682 current_state = MMPLAYER_CURRENT_STATE(player);
7684 /* NOTE : query position except paused state to overcome some bad operation
7685 * please refer to below comments in details
7687 if (current_state != MM_PLAYER_STATE_PAUSED)
7688 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7690 /* NOTE : get last point to overcome some bad operation of some elements
7691 *(returning zero when getting current position in paused state
7692 * and when failed to get postion during seeking
7694 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7695 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7697 if (player->playback_rate < 0.0)
7698 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7700 pos_msec = player->last_position;
7703 pos_msec = player->last_position;
7705 player->last_position = pos_msec;
7707 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7710 if (player->duration > 0 && pos_msec > player->duration)
7711 pos_msec = player->duration;
7713 if (player->sound_focus.keep_last_pos) {
7714 LOGD("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7715 pos_msec = player->last_position;
7717 player->last_position = pos_msec;
7722 case MM_PLAYER_POS_FORMAT_TIME:
7723 *position = GST_TIME_AS_MSECONDS(pos_msec);
7726 case MM_PLAYER_POS_FORMAT_PERCENT:
7728 if (player->duration <= 0) {
7729 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7732 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7733 *position = pos_msec * 100 / player->duration;
7738 return MM_ERROR_PLAYER_INTERNAL;
7741 return MM_ERROR_NONE;
7745 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7747 #define STREAMING_IS_FINISHED 0
7748 #define BUFFERING_MAX_PER 100
7749 #define DEFAULT_PER_VALUE -1
7750 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7752 MMPlayerGstElement *mainbin = NULL;
7753 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7754 gint64 buffered_total = 0;
7755 unsigned long position = 0;
7756 gint buffered_sec = -1;
7757 GstBufferingMode mode = GST_BUFFERING_STREAM;
7758 gint64 content_size_time = player->duration;
7759 guint64 content_size_bytes = player->http_content_size;
7761 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7763 player->pipeline->mainbin,
7764 MM_ERROR_PLAYER_NOT_INITIALIZED);
7766 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7771 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7772 /* and rtsp is not ready yet. */
7773 LOGW("it's only used for http streaming case.\n");
7774 return MM_ERROR_PLAYER_NO_OP;
7777 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7778 LOGW("Time format is not supported yet.\n");
7779 return MM_ERROR_INVALID_ARGUMENT;
7782 if (content_size_time <= 0 || content_size_bytes <= 0) {
7783 LOGW("there is no content size.");
7784 return MM_ERROR_NONE;
7787 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7788 LOGW("fail to get current position.");
7789 return MM_ERROR_NONE;
7792 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7793 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7795 mainbin = player->pipeline->mainbin;
7796 start_per = (gint)(ceil(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7798 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7799 GstQuery *query = NULL;
7800 gint byte_in_rate = 0, byte_out_rate = 0;
7801 gint64 estimated_total = 0;
7803 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7804 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7805 LOGW("fail to get buffering query from queue2");
7807 gst_query_unref(query);
7808 return MM_ERROR_NONE;
7811 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7812 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7814 if (mode == GST_BUFFERING_STREAM) {
7815 /* using only queue in case of push mode(ts / mp3) */
7816 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7817 GST_FORMAT_BYTES, &buffered_total)) {
7818 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7819 stop_per = 100 * buffered_total / content_size_bytes;
7822 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7824 guint num_of_ranges = 0;
7825 gint64 start_byte = 0, stop_byte = 0;
7827 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7828 if (estimated_total != STREAMING_IS_FINISHED) {
7829 /* buffered size info from queue2 */
7830 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7831 for (idx = 0; idx < num_of_ranges; idx++) {
7832 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7833 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7835 buffered_total += (stop_byte - start_byte);
7838 stop_per = BUFFERING_MAX_PER;
7840 gst_query_unref(query);
7843 if (stop_per == DEFAULT_PER_VALUE) {
7844 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7846 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7848 /* buffered size info from multiqueue */
7849 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7850 guint curr_size_bytes = 0;
7851 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7852 "curr-size-bytes", &curr_size_bytes, NULL);
7853 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7854 buffered_total += curr_size_bytes;
7857 if (avg_byterate > 0)
7858 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7859 else if (player->total_maximum_bitrate > 0)
7860 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7861 else if (player->total_bitrate > 0)
7862 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7864 if (buffered_sec >= 0)
7865 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7869 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7870 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7872 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7873 buffered_total, buffered_sec, *start_pos, *stop_pos);
7875 return MM_ERROR_NONE;
7879 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7884 LOGW("set_message_callback is called with invalid player handle\n");
7885 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7888 player->msg_cb = callback;
7889 player->msg_cb_param = user_param;
7891 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7895 return MM_ERROR_NONE;
7898 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7900 int ret = MM_ERROR_PLAYER_INVALID_URI;
7905 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7906 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7907 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7909 memset(data, 0, sizeof(MMPlayerParseProfile));
7911 if ((path = strstr(uri, "es_buff://"))) {
7913 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7914 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7915 ret = MM_ERROR_NONE;
7917 } else if ((path = strstr(uri, "rtsp://"))) {
7919 if ((path = strstr(uri, "/wfd1.0/"))) {
7920 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7921 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
7922 ret = MM_ERROR_NONE;
7923 LOGD("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
7925 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7926 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7927 ret = MM_ERROR_NONE;
7930 } else if ((path = strstr(uri, "http://"))) {
7932 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7934 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7935 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7936 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7938 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7940 ret = MM_ERROR_NONE;
7942 } else if ((path = strstr(uri, "https://"))) {
7944 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7946 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7947 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7948 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7950 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7952 ret = MM_ERROR_NONE;
7954 } else if ((path = strstr(uri, "rtspu://"))) {
7956 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7957 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7958 ret = MM_ERROR_NONE;
7960 } else if ((path = strstr(uri, "rtspr://"))) {
7961 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7962 char *separater = strstr(path, "*");
7966 char *urgent = separater + strlen("*");
7968 if ((urgent_len = strlen(urgent))) {
7969 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7970 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7971 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7972 ret = MM_ERROR_NONE;
7975 } else if ((path = strstr(uri, "mms://"))) {
7977 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7978 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7979 ret = MM_ERROR_NONE;
7981 } else if ((path = strstr(uri, "mem://"))) {
7984 char *buffer = NULL;
7985 char *seperator = strchr(path, ',');
7986 char ext[100] = {0,}, size[100] = {0,};
7989 if ((buffer = strstr(path, "ext="))) {
7990 buffer += strlen("ext=");
7992 if (strlen(buffer)) {
7993 strncpy(ext, buffer, 99);
7995 if ((seperator = strchr(ext, ','))
7996 || (seperator = strchr(ext, ' '))
7997 || (seperator = strchr(ext, '\0'))) {
7998 seperator[0] = '\0';
8003 if ((buffer = strstr(path, "size="))) {
8004 buffer += strlen("size=");
8006 if (strlen(buffer) > 0) {
8007 strncpy(size, buffer, 99);
8009 if ((seperator = strchr(size, ','))
8010 || (seperator = strchr(size, ' '))
8011 || (seperator = strchr(size, '\0'))) {
8012 seperator[0] = '\0';
8015 mem_size = atoi(size);
8020 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8021 if (mem_size && param) {
8025 data->mem = malloc(mem_size);
8028 memcpy(data->mem, param, mem_size);
8029 data->mem_size = mem_size;
8031 LOGE("failed to alloc mem %d", mem_size);
8034 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8035 ret = MM_ERROR_NONE;
8039 gchar *location = NULL;
8042 if ((path = strstr(uri, "file://"))) {
8044 location = g_filename_from_uri(uri, NULL, &err);
8046 if (!location || (err != NULL)) {
8047 LOGE("Invalid URI '%s' for filesrc: %s", path,
8048 (err != NULL) ? err->message : "unknown error");
8050 if (err) g_error_free(err);
8051 if (location) g_free(location);
8053 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8057 LOGD("path from uri: %s", location);
8060 path = (location != NULL) ? (location) : ((char*)uri);
8061 int file_stat = MM_ERROR_NONE;
8063 file_stat = util_exist_file_path(path);
8065 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8066 if (file_stat == MM_ERROR_NONE) {
8067 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8069 if (util_is_sdp_file(path)) {
8070 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8071 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8073 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8075 ret = MM_ERROR_NONE;
8076 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8077 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8079 LOGE("invalid uri, could not play..\n");
8080 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8083 if (location) g_free(location);
8087 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8088 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8089 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8090 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8092 /* dump parse result */
8093 SECURE_LOGW("incomming uri : %s\n", uri);
8094 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8095 data->uri_type, data->mem, data->mem_size, data->urgent);
8102 gboolean _asm_postmsg(gpointer *data)
8104 mm_player_t* player = (mm_player_t*)data;
8105 MMMessageParamType msg = {0, };
8108 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8109 LOGW("get notified");
8111 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8112 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
8118 msg.union_type = MM_MSG_UNION_CODE;
8119 msg.code = player->sound_focus.focus_changed_msg;
8121 MMPLAYER_POST_MSG(player, MM_MESSAGE_READY_TO_RESUME, &msg);
8122 player->resume_event_id = 0;
8128 gboolean _asm_lazy_pause(gpointer *data)
8130 mm_player_t* player = (mm_player_t*)data;
8131 int ret = MM_ERROR_NONE;
8135 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8137 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) {
8138 LOGD("Ready to proceed lazy pause\n");
8139 ret = _mmplayer_pause((MMHandleType)player);
8140 if (MM_ERROR_NONE != ret)
8141 LOGE("MMPlayer pause failed in ASM callback lazy pause\n");
8143 LOGD("Invalid state to proceed lazy pause\n");
8146 if (player->pipeline && player->pipeline->audiobin)
8147 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8149 player->sound_focus.by_asm_cb = FALSE; //should be reset here
8157 __mmplayer_can_do_interrupt(mm_player_t *player)
8159 if (!player || !player->pipeline || !player->attrs) {
8160 LOGW("not initialized");
8164 if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) {
8165 LOGW("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8169 /* check if seeking */
8170 if (player->doing_seek) {
8171 MMMessageParamType msg_param;
8172 memset(&msg_param, 0, sizeof(MMMessageParamType));
8173 msg_param.code = MM_ERROR_PLAYER_SEEK;
8174 player->doing_seek = FALSE;
8175 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8179 /* check other thread */
8180 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8181 LOGW("locked already, cmd state : %d", player->cmd);
8183 /* check application command */
8184 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8185 LOGW("playing.. should wait cmd lock then, will be interrupted");
8187 /* lock will be released at mrp_resource_release_cb() */
8188 MMPLAYER_CMD_LOCK(player);
8191 LOGW("nothing to do");
8194 LOGW("can interrupt immediately");
8198 FAILED: /* with CMD UNLOCKED */
8201 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8205 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8207 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8209 int ret = MM_ERROR_NONE;
8210 MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8212 if (strstr(reason_for_change, "alarm")) {
8213 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8215 } else if (strstr(reason_for_change, "notification")) {
8216 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8218 } else if (strstr(reason_for_change, "emergency")) {
8219 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8221 } else if (strstr(reason_for_change, "call-voice") ||
8222 strstr(reason_for_change, "call-video") ||
8223 strstr(reason_for_change, "voip") ||
8224 strstr(reason_for_change, "ringtone-voip") ||
8225 strstr(reason_for_change, "ringtone-call")) {
8226 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8228 } else if (strstr(reason_for_change, "media") ||
8229 strstr(reason_for_change, "radio") ||
8230 strstr(reason_for_change, "loopback") ||
8231 strstr(reason_for_change, "system") ||
8232 strstr(reason_for_change, "voice-information") ||
8233 strstr(reason_for_change, "voice-recognition")) {
8234 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8237 ret = MM_ERROR_INVALID_ARGUMENT;
8238 LOGW("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8242 if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8244 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8246 LOGD("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8253 /* FIXME: will be updated with new funct */
8254 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8255 const char *reason_for_change, const char *additional_info, void *user_data)
8257 mm_player_t* player = (mm_player_t*) user_data;
8258 int result = MM_ERROR_NONE;
8259 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8261 LOGW("focus watch notified");
8263 if (!__mmplayer_can_do_interrupt(player)) {
8264 LOGW("no need to interrupt, so leave");
8265 goto EXIT_WITHOUT_UNLOCK;
8268 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8269 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8273 LOGW("watch: state: %d, focus_type : %d, reason_for_change : %s",
8274 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8276 player->sound_focus.cb_pending = TRUE;
8277 player->sound_focus.by_asm_cb = TRUE;
8279 if (focus_state == FOCUS_IS_ACQUIRED) {
8280 LOGW("watch: FOCUS_IS_ACQUIRED");
8281 player->sound_focus.acquired = TRUE;
8283 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8284 player->sound_focus.focus_changed_msg = (int)msg;
8286 if (strstr(reason_for_change, "call") ||
8287 strstr(reason_for_change, "voip") || /* FIXME: to check */
8288 strstr(reason_for_change, "alarm") ||
8289 strstr(reason_for_change, "media")) {
8290 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8291 // hold 0.7 second to excute "fadedown mute" effect
8292 LOGW("do fade down->pause->undo fade down");
8294 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8296 result = _mmplayer_pause((MMHandleType)player);
8297 if (result != MM_ERROR_NONE) {
8298 LOGW("fail to set Pause state by asm");
8301 __mmplayer_undo_sound_fadedown(player);
8303 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8304 _mmplayer_unrealize((MMHandleType)player);
8306 LOGW("pause immediately");
8307 result = _mmplayer_pause((MMHandleType)player);
8308 if (result != MM_ERROR_NONE) {
8309 LOGW("fail to set Pause state by asm");
8313 } else if (focus_state == FOCUS_IS_RELEASED) {
8314 LOGW("FOCUS_IS_RELEASED: Got msg from asm to resume");
8315 player->sound_focus.acquired = FALSE;
8316 player->sound_focus.antishock = TRUE;
8317 player->sound_focus.by_asm_cb = FALSE;
8319 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8320 player->sound_focus.focus_changed_msg = (int)msg;
8322 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8323 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8326 LOGW("unknown focus state %d", focus_state);
8329 player->sound_focus.by_asm_cb = FALSE;
8330 player->sound_focus.cb_pending = FALSE;
8333 MMPLAYER_CMD_UNLOCK(player);
8337 EXIT_WITHOUT_UNLOCK:
8343 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8344 const char *reason_for_change, int option, const char *additional_info, void *user_data)
8346 mm_player_t* player = (mm_player_t*) user_data;
8347 int result = MM_ERROR_NONE;
8348 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8350 LOGW("get focus notified");
8352 if (!__mmplayer_can_do_interrupt(player)) {
8353 LOGW("no need to interrupt, so leave");
8354 goto EXIT_WITHOUT_UNLOCK;
8357 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8358 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8362 LOGW("state: %d, focus_type : %d, reason_for_change : %s",
8363 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8365 player->sound_focus.cb_pending = TRUE;
8366 player->sound_focus.by_asm_cb = TRUE;
8367 // player->sound_focus.event_src = event_src;
8369 if (focus_state == FOCUS_IS_RELEASED) {
8370 LOGW("FOCUS_IS_RELEASED");
8371 player->sound_focus.acquired = FALSE;
8373 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8374 player->sound_focus.focus_changed_msg = (int)msg;
8376 if (strstr(reason_for_change, "call") ||
8377 strstr(reason_for_change, "voip") || /* FIXME: to check */
8378 strstr(reason_for_change, "alarm") ||
8379 strstr(reason_for_change, "media")) {
8380 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8381 //hold 0.7 second to excute "fadedown mute" effect
8382 LOGW("do fade down->pause->undo fade down");
8384 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8386 result = _mmplayer_pause((MMHandleType)player);
8387 if (result != MM_ERROR_NONE) {
8388 LOGW("fail to set Pause state by asm");
8391 __mmplayer_undo_sound_fadedown(player);
8393 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8394 _mmplayer_unrealize((MMHandleType)player);
8396 LOGW("pause immediately");
8397 result = _mmplayer_pause((MMHandleType)player);
8398 if (result != MM_ERROR_NONE) {
8399 LOGW("fail to set Pause state by asm");
8403 } else if (focus_state == FOCUS_IS_ACQUIRED) {
8404 LOGW("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8405 player->sound_focus.antishock = TRUE;
8406 player->sound_focus.by_asm_cb = FALSE;
8408 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8409 player->sound_focus.focus_changed_msg = (int)msg;
8411 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8412 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8415 LOGW("unknown focus state %d", focus_state);
8418 player->sound_focus.by_asm_cb = FALSE;
8419 player->sound_focus.cb_pending = FALSE;
8422 if (mm_sound_update_focus_status(id, 0))
8423 LOGE("failed to update focus status\n");
8424 MMPLAYER_CMD_UNLOCK(player);
8428 EXIT_WITHOUT_UNLOCK:
8435 _mmplayer_create_player(MMHandleType handle)
8437 int ret = MM_ERROR_PLAYER_INTERNAL;
8438 mm_player_t* player = MM_PLAYER_CAST(handle);
8442 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8444 /* initialize player state */
8445 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8446 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8447 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8448 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8450 /* check current state */
8451 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8453 /* construct attributes */
8454 player->attrs = _mmplayer_construct_attribute(handle);
8456 if (!player->attrs) {
8457 LOGE("Failed to construct attributes\n");
8461 /* initialize gstreamer with configured parameter */
8462 if (!__mmplayer_init_gstreamer(player)) {
8463 LOGE("Initializing gstreamer failed\n");
8464 _mmplayer_deconstruct_attribute(handle);
8468 /* initialize factories if not using decodebin */
8469 if (player->factories == NULL)
8470 __mmplayer_init_factories(player);
8472 /* create lock. note that g_tread_init() has already called in gst_init() */
8473 g_mutex_init(&player->fsink_lock);
8475 /* create update tag lock */
8476 g_mutex_init(&player->update_tag_lock);
8478 /* create repeat mutex */
8479 g_mutex_init(&player->repeat_thread_mutex);
8481 /* create repeat cond */
8482 g_cond_init(&player->repeat_thread_cond);
8484 /* create repeat thread */
8485 player->repeat_thread =
8486 g_thread_try_new("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8487 if (!player->repeat_thread) {
8488 LOGE("failed to create repeat_thread(%s)");
8489 g_mutex_clear(&player->repeat_thread_mutex);
8490 g_cond_clear(&player->repeat_thread_cond);
8491 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8495 /* create next play mutex */
8496 g_mutex_init(&player->next_play_thread_mutex);
8498 /* create next play cond */
8499 g_cond_init(&player->next_play_thread_cond);
8501 /* create next play thread */
8502 player->next_play_thread =
8503 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8504 if (!player->next_play_thread) {
8505 LOGE("failed to create next play thread");
8506 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8507 g_mutex_clear(&player->next_play_thread_mutex);
8508 g_cond_clear(&player->next_play_thread_cond);
8512 ret = _mmplayer_initialize_video_capture(player);
8513 if (ret != MM_ERROR_NONE) {
8514 LOGE("failed to initialize video capture\n");
8518 /* initialize resource manager */
8519 if (MM_ERROR_NONE != _mmplayer_resource_manager_init(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], player)) {
8520 LOGE("failed to initialize resource manager\n");
8524 if (MM_ERROR_NONE != _mmplayer_resource_manager_init(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], player)) {
8525 LOGE("failed to initialize resource manager\n");
8529 if (MMPLAYER_IS_HTTP_PD(player)) {
8530 player->pd_downloader = NULL;
8531 player->pd_file_save_path = NULL;
8534 /* create video bo lock and cond */
8535 g_mutex_init(&player->video_bo_mutex);
8536 g_cond_init(&player->video_bo_cond);
8538 /* create media stream callback mutex */
8539 g_mutex_init(&player->media_stream_cb_lock);
8541 player->streaming_type = STREAMING_SERVICE_NONE;
8543 /* give default value of audio effect setting */
8544 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8545 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8547 player->play_subtitle = FALSE;
8548 player->play_count = 0;
8549 player->use_decodebin = TRUE;
8550 player->ignore_asyncdone = FALSE;
8551 player->use_deinterleave = FALSE;
8552 player->max_audio_channels = 0;
8553 player->video_share_api_delta = 0;
8554 player->video_share_clock_delta = 0;
8555 player->has_closed_caption = FALSE;
8556 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8557 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8558 player->pending_resume = FALSE;
8559 if (player->ini.dump_element_keyword[0][0] == '\0')
8560 player->ini.set_dump_element_flag = FALSE;
8562 player->ini.set_dump_element_flag = TRUE;
8564 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8565 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8566 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8568 /* set player state to null */
8569 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8570 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8572 return MM_ERROR_NONE;
8576 g_mutex_clear(&player->fsink_lock);
8578 /* free update tag lock */
8579 g_mutex_clear(&player->update_tag_lock);
8582 if (player->repeat_thread) {
8583 MMPLAYER_REPEAT_THREAD_LOCK(player);
8584 player->repeat_thread_exit = TRUE;
8585 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8586 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
8588 g_thread_join(player->repeat_thread);
8589 player->repeat_thread = NULL;
8591 g_mutex_clear(&player->repeat_thread_mutex);
8592 g_cond_clear(&player->repeat_thread_cond);
8595 /* free next play thread */
8596 if (player->next_play_thread) {
8597 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8598 player->next_play_thread_exit = TRUE;
8599 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8600 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8602 g_thread_join(player->next_play_thread);
8603 player->next_play_thread = NULL;
8605 g_mutex_clear(&player->next_play_thread_mutex);
8606 g_cond_clear(&player->next_play_thread_cond);
8609 /* release attributes */
8610 _mmplayer_deconstruct_attribute(handle);
8618 __mmplayer_init_gstreamer(mm_player_t* player)
8620 static gboolean initialized = FALSE;
8621 static const int max_argc = 50;
8623 gchar** argv = NULL;
8624 gchar** argv2 = NULL;
8630 LOGD("gstreamer already initialized.\n");
8635 argc = malloc(sizeof(int));
8636 argv = malloc(sizeof(gchar*) * max_argc);
8637 argv2 = malloc(sizeof(gchar*) * max_argc);
8639 if (!argc || !argv || !argv2)
8642 memset(argv, 0, sizeof(gchar*) * max_argc);
8643 memset(argv2, 0, sizeof(gchar*) * max_argc);
8647 argv[0] = g_strdup("mmplayer");
8650 for (i = 0; i < 5; i++) {
8651 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8652 if (strlen(player->ini.gst_param[i]) > 0) {
8653 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8658 /* we would not do fork for scanning plugins */
8659 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8662 /* check disable registry scan */
8663 if (player->ini.skip_rescan) {
8664 argv[*argc] = g_strdup("--gst-disable-registry-update");
8668 /* check disable segtrap */
8669 if (player->ini.disable_segtrap) {
8670 argv[*argc] = g_strdup("--gst-disable-segtrap");
8674 LOGD("initializing gstreamer with following parameter\n");
8675 LOGD("argc : %d\n", *argc);
8678 for (i = 0; i < arg_count; i++) {
8680 LOGD("argv[%d] : %s\n", i, argv2[i]);
8683 /* initializing gstreamer */
8684 if (!gst_init_check(argc, &argv, &err)) {
8685 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8692 for (i = 0; i < arg_count; i++) {
8693 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8694 MMPLAYER_FREEIF(argv2[i]);
8697 MMPLAYER_FREEIF(argv);
8698 MMPLAYER_FREEIF(argv2);
8699 MMPLAYER_FREEIF(argc);
8709 for (i = 0; i < arg_count; i++) {
8710 LOGD("free[%d] : %s\n", i, argv2[i]);
8711 MMPLAYER_FREEIF(argv2[i]);
8714 MMPLAYER_FREEIF(argv);
8715 MMPLAYER_FREEIF(argv2);
8716 MMPLAYER_FREEIF(argc);
8722 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8724 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8726 if (player->pd_downloader) {
8727 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8728 MMPLAYER_FREEIF(player->pd_downloader);
8731 if (MMPLAYER_IS_HTTP_PD(player)) {
8732 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8733 MMPLAYER_FREEIF(player->pd_file_save_path);
8736 return MM_ERROR_NONE;
8740 __mmplayer_check_async_state_transition(mm_player_t* player)
8742 GstState element_state = GST_STATE_VOID_PENDING;
8743 GstState element_pending_state = GST_STATE_VOID_PENDING;
8744 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8745 GstElement * element = NULL;
8746 gboolean async = FALSE;
8748 /* check player handle */
8749 MMPLAYER_RETURN_IF_FAIL(player &&
8751 player->pipeline->mainbin &&
8752 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8755 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8757 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8758 LOGD("don't need to check the pipeline state");
8762 MMPLAYER_PRINT_STATE(player);
8764 /* wait for state transition */
8765 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8766 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8768 if (ret == GST_STATE_CHANGE_FAILURE) {
8769 LOGE(" [%s] state : %s pending : %s \n",
8770 GST_ELEMENT_NAME(element),
8771 gst_element_state_get_name(element_state),
8772 gst_element_state_get_name(element_pending_state));
8774 /* dump state of all element */
8775 __mmplayer_dump_pipeline_state(player);
8780 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8785 _mmplayer_destroy(MMHandleType handle)
8787 mm_player_t* player = MM_PLAYER_CAST(handle);
8791 /* check player handle */
8792 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8794 /* destroy can called at anytime */
8795 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8797 /* check async state transition */
8798 __mmplayer_check_async_state_transition(player);
8800 __mmplayer_destroy_streaming_ext(player);
8802 /* release repeat thread */
8803 if (player->repeat_thread) {
8804 MMPLAYER_REPEAT_THREAD_LOCK(player);
8805 player->repeat_thread_exit = TRUE;
8806 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8807 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
8809 LOGD("waitting for repeat thread exit\n");
8810 g_thread_join(player->repeat_thread);
8811 g_mutex_clear(&player->repeat_thread_mutex);
8812 g_cond_clear(&player->repeat_thread_cond);
8813 LOGD("repeat thread released\n");
8816 /* release next play thread */
8817 if (player->next_play_thread) {
8818 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8819 player->next_play_thread_exit = TRUE;
8820 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8821 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8823 LOGD("waitting for next play thread exit\n");
8824 g_thread_join(player->next_play_thread);
8825 g_mutex_clear(&player->next_play_thread_mutex);
8826 g_cond_clear(&player->next_play_thread_cond);
8827 LOGD("next play thread released\n");
8830 _mmplayer_release_video_capture(player);
8832 /* flush any pending asm_cb */
8833 if (player->sound_focus.cb_pending) {
8834 /* set a flag for make sure asm_cb to be returned immediately */
8835 LOGW("asm cb has pending state");
8836 player->sound_focus.exit_cb = TRUE;
8838 /* make sure to release any pending asm_cb which locked by cmd_lock */
8839 MMPLAYER_CMD_UNLOCK(player);
8841 MMPLAYER_CMD_LOCK(player);
8845 if (MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus))
8846 LOGE("failed to deregister asm server\n");
8848 /* de-initialize resource manager */
8849 if (MM_ERROR_NONE != _mmplayer_resource_manager_deinit(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER]))
8850 LOGE("failed to deinitialize resource manager\n");
8852 if (MM_ERROR_NONE != _mmplayer_resource_manager_deinit(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]))
8853 LOGE("failed to deinitialize resource manager\n");
8855 #ifdef USE_LAZY_PAUSE
8856 if (player->lazy_pause_event_id) {
8857 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
8858 player->lazy_pause_event_id = 0;
8862 if (player->resume_event_id) {
8863 g_source_remove(player->resume_event_id);
8864 player->resume_event_id = 0;
8867 if (player->resumable_cancel_id) {
8868 g_source_remove(player->resumable_cancel_id);
8869 player->resumable_cancel_id = 0;
8872 /* release pipeline */
8873 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8874 LOGE("failed to destory pipeline\n");
8875 return MM_ERROR_PLAYER_INTERNAL;
8878 if (player->is_external_subtitle_present && player->subtitle_language_list) {
8879 g_list_free(player->subtitle_language_list);
8880 player->subtitle_language_list = NULL;
8883 __mmplayer_release_dump_list(player->dump_list);
8885 /* release miscellaneous information.
8886 these info needs to be released after pipeline is destroyed. */
8887 __mmplayer_release_misc_post(player);
8889 /* release attributes */
8890 _mmplayer_deconstruct_attribute(handle);
8892 /* release factories */
8893 __mmplayer_release_factories(player);
8896 g_mutex_clear(&player->fsink_lock);
8899 g_mutex_clear(&player->update_tag_lock);
8901 /* release video bo lock and cond */
8902 g_mutex_clear(&player->video_bo_mutex);
8903 g_cond_clear(&player->video_bo_cond);
8905 /* release media stream callback lock */
8906 g_mutex_clear(&player->media_stream_cb_lock);
8910 return MM_ERROR_NONE;
8914 __mmplayer_realize_streaming_ext(mm_player_t* player)
8916 int ret = MM_ERROR_NONE;
8919 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8921 if (MMPLAYER_IS_HTTP_PD(player)) {
8922 gboolean bret = FALSE;
8924 player->pd_downloader = _mmplayer_create_pd_downloader();
8925 if (!player->pd_downloader) {
8926 LOGE("Unable to create PD Downloader...");
8927 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8930 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8932 if (FALSE == bret) {
8933 LOGE("Unable to create PD Downloader...");
8934 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8943 _mmplayer_sound_register_with_pid(MMHandleType hplayer, int pid)
8945 mm_player_t* player = (mm_player_t*)hplayer;
8946 MMHandleType attrs = 0;
8947 int ret = MM_ERROR_NONE;
8949 attrs = MMPLAYER_GET_ATTRS(player);
8951 LOGE("fail to get attributes.\n");
8952 return MM_ERROR_PLAYER_INTERNAL;
8955 player->sound_focus.pid = pid;
8957 /* register to asm */
8958 if (MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
8959 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
8960 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
8962 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
8963 LOGE("failed to register asm server\n");
8964 return MM_ERROR_POLICY_INTERNAL;
8970 _mmplayer_get_client_pid(MMHandleType hplayer, int* pid)
8972 mm_player_t* player = (mm_player_t*) hplayer;
8976 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8978 *pid = player->sound_focus.pid;
8980 LOGD("registered pid[%d] %p", *pid, player);
8984 return MM_ERROR_NONE;
8988 _mmplayer_realize(MMHandleType hplayer)
8990 mm_player_t* player = (mm_player_t*)hplayer;
8993 gboolean update_registry = FALSE;
8994 MMHandleType attrs = 0;
8995 int ret = MM_ERROR_NONE;
8999 /* check player handle */
9000 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
9002 /* check current state */
9003 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
9005 attrs = MMPLAYER_GET_ATTRS(player);
9007 LOGE("fail to get attributes.\n");
9008 return MM_ERROR_PLAYER_INTERNAL;
9010 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
9011 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
9013 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
9014 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
9016 if (ret != MM_ERROR_NONE) {
9017 LOGE("failed to parse profile\n");
9022 /* profile.mem or mem_buf.buf have to be free when player is destroyed */
9023 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
9024 player->mem_buf.buf = (char *)player->profile.mem;
9025 player->mem_buf.len = player->profile.mem_size;
9026 player->mem_buf.offset = 0;
9029 if (uri && (strstr(uri, "es_buff://"))) {
9030 if (strstr(uri, "es_buff://push_mode"))
9031 player->es_player_push_mode = TRUE;
9033 player->es_player_push_mode = FALSE;
9036 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
9037 LOGW("mms protocol is not supported format.\n");
9038 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9041 if (MMPLAYER_IS_STREAMING(player))
9042 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
9044 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
9046 player->smooth_streaming = FALSE;
9047 player->videodec_linked = 0;
9048 player->videosink_linked = 0;
9049 player->audiodec_linked = 0;
9050 player->audiosink_linked = 0;
9051 player->textsink_linked = 0;
9052 player->is_external_subtitle_present = FALSE;
9053 player->is_external_subtitle_added_now = FALSE;
9054 /* set the subtitle ON default */
9055 player->is_subtitle_off = FALSE;
9057 /* registry should be updated for downloadable codec */
9058 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
9060 if (update_registry) {
9061 LOGD("updating registry...\n");
9062 gst_update_registry();
9064 /* then we have to rebuild factories */
9065 __mmplayer_release_factories(player);
9066 __mmplayer_init_factories(player);
9069 /* realize pipeline */
9070 ret = __gst_realize(player);
9071 if (ret != MM_ERROR_NONE)
9072 LOGE("fail to realize the player.\n");
9074 ret = __mmplayer_realize_streaming_ext(player);
9082 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
9085 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9087 /* destroy can called at anytime */
9088 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) {
9089 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9090 MMPLAYER_FREEIF(player->pd_downloader);
9094 return MM_ERROR_NONE;
9098 _mmplayer_unrealize(MMHandleType hplayer)
9100 mm_player_t* player = (mm_player_t*)hplayer;
9101 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
9102 int ret = MM_ERROR_NONE;
9106 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
9108 /* check current state */
9109 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
9111 /* check async state transition */
9112 __mmplayer_check_async_state_transition(player);
9114 __mmplayer_unrealize_streaming_ext(player);
9116 /* unrealize pipeline */
9117 ret = __gst_unrealize(player);
9119 /* set asm stop if success */
9120 if (MM_ERROR_NONE == ret) {
9121 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9122 if (ret != MM_ERROR_NONE)
9123 LOGE("failed to release sound focus, ret(0x%x)\n", ret);
9125 if (!player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER].by_rm_cb && /* is being released */
9126 !player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY].by_rm_cb &&
9127 _mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], &resource_state) == MM_ERROR_NONE) {
9128 if (resource_state >= RESOURCE_STATE_ACQUIRED) {
9129 ret = _mmplayer_resource_manager_release(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER]);
9130 if (ret != MM_ERROR_NONE)
9131 LOGE("failed to release decoder resource, ret(0x%x)\n", ret);
9135 if (!player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER].by_rm_cb && /* is being released */
9136 !player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY].by_rm_cb &&
9137 _mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
9138 if (resource_state >= RESOURCE_STATE_ACQUIRED) {
9139 ret = _mmplayer_resource_manager_release(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
9140 if (ret != MM_ERROR_NONE)
9141 LOGE("failed to release overlay resource, ret(0x%x)\n", ret);
9145 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], &resource_state) == MM_ERROR_NONE) {
9146 if (resource_state == RESOURCE_STATE_PREPARED) {
9147 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER]);
9148 if (ret != MM_ERROR_NONE)
9149 LOGE("failed to unprepare decoder resource, ret(0x%x)\n", ret);
9154 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
9155 if (resource_state == RESOURCE_STATE_PREPARED) {
9156 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
9157 if (ret != MM_ERROR_NONE)
9158 LOGE("failed to unprepare overlay resource, ret(0x%x)\n", ret);
9162 LOGE("failed and don't change asm state to stop");
9170 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
9172 mm_player_t* player = (mm_player_t*)hplayer;
9174 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9176 return __gst_set_message_callback(player, callback, user_param);
9180 _mmplayer_get_state(MMHandleType hplayer, int* state)
9182 mm_player_t *player = (mm_player_t*)hplayer;
9184 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
9186 *state = MMPLAYER_CURRENT_STATE(player);
9188 return MM_ERROR_NONE;
9193 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
9195 mm_player_t* player = (mm_player_t*) hplayer;
9196 GstElement* vol_element = NULL;
9201 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9203 LOGD("volume [L]=%f:[R]=%f\n",
9204 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9206 /* invalid factor range or not */
9207 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
9208 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9209 LOGE("Invalid factor!(valid factor:0~1.0)\n");
9210 return MM_ERROR_INVALID_ARGUMENT;
9214 /* not support to set other value into each channel */
9215 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9216 return MM_ERROR_INVALID_ARGUMENT;
9218 /* Save volume to handle. Currently the first array element will be saved. */
9219 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9221 /* check pipeline handle */
9222 if (!player->pipeline || !player->pipeline->audiobin) {
9223 LOGD("audiobin is not created yet\n");
9224 LOGD("but, current stored volume will be set when it's created.\n");
9226 /* NOTE : stored volume will be used in create_audiobin
9227 * returning MM_ERROR_NONE here makes application to able to
9228 * set volume at anytime.
9230 return MM_ERROR_NONE;
9233 /* setting volume to volume element */
9234 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9237 LOGD("volume is set [%f]\n", player->sound.volume);
9238 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9243 return MM_ERROR_NONE;
9248 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9250 mm_player_t* player = (mm_player_t*) hplayer;
9255 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9256 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
9258 /* returning stored volume */
9259 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9260 volume->level[i] = player->sound.volume;
9264 return MM_ERROR_NONE;
9270 _mmplayer_set_mute(MMHandleType hplayer, int mute)
9272 mm_player_t* player = (mm_player_t*) hplayer;
9273 GstElement* vol_element = NULL;
9277 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9279 /* mute value shoud 0 or 1 */
9280 if (mute != 0 && mute != 1) {
9281 LOGE("bad mute value\n");
9283 /* FIXIT : definitly, we need _BAD_PARAM error code */
9284 return MM_ERROR_INVALID_ARGUMENT;
9287 player->sound.mute = mute;
9289 /* just hold mute value if pipeline is not ready */
9290 if (!player->pipeline || !player->pipeline->audiobin) {
9291 LOGD("pipeline is not ready. holding mute value\n");
9292 return MM_ERROR_NONE;
9295 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9297 /* NOTE : volume will only created when the bt is enabled */
9299 LOGD("mute : %d\n", mute);
9300 g_object_set(vol_element, "mute", mute, NULL);
9302 LOGD("volume elemnet is not created. using volume in audiosink\n");
9306 return MM_ERROR_NONE;
9310 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
9312 mm_player_t* player = (mm_player_t*) hplayer;
9316 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9317 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
9319 /* just hold mute value if pipeline is not ready */
9320 if (!player->pipeline || !player->pipeline->audiobin) {
9321 LOGD("pipeline is not ready. returning stored value\n");
9322 *pmute = player->sound.mute;
9323 return MM_ERROR_NONE;
9326 *pmute = player->sound.mute;
9330 return MM_ERROR_NONE;
9334 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9336 mm_player_t* player = (mm_player_t*) hplayer;
9340 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9342 player->video_stream_changed_cb = callback;
9343 player->video_stream_changed_cb_user_param = user_param;
9344 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9348 return MM_ERROR_NONE;
9352 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9354 mm_player_t* player = (mm_player_t*) hplayer;
9358 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9360 player->audio_stream_changed_cb = callback;
9361 player->audio_stream_changed_cb_user_param = user_param;
9362 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9366 return MM_ERROR_NONE;
9370 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9372 mm_player_t* player = (mm_player_t*) hplayer;
9376 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9378 player->audio_stream_render_cb_ex = callback;
9379 player->audio_stream_cb_user_param = user_param;
9380 player->audio_stream_sink_sync = sync;
9381 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);
9385 return MM_ERROR_NONE;
9389 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9391 mm_player_t* player = (mm_player_t*) hplayer;
9395 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9397 if (callback && !player->bufmgr)
9398 player->bufmgr = tbm_bufmgr_init(-1);
9400 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9401 player->video_stream_cb = callback;
9402 player->video_stream_cb_user_param = user_param;
9404 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9408 return MM_ERROR_NONE;
9412 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9414 mm_player_t* player = (mm_player_t*) hplayer;
9418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9420 player->audio_stream_cb = callback;
9421 player->audio_stream_cb_user_param = user_param;
9422 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9426 return MM_ERROR_NONE;
9431 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
9433 mm_player_t* player = (mm_player_t*) hplayer;
9437 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9439 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
9440 return MM_ERROR_PLAYER_INVALID_STATE;
9442 LOGD("pre buffer size : %d sec\n", second);
9445 LOGE("bad size value\n");
9446 return MM_ERROR_INVALID_ARGUMENT;
9449 if (player->streamer == NULL) {
9450 player->streamer = __mm_player_streaming_create();
9451 __mm_player_streaming_initialize(player->streamer);
9454 player->streamer->buffering_req.initial_second = second;
9458 return MM_ERROR_NONE;
9463 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
9465 mm_player_t* player = (mm_player_t*) hplayer;
9469 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9471 LOGD("mode %d\n", mode);
9473 if ((mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
9474 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
9475 return MM_ERROR_INVALID_ARGUMENT;
9477 if (player->streamer == NULL) {
9478 player->streamer = __mm_player_streaming_create();
9479 __mm_player_streaming_initialize(player->streamer);
9482 player->streamer->buffering_req.mode = mode;
9485 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
9486 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
9487 player->streamer->buffering_req.runtime_second = second;
9491 return MM_ERROR_NONE;
9495 __mmplayer_start_streaming_ext(mm_player_t *player)
9497 gint ret = MM_ERROR_NONE;
9500 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9502 if (MMPLAYER_IS_HTTP_PD(player)) {
9503 if (!player->pd_downloader) {
9504 ret = __mmplayer_realize_streaming_ext(player);
9506 if (ret != MM_ERROR_NONE) {
9507 LOGE("failed to realize streaming ext\n");
9512 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9513 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9515 LOGE("ERROR while starting PD...\n");
9516 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9518 ret = MM_ERROR_NONE;
9527 _mmplayer_start(MMHandleType hplayer)
9529 mm_player_t* player = (mm_player_t*) hplayer;
9530 gint ret = MM_ERROR_NONE;
9534 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9536 /* check current state */
9537 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9539 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9540 if (ret != MM_ERROR_NONE) {
9541 LOGE("failed to acquire sound focus.\n");
9545 /* NOTE : we should check and create pipeline again if not created as we destroy
9546 * whole pipeline when stopping in streamming playback
9548 if (!player->pipeline) {
9549 ret = __gst_realize(player);
9550 if (MM_ERROR_NONE != ret) {
9551 LOGE("failed to realize before starting. only in streamming\n");
9557 ret = __mmplayer_start_streaming_ext(player);
9558 if (ret != MM_ERROR_NONE)
9559 LOGE("failed to start streaming ext \n");
9561 /* start pipeline */
9562 ret = __gst_start(player);
9563 if (ret != MM_ERROR_NONE)
9564 LOGE("failed to start player.\n");
9571 /* NOTE: post "not supported codec message" to application
9572 * when one codec is not found during AUTOPLUGGING in MSL.
9573 * So, it's separated with error of __mmplayer_gst_callback().
9574 * And, if any codec is not found, don't send message here.
9575 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9578 __mmplayer_handle_missed_plugin(mm_player_t* player)
9580 MMMessageParamType msg_param;
9581 memset(&msg_param, 0, sizeof(MMMessageParamType));
9582 gboolean post_msg_direct = FALSE;
9586 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9588 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9589 player->not_supported_codec, player->can_support_codec);
9591 if (player->not_found_demuxer) {
9592 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9593 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9595 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9596 MMPLAYER_FREEIF(msg_param.data);
9598 return MM_ERROR_NONE;
9601 if (player->not_supported_codec) {
9602 if (player->can_support_codec) {
9603 // There is one codec to play
9604 post_msg_direct = TRUE;
9606 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9607 post_msg_direct = TRUE;
9610 if (post_msg_direct) {
9611 MMMessageParamType msg_param;
9612 memset(&msg_param, 0, sizeof(MMMessageParamType));
9614 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9615 LOGW("not found AUDIO codec, posting error code to application.\n");
9617 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9618 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9619 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9620 LOGW("not found VIDEO codec, posting error code to application.\n");
9622 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9623 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9626 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9628 MMPLAYER_FREEIF(msg_param.data);
9630 return MM_ERROR_NONE;
9632 // no any supported codec case
9633 LOGW("not found any codec, posting error code to application.\n");
9635 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9636 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9637 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9639 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9640 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9643 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9645 MMPLAYER_FREEIF(msg_param.data);
9651 return MM_ERROR_NONE;
9654 static void __mmplayer_check_pipeline(mm_player_t* player)
9656 GstState element_state = GST_STATE_VOID_PENDING;
9657 GstState element_pending_state = GST_STATE_VOID_PENDING;
9659 int ret = MM_ERROR_NONE;
9661 if (player->gapless.reconfigure) {
9662 LOGW("pipeline is under construction.\n");
9664 MMPLAYER_PLAYBACK_LOCK(player);
9665 MMPLAYER_PLAYBACK_UNLOCK(player);
9667 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9669 /* wait for state transition */
9670 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9672 if (ret == GST_STATE_CHANGE_FAILURE)
9673 LOGE("failed to change pipeline state within %d sec\n", timeout);
9677 /* NOTE : it should be able to call 'stop' anytime*/
9679 _mmplayer_stop(MMHandleType hplayer)
9681 mm_player_t* player = (mm_player_t*)hplayer;
9682 int ret = MM_ERROR_NONE;
9686 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9688 /* check current state */
9689 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9691 /* check pipline building state */
9692 __mmplayer_check_pipeline(player);
9693 __mmplayer_reset_gapless_state(player);
9695 /* NOTE : application should not wait for EOS after calling STOP */
9696 __mmplayer_cancel_eos_timer(player);
9698 __mmplayer_unrealize_streaming_ext(player);
9701 player->doing_seek = FALSE;
9704 ret = __gst_stop(player);
9706 if (ret != MM_ERROR_NONE)
9707 LOGE("failed to stop player.\n");
9715 _mmplayer_pause(MMHandleType hplayer)
9717 mm_player_t* player = (mm_player_t*)hplayer;
9718 gint64 pos_msec = 0;
9719 gboolean async = FALSE;
9720 gint ret = MM_ERROR_NONE;
9724 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9726 /* check current state */
9727 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9729 /* check pipline building state */
9730 __mmplayer_check_pipeline(player);
9732 switch (MMPLAYER_CURRENT_STATE(player)) {
9733 case MM_PLAYER_STATE_READY:
9735 /* check prepare async or not.
9736 * In the case of streaming playback, it's recommned to avoid blocking wait.
9738 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9739 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9741 /* Changing back sync of rtspsrc to async */
9742 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9743 LOGD("async prepare working mode for rtsp");
9749 case MM_PLAYER_STATE_PLAYING:
9751 /* NOTE : store current point to overcome some bad operation
9752 *(returning zero when getting current position in paused state) of some
9755 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9756 LOGW("getting current position failed in paused\n");
9758 player->last_position = pos_msec;
9760 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9761 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9762 This causes problem is position calculation during normal pause resume scenarios also.
9763 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9764 if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
9765 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
9766 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
9772 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9773 LOGD("doing async pause in case of ms buff src");
9777 /* pause pipeline */
9778 ret = __gst_pause(player, async);
9780 if (ret != MM_ERROR_NONE)
9781 LOGE("failed to pause player. ret : 0x%x\n", ret);
9783 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9784 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9785 LOGE("failed to update display_rotation");
9794 _mmplayer_resume(MMHandleType hplayer)
9796 mm_player_t* player = (mm_player_t*)hplayer;
9797 int ret = MM_ERROR_NONE;
9798 gboolean async = FALSE;
9802 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9804 /* Changing back sync mode rtspsrc to async */
9805 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9806 LOGD("async resume for rtsp case");
9810 /* check current state */
9811 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9813 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9814 if (ret != MM_ERROR_NONE) {
9815 LOGE("failed to acquire sound focus.\n");
9819 ret = __gst_resume(player, async);
9821 if (ret != MM_ERROR_NONE)
9822 LOGE("failed to resume player.\n");
9830 __mmplayer_set_play_count(mm_player_t* player, gint count)
9832 MMHandleType attrs = 0;
9836 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9838 attrs = MMPLAYER_GET_ATTRS(player);
9840 LOGE("fail to get attributes.\n");
9841 return MM_ERROR_PLAYER_INTERNAL;
9844 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
9845 if (mmf_attrs_commit(attrs)) /* return -1 if error */
9846 LOGE("failed to commit\n");
9850 return MM_ERROR_NONE;
9854 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
9856 mm_player_t* player = (mm_player_t*)hplayer;
9857 gint64 start_pos = 0;
9863 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9864 MMPLAYER_RETURN_VAL_IF_FAIL(end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT);
9866 player->section_repeat = TRUE;
9867 player->section_repeat_start = start;
9868 player->section_repeat_end = end;
9870 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
9871 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
9873 __mmplayer_set_play_count(player, infinity);
9875 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9876 player->playback_rate,
9878 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9879 GST_SEEK_TYPE_SET, start_pos,
9880 GST_SEEK_TYPE_SET, end_pos))) {
9881 LOGE("failed to activate section repeat\n");
9883 return MM_ERROR_PLAYER_SEEK;
9886 LOGD("succeeded to set section repeat from %d to %d\n",
9887 player->section_repeat_start, player->section_repeat_end);
9891 return MM_ERROR_NONE;
9895 __mmplayer_set_pcm_extraction(mm_player_t* player)
9897 gint64 start_nsec = 0;
9898 gint64 end_nsec = 0;
9899 gint64 dur_nsec = 0;
9900 gint64 dur_msec = 0;
9901 int required_start = 0;
9902 int required_end = 0;
9907 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9909 mm_attrs_multiple_get(player->attrs,
9911 "pcm_extraction_start_msec", &required_start,
9912 "pcm_extraction_end_msec", &required_end,
9915 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9917 if (required_start == 0 && required_end == 0) {
9918 LOGD("extracting entire stream");
9919 return MM_ERROR_NONE;
9920 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9921 LOGD("invalid range for pcm extraction");
9922 return MM_ERROR_INVALID_ARGUMENT;
9926 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9928 LOGE("failed to get duration");
9929 return MM_ERROR_PLAYER_INTERNAL;
9931 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9933 if (dur_msec < required_end) {
9935 LOGD("invalid end pos for pcm extraction");
9936 return MM_ERROR_INVALID_ARGUMENT;
9939 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9940 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9942 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9945 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9946 GST_SEEK_TYPE_SET, start_nsec,
9947 GST_SEEK_TYPE_SET, end_nsec))) {
9948 LOGE("failed to seek for pcm extraction\n");
9950 return MM_ERROR_PLAYER_SEEK;
9953 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9957 return MM_ERROR_NONE;
9961 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
9963 mm_player_t* player = (mm_player_t*)hplayer;
9969 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9971 player->section_repeat = FALSE;
9973 __mmplayer_set_play_count(player, onetime);
9975 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
9977 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9980 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9981 GST_SEEK_TYPE_SET, cur_pos,
9982 GST_SEEK_TYPE_SET, player->duration))) {
9983 LOGE("failed to deactivate section repeat\n");
9985 return MM_ERROR_PLAYER_SEEK;
9990 return MM_ERROR_NONE;
9994 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9996 mm_player_t* player = (mm_player_t*)hplayer;
9997 gint64 pos_msec = 0;
9998 int ret = MM_ERROR_NONE;
10000 signed long long start = 0, stop = 0;
10001 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
10004 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10005 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
10007 /* The sound of video is not supported under 0.0 and over 2.0. */
10008 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
10009 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
10012 _mmplayer_set_mute(hplayer, mute);
10014 if (player->playback_rate == rate)
10015 return MM_ERROR_NONE;
10017 /* If the position is reached at start potion during fast backward, EOS is posted.
10018 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
10020 player->playback_rate = rate;
10022 current_state = MMPLAYER_CURRENT_STATE(player);
10024 if (current_state != MM_PLAYER_STATE_PAUSED)
10025 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
10027 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
10029 if ((current_state == MM_PLAYER_STATE_PAUSED)
10030 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
10031 LOGW("returning last point : %lld\n", player->last_position);
10032 pos_msec = player->last_position;
10037 stop = GST_CLOCK_TIME_NONE;
10039 start = GST_CLOCK_TIME_NONE;
10043 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10044 player->playback_rate,
10046 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
10047 GST_SEEK_TYPE_SET, start,
10048 GST_SEEK_TYPE_SET, stop)) {
10049 LOGE("failed to set speed playback\n");
10050 return MM_ERROR_PLAYER_SEEK;
10053 LOGD("succeeded to set speed playback as %0.1f\n", rate);
10057 return MM_ERROR_NONE;;
10061 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
10063 mm_player_t* player = (mm_player_t*)hplayer;
10064 int ret = MM_ERROR_NONE;
10068 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10070 /* check pipline building state */
10071 __mmplayer_check_pipeline(player);
10073 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
10081 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
10083 mm_player_t* player = (mm_player_t*)hplayer;
10084 int ret = MM_ERROR_NONE;
10086 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10088 ret = __gst_get_position(player, format, position);
10094 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
10096 mm_player_t* player = (mm_player_t*)hplayer;
10097 int ret = MM_ERROR_NONE;
10099 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10101 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
10107 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
10109 mm_player_t* player = (mm_player_t*)hplayer;
10110 int ret = MM_ERROR_NONE;
10114 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10116 ret = __gst_adjust_subtitle_position(player, format, position);
10123 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
10125 mm_player_t* player = (mm_player_t*)hplayer;
10126 int ret = MM_ERROR_NONE;
10130 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10132 ret = __gst_adjust_video_position(player, offset);
10140 __mmplayer_is_midi_type(gchar* str_caps)
10142 if ((g_strrstr(str_caps, "audio/midi")) ||
10143 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
10144 (g_strrstr(str_caps, "application/x-smaf")) ||
10145 (g_strrstr(str_caps, "audio/x-imelody")) ||
10146 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
10147 (g_strrstr(str_caps, "audio/xmf")) ||
10148 (g_strrstr(str_caps, "audio/mxmf"))) {
10157 __mmplayer_is_only_mp3_type(gchar *str_caps)
10159 if (g_strrstr(str_caps, "application/x-id3") ||
10160 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
10166 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
10168 GstStructure* caps_structure = NULL;
10169 gint samplerate = 0;
10173 MMPLAYER_RETURN_IF_FAIL(player && caps);
10175 caps_structure = gst_caps_get_structure(caps, 0);
10177 /* set stream information */
10178 gst_structure_get_int(caps_structure, "rate", &samplerate);
10179 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
10181 gst_structure_get_int(caps_structure, "channels", &channels);
10182 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
10184 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
10188 __mmplayer_update_content_type_info(mm_player_t* player)
10191 MMPLAYER_RETURN_IF_FAIL(player && player->type);
10193 if (__mmplayer_is_midi_type(player->type)) {
10194 player->bypass_audio_effect = TRUE;
10195 } else if (g_strrstr(player->type, "application/x-hls")) {
10196 /* If it can't know exact type when it parses uri because of redirection case,
10197 * it will be fixed by typefinder or when doing autoplugging.
10199 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10200 if (player->streamer) {
10201 player->streamer->is_adaptive_streaming = TRUE;
10202 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10203 player->streamer->buffering_req.runtime_second = 5;
10205 } else if (g_strrstr(player->type, "application/dash+xml")) {
10206 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10213 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
10214 GstCaps *caps, gpointer data)
10216 mm_player_t* player = (mm_player_t*)data;
10217 GstPad* pad = NULL;
10221 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
10223 /* store type string */
10224 MMPLAYER_FREEIF(player->type);
10225 player->type = gst_caps_to_string(caps);
10227 LOGD("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
10229 if ((!MMPLAYER_IS_WFD_STREAMING(player)) &&
10230 (!MMPLAYER_IS_RTSP_STREAMING(player)) &&
10231 (g_strrstr(player->type, "audio/x-raw-int"))) {
10232 LOGE("not support media format\n");
10234 if (player->msg_posted == FALSE) {
10235 MMMessageParamType msg_param;
10236 memset(&msg_param, 0, sizeof(MMMessageParamType));
10238 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10239 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10241 /* don't post more if one was sent already */
10242 player->msg_posted = TRUE;
10247 __mmplayer_update_content_type_info(player);
10249 pad = gst_element_get_static_pad(tf, "src");
10251 LOGE("fail to get typefind src pad.\n");
10255 if (player->use_decodebin) {
10256 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
10257 gboolean async = FALSE;
10258 LOGE("failed to autoplug %s\n", player->type);
10260 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10262 if (async && player->msg_posted == FALSE)
10263 __mmplayer_handle_missed_plugin(player);
10269 if (!__mmplayer_try_to_plug(player, pad, caps)) {
10270 gboolean async = FALSE;
10271 LOGE("failed to autoplug %s\n", player->type);
10273 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10275 if (async && player->msg_posted == FALSE)
10276 __mmplayer_handle_missed_plugin(player);
10281 /* finish autopluging if no dynamic pad waiting */
10282 if ((!player->have_dynamic_pad) && (!player->has_many_types)) {
10283 if (!MMPLAYER_IS_RTSP_STREAMING(player))
10284 __mmplayer_pipeline_complete(NULL, (gpointer)player);
10289 gst_object_unref(GST_OBJECT(pad));
10296 static GstElement *
10297 __mmplayer_create_decodebin(mm_player_t* player)
10299 GstElement *decodebin = NULL;
10303 /* create decodebin */
10304 decodebin = gst_element_factory_make("decodebin", NULL);
10307 LOGE("fail to create decodebin\n");
10311 /* raw pad handling signal */
10312 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10313 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10315 /* no-more-pad pad handling signal */
10316 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10317 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10319 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10320 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10322 /* This signal is emitted when a pad for which there is no further possible
10323 decoding is added to the decodebin.*/
10324 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10325 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
10327 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10328 before looking for any elements that can handle that stream.*/
10329 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10330 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10332 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10333 before looking for any elements that can handle that stream.*/
10334 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10335 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10337 /* This signal is emitted once decodebin has finished decoding all the data.*/
10338 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10339 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10341 /* This signal is emitted when a element is added to the bin.*/
10342 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10343 G_CALLBACK(__mmplayer_gst_element_added), player);
10350 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10352 MMPlayerGstElement* mainbin = NULL;
10353 GstElement* decodebin = NULL;
10354 GstElement* queue2 = NULL;
10355 GstPad* sinkpad = NULL;
10356 GstPad* qsrcpad = NULL;
10357 gint64 dur_bytes = 0L;
10359 guint max_buffer_size_bytes = 0;
10360 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
10363 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10365 mainbin = player->pipeline->mainbin;
10367 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10368 (MMPLAYER_IS_HTTP_STREAMING(player))) {
10369 LOGD("creating http streaming buffering queue(queue2)\n");
10371 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
10372 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10374 queue2 = gst_element_factory_make("queue2", "queue2");
10376 LOGE("failed to create buffering queue element\n");
10380 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
10381 LOGE("failed to add buffering queue\n");
10385 sinkpad = gst_element_get_static_pad(queue2, "sink");
10386 qsrcpad = gst_element_get_static_pad(queue2, "src");
10388 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10389 LOGE("failed to link buffering queue\n");
10393 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10394 LOGE("fail to get duration.\n");
10396 LOGD("dur_bytes = %lld\n", dur_bytes);
10398 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
10400 if (dur_bytes > 0) {
10401 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
10402 type = MUXED_BUFFER_TYPE_FILE;
10404 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
10405 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
10411 /* NOTE : we cannot get any duration info from ts container in case of streaming */
10412 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10413 if (!g_strrstr(player->type, "video/mpegts")) {
10414 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
10415 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10417 __mm_player_streaming_set_queue2(player->streamer,
10420 max_buffer_size_bytes,
10421 player->ini.http_buffering_time,
10423 player->ini.http_buffering_limit, // no meaning
10425 player->http_file_buffering_path,
10426 (guint64)dur_bytes);
10429 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
10430 LOGE("failed to sync queue2 state with parent\n");
10436 gst_object_unref(GST_OBJECT(sinkpad));
10438 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10439 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10443 /* create decodebin */
10444 decodebin = __mmplayer_create_decodebin(player);
10447 LOGE("can not create autoplug element\n");
10451 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
10452 LOGE("failed to add decodebin\n");
10456 /* to force caps on the decodebin element and avoid reparsing stuff by
10457 * typefind. It also avoids a deadlock in the way typefind activates pads in
10458 * the state change */
10459 g_object_set(decodebin, "sink-caps", caps, NULL);
10461 sinkpad = gst_element_get_static_pad(decodebin, "sink");
10463 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10464 LOGE("failed to link decodebin\n");
10468 gst_object_unref(GST_OBJECT(sinkpad));
10470 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10471 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10473 /* set decodebin property about buffer in streaming playback. *
10474 * in case of hls, it does not need to have big buffer *
10475 * because it is kind of adaptive streaming. */
10476 if (((!MMPLAYER_IS_HTTP_PD(player)) &&
10477 (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING(player)) {
10478 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10479 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10480 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
10482 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
10483 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10484 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10487 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
10488 "high-percent", (gint)player->ini.http_buffering_limit,
10489 "low-percent", 1, // 1%
10490 "max-size-bytes", max_size_bytes,
10491 "max-size-time", (guint64)(max_size_time * GST_SECOND),
10492 "max-size-buffers", 0, NULL); // disable or automatic
10495 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
10496 LOGE("failed to sync decodebin state with parent\n");
10507 gst_object_unref(GST_OBJECT(sinkpad));
10510 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10511 * You need to explicitly set elements to the NULL state before
10512 * dropping the final reference, to allow them to clean up.
10514 gst_element_set_state(queue2, GST_STATE_NULL);
10516 /* And, it still has a parent "player".
10517 * You need to let the parent manage the object instead of unreffing the object directly.
10519 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10520 gst_object_unref(queue2);
10525 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10526 * You need to explicitly set elements to the NULL state before
10527 * dropping the final reference, to allow them to clean up.
10529 gst_element_set_state(decodebin, GST_STATE_NULL);
10531 /* And, it still has a parent "player".
10532 * You need to let the parent manage the object instead of unreffing the object directly.
10535 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10536 gst_object_unref(decodebin);
10543 /* it will return first created element */
10545 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps)
10547 MMPlayerGstElement* mainbin = NULL;
10548 const char* mime = NULL;
10549 const GList* item = NULL;
10550 const gchar* klass = NULL;
10551 GstCaps* res = NULL;
10552 gboolean skip = FALSE;
10553 GstPad* queue_pad = NULL;
10554 GstElement* queue = NULL;
10555 GstElement *element = NULL;
10559 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10561 mainbin = player->pipeline->mainbin;
10563 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10565 /* return if we got raw output */
10566 if (g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
10567 || g_str_has_prefix(mime, "text/plain") || g_str_has_prefix(mime, "text/x-pango-markup")) {
10569 element = (GstElement*)gst_pad_get_parent(pad);
10570 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
10571 * No queue will be added. I think it can caused breaking sound when playing raw audio
10572 * frames but there's no different. Decodebin also doesn't add with those wav fils.
10573 * Anyway, currentely raw-queue seems not necessary.
10576 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
10577 * has linked. if so, we need to add queue for quality of output. note that
10578 * decodebin also has same problem.
10580 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
10582 /* add queue if needed */
10583 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
10584 || g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text")) {
10585 LOGD("adding raw queue\n");
10587 queue = gst_element_factory_make("queue", NULL);
10589 LOGW("failed to create queue\n");
10594 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
10595 LOGW("failed to set state READY to queue\n");
10599 /* add to pipeline */
10600 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
10601 LOGW("failed to add queue\n");
10606 queue_pad = gst_element_get_static_pad(queue, "sink");
10608 if (GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad)) {
10609 LOGW("failed to link queue\n");
10612 gst_object_unref(GST_OBJECT(queue_pad));
10616 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
10617 LOGW("failed to set state PAUSED to queue\n");
10621 /* replace given pad to queue:src */
10622 pad = gst_element_get_static_pad(queue, "src");
10624 LOGW("failed to get pad from queue\n");
10629 /* check if player can do start continually */
10630 MMPLAYER_CHECK_CMD_IF_EXIT(player);
10632 if (__mmplayer_link_sink(player, pad))
10633 __mmplayer_gst_decode_callback(element, pad, player);
10635 gst_object_unref(GST_OBJECT(element));
10641 item = player->factories;
10642 for (; item != NULL; item = item->next) {
10643 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
10649 /* filtering exclude keyword */
10650 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10651 if (g_strrstr(GST_OBJECT_NAME(factory),
10652 player->ini.exclude_element_keyword[idx])) {
10653 LOGW("skipping [%s] by exculde keyword [%s]\n",
10654 GST_OBJECT_NAME(factory),
10655 player->ini.exclude_element_keyword[idx]);
10662 if (MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME(factory), "omx_mpeg4dec")) {
10663 // omx decoder can not support mpeg4video data partitioned
10664 // rtsp streaming didn't know mpeg4video data partitioned format
10665 // so, if rtsp playback, player will skip omx_mpeg4dec.
10666 LOGW("skipping [%s] when rtsp streaming \n",
10667 GST_OBJECT_NAME(factory));
10672 if (skip) continue;
10674 /* check factory class for filtering */
10675 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS);
10677 /*parsers are not required in case of external feeder*/
10678 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_MS_BUFF_SRC(player))
10681 /* NOTE : msl don't need to use image plugins.
10682 * So, those plugins should be skipped for error handling.
10684 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10685 LOGD("skipping [%s] by not required\n", GST_OBJECT_NAME(factory));
10689 /* check pad compatability */
10690 for (pads = gst_element_factory_get_static_pad_templates(factory);
10691 pads != NULL; pads = pads->next) {
10692 GstStaticPadTemplate *temp1 = pads->data;
10693 GstCaps* static_caps = NULL;
10695 if (temp1->direction != GST_PAD_SINK
10696 || temp1->presence != GST_PAD_ALWAYS)
10699 /* using existing caps */
10700 if (GST_IS_CAPS(&temp1->static_caps.caps))
10701 static_caps = gst_caps_ref(temp1->static_caps.caps);
10704 static_caps = gst_caps_from_string(temp1->static_caps.string);
10706 res = gst_caps_intersect((GstCaps*)caps, static_caps);
10707 gst_caps_unref(static_caps);
10708 static_caps = NULL;
10710 if (res && !gst_caps_is_empty(res)) {
10711 GstElement *new_element;
10712 GList *elements = player->parsers;
10713 char *name_template = g_strdup(temp1->name_template);
10714 gchar *name_to_plug = GST_OBJECT_NAME(factory);
10715 gst_caps_unref(res);
10717 /* check ALP Codec can be used or not */
10718 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10719 /* consider mp3 audio only */
10720 if (!MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type)) {
10721 /* try to use ALP decoder first instead of selected decoder */
10722 GstElement *element = NULL;
10723 GstElementFactory * element_facory;
10724 gchar *path = NULL;
10725 guint64 data_size = 0;
10726 #define MIN_THRESHOLD_SIZE 320 * 1024 // 320K
10729 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
10731 if (stat(path, &sb) == 0)
10732 data_size = (guint64)sb.st_size;
10733 LOGD("file size : %u", data_size);
10735 if (data_size > MIN_THRESHOLD_SIZE) {
10736 LOGD("checking if ALP can be used or not");
10737 element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
10739 /* check availability because multi-instance is not supported */
10740 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
10742 if (ret != GST_STATE_CHANGE_SUCCESS) {
10743 // use just selected decoder
10744 gst_object_unref(element);
10745 } else if (ret == GST_STATE_CHANGE_SUCCESS) {
10746 // replace facotry to use omx
10748 gst_element_set_state(element, GST_STATE_NULL);
10749 gst_object_unref(element);
10751 element_facory = gst_element_factory_find("omx_mp3dec");
10752 /* replace, otherwise use selected thing instead */
10753 if (element_facory) {
10754 factory = element_facory;
10755 name_to_plug = GST_OBJECT_NAME(factory);
10761 } else if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
10762 if (g_strrstr(GST_OBJECT_NAME(factory), "omx_")) {
10763 char *env = getenv("MM_PLAYER_HW_CODEC_DISABLE");
10765 if (strncasecmp(env, "yes", 3) == 0) {
10766 LOGD("skipping [%s] by disabled\n", name_to_plug);
10767 MMPLAYER_FREEIF(name_template);
10774 LOGD("found %s to plug\n", name_to_plug);
10776 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
10777 if (!new_element) {
10778 LOGE("failed to create element [%s]. continue with next.\n",
10779 GST_OBJECT_NAME(factory));
10781 MMPLAYER_FREEIF(name_template);
10786 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
10787 * because parser can accept its own output as input.
10789 if (g_strrstr(klass, "Parser")) {
10790 gchar *selected = NULL;
10792 for (; elements; elements = g_list_next(elements)) {
10793 gchar *element_name = elements->data;
10795 if (g_strrstr(element_name, name_to_plug)) {
10796 LOGD("but, %s already linked, so skipping it\n", name_to_plug);
10802 MMPLAYER_FREEIF(name_template);
10806 selected = g_strdup(name_to_plug);
10807 player->parsers = g_list_append(player->parsers, selected);
10810 /* store specific handles for futher control */
10811 if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
10812 /* FIXIT : first value will be overwritten if there's more
10813 * than 1 demuxer/parser
10815 LOGD("plugged element is demuxer. take it\n");
10816 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
10817 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
10819 /*Added for multi audio support */
10820 if (g_strrstr(klass, "Demux")) {
10821 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
10822 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
10824 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
10825 no-more-pad signal. this may cause wrong content attributes at PAUSED state
10826 this code should be removed after mpegtsdemux is fixed */
10827 if (g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux")) {
10828 LOGW("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
10829 player->no_more_pad = TRUE;
10832 if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
10833 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri, NULL);
10834 } else if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, pad)) {
10835 if (mainbin[MMPLAYER_M_DEC1].gst == NULL) {
10836 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
10837 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
10838 mainbin[MMPLAYER_M_DEC1].gst = new_element;
10839 } else if (mainbin[MMPLAYER_M_DEC2].gst == NULL) {
10840 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
10841 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
10842 mainbin[MMPLAYER_M_DEC2].gst = new_element;
10844 /* NOTE : IF one codec is found, add it to supported_codec and remove from
10845 * missing plugin. Both of them are used to check what's supported codec
10846 * before returning result of play start. And, missing plugin should be
10847 * updated here for multi track files.
10849 if (g_str_has_prefix(mime, "video")) {
10850 GstPad *src_pad = NULL;
10851 GstPadTemplate *pad_templ = NULL;
10852 GstCaps *caps = NULL;
10853 gchar *caps_str = NULL;
10855 LOGD("found VIDEO decoder\n");
10856 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10857 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10859 src_pad = gst_element_get_static_pad(new_element, "src");
10860 pad_templ = gst_pad_get_pad_template(src_pad);
10861 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
10863 caps_str = gst_caps_to_string(caps);
10866 MMPLAYER_FREEIF(caps_str);
10867 gst_object_unref(src_pad);
10868 } else if (g_str_has_prefix(mime, "audio")) {
10869 LOGD("found AUDIO decoder\n");
10870 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10871 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10875 if (!__mmplayer_close_link(player, pad, new_element,
10876 name_template, gst_element_factory_get_static_pad_templates(factory))) {
10877 MMPLAYER_FREEIF(name_template);
10878 if (player->keep_detecting_vcodec)
10881 /* Link is failed even though a supportable codec is found. */
10882 __mmplayer_check_not_supported_codec(player, klass, mime);
10884 LOGE("failed to call _close_link\n");
10888 MMPLAYER_FREEIF(name_template);
10892 gst_caps_unref(res);
10897 /* There is no available codec. */
10898 __mmplayer_check_not_supported_codec(player, klass, mime);
10906 gst_object_unref(queue);
10909 gst_object_unref(queue_pad);
10912 gst_object_unref(element);
10919 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
10923 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10924 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10926 LOGD("class : %s, mime : %s \n", factory_class, mime);
10928 /* add missing plugin */
10929 /* NOTE : msl should check missing plugin for image mime type.
10930 * Some motion jpeg clips can have playable audio track.
10931 * So, msl have to play audio after displaying popup written video format not supported.
10933 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10934 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10935 LOGD("not found demuxer\n");
10936 player->not_found_demuxer = TRUE;
10937 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10943 if (!g_strrstr(factory_class, "Demuxer")) {
10944 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10945 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
10946 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10948 /* check that clip have multi tracks or not */
10949 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10950 LOGD("video plugin is already linked\n");
10952 LOGW("add VIDEO to missing plugin\n");
10953 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10955 } else if (g_str_has_prefix(mime, "audio")) {
10956 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10957 LOGD("audio plugin is already linked\n");
10959 LOGW("add AUDIO to missing plugin\n");
10960 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10968 return MM_ERROR_NONE;
10973 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10975 mm_player_t* player = (mm_player_t*)data;
10979 MMPLAYER_RETURN_IF_FAIL(player);
10981 /* remove fakesink. */
10982 if (!__mmplayer_gst_remove_fakesink(player,
10983 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10984 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10985 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10986 * source element are not same. To overcome this situation, this function will called
10987 * several places and several times. Therefore, this is not an error case.
10992 LOGD("pipeline has completely constructed\n");
10994 if ((player->ini.async_start) &&
10995 (player->msg_posted == FALSE) &&
10996 (player->cmd >= MMPLAYER_COMMAND_START))
10997 __mmplayer_handle_missed_plugin(player);
10999 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
11003 __mmplayer_verify_next_play_path(mm_player_t *player)
11005 MMHandleType attrs = 0;
11006 MMPlayerParseProfile profile;
11007 gint uri_idx = 0, check_cnt = 0;
11009 gint mode = MM_PLAYER_PD_MODE_NONE;
11013 guint num_of_list = 0;
11014 static int profile_tv = -1;
11018 LOGD("checking for gapless play");
11020 if (player->pipeline->textbin) {
11021 LOGE("subtitle path is enabled. gapless play is not supported.\n");
11025 attrs = MMPLAYER_GET_ATTRS(player);
11027 LOGE("fail to get attributes.\n");
11031 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
11033 if (__builtin_expect(profile_tv == -1, 0)) {
11035 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
11036 switch (*profileName) {
11046 /* gapless playback is not supported in case of video at TV profile. */
11047 if (profile_tv && video) {
11048 LOGW("not support video gapless playback");
11052 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
11053 if (mode == TRUE) {
11059 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
11060 LOGE("can not get play count\n");
11062 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
11063 LOGE("can not get gapless mode\n");
11065 if (video && !gapless) {
11066 LOGW("not enabled video gapless playback");
11070 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
11074 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
11078 num_of_list = g_list_length(player->uri_info.uri_list);
11080 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
11082 if (num_of_list == 0) {
11083 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
11084 LOGE("can not get profile_uri\n");
11089 LOGE("uri list is empty.\n");
11093 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11094 LOGD("add original path : %s ", uri);
11100 uri_idx = player->uri_info.uri_idx;
11105 if (check_cnt > num_of_list) {
11106 LOGE("there is no valid uri.");
11110 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
11112 if (uri_idx < num_of_list-1) {
11115 if ((count <= 1) && (count != -1)) {
11116 LOGD("no repeat.");
11118 } else if (count > 1) {
11119 /* decrease play count */
11120 /* we succeeded to rewind. update play count and then wait for next EOS */
11123 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
11125 /* commit attribute */
11126 if (mmf_attrs_commit(attrs))
11127 LOGE("failed to commit attribute\n");
11130 /* count < 0 : repeat continually */
11134 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11135 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
11138 LOGW("next uri does not exist\n");
11142 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
11143 LOGE("failed to parse profile\n");
11147 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
11148 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
11149 LOGW("uri type is not supported(%d).", profile.uri_type);
11156 player->uri_info.uri_idx = uri_idx;
11157 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11159 if (mmf_attrs_commit(player->attrs)) {
11160 LOGE("failed to commit.\n");
11164 LOGD("next uri %s(%d)\n", uri, uri_idx);
11170 LOGE("unable to play next path. EOS will be posted soon.\n");
11175 __mmplayer_initialize_next_play(mm_player_t *player)
11181 player->smooth_streaming = FALSE;
11182 player->videodec_linked = 0;
11183 player->audiodec_linked = 0;
11184 player->videosink_linked = 0;
11185 player->audiosink_linked = 0;
11186 player->textsink_linked = 0;
11187 player->is_external_subtitle_present = FALSE;
11188 player->is_external_subtitle_added_now = FALSE;
11189 player->not_supported_codec = MISSING_PLUGIN_NONE;
11190 player->can_support_codec = FOUND_PLUGIN_NONE;
11191 player->pending_seek.is_pending = FALSE;
11192 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11193 player->pending_seek.pos = 0;
11194 player->msg_posted = FALSE;
11195 player->has_many_types = FALSE;
11196 player->no_more_pad = FALSE;
11197 player->not_found_demuxer = 0;
11198 player->doing_seek = FALSE;
11199 player->max_audio_channels = 0;
11200 player->is_subtitle_force_drop = FALSE;
11201 player->play_subtitle = FALSE;
11202 player->adjust_subtitle_pos = 0;
11204 player->updated_bitrate_count = 0;
11205 player->total_bitrate = 0;
11206 player->updated_maximum_bitrate_count = 0;
11207 player->total_maximum_bitrate = 0;
11209 _mmplayer_track_initialize(player);
11210 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11212 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11213 player->bitrate[i] = 0;
11214 player->maximum_bitrate[i] = 0;
11217 if (player->v_stream_caps) {
11218 gst_caps_unref(player->v_stream_caps);
11219 player->v_stream_caps = NULL;
11222 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11223 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
11225 /* clean found parsers */
11226 if (player->parsers) {
11227 GList *parsers = player->parsers;
11228 for (; parsers; parsers = g_list_next(parsers)) {
11229 gchar *name = parsers->data;
11230 MMPLAYER_FREEIF(name);
11232 g_list_free(player->parsers);
11233 player->parsers = NULL;
11236 /* clean found audio decoders */
11237 if (player->audio_decoders) {
11238 GList *a_dec = player->audio_decoders;
11239 for (; a_dec; a_dec = g_list_next(a_dec)) {
11240 gchar *name = a_dec->data;
11241 MMPLAYER_FREEIF(name);
11243 g_list_free(player->audio_decoders);
11244 player->audio_decoders = NULL;
11251 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11253 MMPlayerGstElement *mainbin = NULL;
11254 MMMessageParamType msg_param = {0,};
11255 GstElement *element = NULL;
11256 MMHandleType attrs = 0;
11258 enum MainElementID elemId = MMPLAYER_M_NUM;
11262 if ((player == NULL) ||
11263 (player->pipeline == NULL) ||
11264 (player->pipeline->mainbin == NULL)) {
11265 LOGE("player is null.\n");
11269 mainbin = player->pipeline->mainbin;
11270 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11272 attrs = MMPLAYER_GET_ATTRS(player);
11274 LOGE("fail to get attributes.\n");
11278 /* Initialize Player values */
11279 __mmplayer_initialize_next_play(player);
11281 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11283 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
11284 LOGE("failed to parse profile\n");
11285 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11289 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11290 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
11291 LOGE("it's dash or hls. not support.");
11292 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11297 switch (player->profile.uri_type) {
11299 case MM_PLAYER_URI_TYPE_FILE:
11301 LOGD("using filesrc for 'file://' handler.\n");
11302 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
11303 LOGE("failed to get storage info");
11307 element = gst_element_factory_make("filesrc", "source");
11310 LOGE("failed to create filesrc\n");
11314 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
11317 case MM_PLAYER_URI_TYPE_URL_HTTP:
11319 gchar *user_agent, *proxy, *cookies, **cookie_list;
11320 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11321 user_agent = proxy = cookies = NULL;
11322 cookie_list = NULL;
11324 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11326 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11329 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
11331 /* get attribute */
11332 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
11333 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
11334 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
11335 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
11337 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11338 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
11339 LOGD("get timeout from ini\n");
11340 http_timeout = player->ini.http_timeout;
11343 /* get attribute */
11344 SECURE_LOGD("location : %s\n", player->profile.uri);
11345 SECURE_LOGD("cookies : %s\n", cookies);
11346 SECURE_LOGD("proxy : %s\n", proxy);
11347 SECURE_LOGD("user_agent : %s\n", user_agent);
11348 LOGD("timeout : %d\n", http_timeout);
11350 /* setting property to streaming source */
11351 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11352 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11353 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11355 /* check if prosy is vailid or not */
11356 if (util_check_valid_url(proxy))
11357 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11358 /* parsing cookies */
11359 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
11360 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11362 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11366 LOGE("not support uri type %d\n", player->profile.uri_type);
11371 LOGE("no source element was created.\n");
11375 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11376 LOGE("failed to add source element to pipeline\n");
11377 gst_object_unref(GST_OBJECT(element));
11382 /* take source element */
11383 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11384 mainbin[MMPLAYER_M_SRC].gst = element;
11388 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
11389 if (player->streamer == NULL) {
11390 player->streamer = __mm_player_streaming_create();
11391 __mm_player_streaming_initialize(player->streamer);
11394 elemId = MMPLAYER_M_TYPEFIND;
11395 element = gst_element_factory_make("typefind", "typefinder");
11396 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11397 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
11399 elemId = MMPLAYER_M_AUTOPLUG;
11400 element = __mmplayer_create_decodebin(player);
11403 /* check autoplug element is OK */
11405 LOGE("can not create element(%d)\n", elemId);
11409 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11410 LOGE("failed to add sinkbin to pipeline\n");
11411 gst_object_unref(GST_OBJECT(element));
11416 mainbin[elemId].id = elemId;
11417 mainbin[elemId].gst = element;
11419 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
11420 LOGE("Failed to link src - autoplug(or typefind)\n");
11424 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
11425 LOGE("Failed to change state of src element\n");
11429 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
11430 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
11431 LOGE("Failed to change state of decodebin\n");
11435 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
11436 LOGE("Failed to change state of src element\n");
11441 player->gapless.stream_changed = TRUE;
11442 player->gapless.running = TRUE;
11448 MMPLAYER_PLAYBACK_UNLOCK(player);
11450 if (!player->msg_posted) {
11451 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11452 player->msg_posted = TRUE;
11459 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11461 mm_player_selector_t *selector = &player->selector[type];
11462 MMPlayerGstElement *sinkbin = NULL;
11463 enum MainElementID selectorId = MMPLAYER_M_NUM;
11464 enum MainElementID sinkId = MMPLAYER_M_NUM;
11465 GstPad *srcpad = NULL;
11466 GstPad *sinkpad = NULL;
11467 gboolean send_notice = FALSE;
11470 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11472 LOGD("type %d", type);
11475 case MM_PLAYER_TRACK_TYPE_AUDIO:
11476 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11477 sinkId = MMPLAYER_A_BIN;
11478 sinkbin = player->pipeline->audiobin;
11480 case MM_PLAYER_TRACK_TYPE_VIDEO:
11481 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
11482 sinkId = MMPLAYER_V_BIN;
11483 sinkbin = player->pipeline->videobin;
11484 send_notice = TRUE;
11486 case MM_PLAYER_TRACK_TYPE_TEXT:
11487 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11488 sinkId = MMPLAYER_T_BIN;
11489 sinkbin = player->pipeline->textbin;
11492 LOGE("requested type is not supportable");
11497 if (player->pipeline->mainbin[selectorId].gst) {
11500 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11502 if (selector->event_probe_id != 0)
11503 gst_pad_remove_probe(srcpad, selector->event_probe_id);
11504 selector->event_probe_id = 0;
11506 if ((sinkbin) && (sinkbin[sinkId].gst)) {
11507 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11509 if (srcpad && sinkpad) {
11510 /* after getting drained signal there is no data flows, so no need to do pad_block */
11511 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11512 gst_pad_unlink(srcpad, sinkpad);
11514 /* send custom event to sink pad to handle it at video sink */
11516 LOGD("send custom event to sinkpad");
11517 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
11518 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
11519 gst_pad_send_event(sinkpad, event);
11523 gst_object_unref(sinkpad);
11526 gst_object_unref(srcpad);
11529 LOGD("selector release");
11531 /* release and unref requests pad from the selector */
11532 for (n = 0; n < selector->channels->len; n++) {
11533 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
11534 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
11536 g_ptr_array_set_size(selector->channels, 0);
11538 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11539 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11541 player->pipeline->mainbin[selectorId].gst = NULL;
11549 __mmplayer_deactivate_old_path(mm_player_t *player)
11552 MMPLAYER_RETURN_IF_FAIL(player);
11554 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11555 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
11556 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
11557 LOGE("deactivate selector error");
11561 _mmplayer_track_destroy(player);
11562 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11564 if (player->streamer) {
11565 __mm_player_streaming_deinitialize(player->streamer);
11566 __mm_player_streaming_destroy(player->streamer);
11567 player->streamer = NULL;
11570 MMPLAYER_PLAYBACK_LOCK(player);
11571 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
11578 if (!player->msg_posted) {
11579 MMMessageParamType msg = {0,};
11582 msg.code = MM_ERROR_PLAYER_INTERNAL;
11583 LOGE("next_uri_play> deactivate error");
11585 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11586 player->msg_posted = TRUE;
11591 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
11593 int result = MM_ERROR_NONE;
11594 mm_player_t* player = (mm_player_t*) hplayer;
11597 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11600 player->http_file_buffering_path = (gchar*)file_path;
11601 LOGD("temp file path: %s\n", player->http_file_buffering_path);
11607 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11609 int result = MM_ERROR_NONE;
11610 mm_player_t* player = (mm_player_t*) hplayer;
11613 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11615 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11616 if (mmf_attrs_commit(player->attrs)) {
11617 LOGE("failed to commit the original uri.\n");
11618 result = MM_ERROR_PLAYER_INTERNAL;
11620 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11621 LOGE("failed to add the original uri in the uri list.\n");
11628 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11630 mm_player_t* player = (mm_player_t*) hplayer;
11631 guint num_of_list = 0;
11635 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11636 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
11638 if (player->pipeline && player->pipeline->textbin) {
11639 LOGE("subtitle path is enabled.\n");
11640 return MM_ERROR_PLAYER_INVALID_STATE;
11643 num_of_list = g_list_length(player->uri_info.uri_list);
11645 if (is_first_path == TRUE) {
11646 if (num_of_list == 0) {
11647 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11648 LOGD("add original path : %s", uri);
11650 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
11651 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
11653 LOGD("change original path : %s", uri);
11656 MMHandleType attrs = 0;
11657 attrs = MMPLAYER_GET_ATTRS(player);
11659 if (num_of_list == 0) {
11660 char *original_uri = NULL;
11663 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
11665 if (!original_uri) {
11666 LOGE("there is no original uri.");
11667 return MM_ERROR_PLAYER_INVALID_STATE;
11670 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
11671 player->uri_info.uri_idx = 0;
11673 LOGD("add original path at first : %s(%d)", original_uri);
11677 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11678 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
11682 return MM_ERROR_NONE;
11685 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
11687 mm_player_t* player = (mm_player_t*) hplayer;
11688 char *next_uri = NULL;
11689 guint num_of_list = 0;
11692 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11694 num_of_list = g_list_length(player->uri_info.uri_list);
11696 if (num_of_list > 0) {
11697 gint uri_idx = player->uri_info.uri_idx;
11699 if (uri_idx < num_of_list-1)
11704 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11705 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
11707 *uri = g_strdup(next_uri);
11711 return MM_ERROR_NONE;
11715 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
11716 GstCaps *caps, gpointer data)
11718 mm_player_t* player = (mm_player_t*)data;
11719 const gchar* klass = NULL;
11720 const gchar* mime = NULL;
11721 gchar* caps_str = NULL;
11723 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
11724 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11725 caps_str = gst_caps_to_string(caps);
11727 LOGW("unknown type of caps : %s from %s",
11728 caps_str, GST_ELEMENT_NAME(elem));
11730 MMPLAYER_FREEIF(caps_str);
11732 /* There is no available codec. */
11733 __mmplayer_check_not_supported_codec(player, klass, mime);
11737 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
11738 GstCaps * caps, gpointer data)
11740 mm_player_t* player = (mm_player_t*)data;
11741 const char* mime = NULL;
11742 gboolean ret = TRUE;
11744 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
11745 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11747 if (g_str_has_prefix(mime, "audio")) {
11748 GstStructure* caps_structure = NULL;
11749 gint samplerate = 0;
11751 gchar *caps_str = NULL;
11753 caps_structure = gst_caps_get_structure(caps, 0);
11754 gst_structure_get_int(caps_structure, "rate", &samplerate);
11755 gst_structure_get_int(caps_structure, "channels", &channels);
11757 if ((channels > 0 && samplerate == 0)) {
11758 LOGD("exclude audio...");
11762 caps_str = gst_caps_to_string(caps);
11763 /* set it directly because not sent by TAG */
11764 if (g_strrstr(caps_str, "mobile-xmf"))
11765 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
11766 MMPLAYER_FREEIF(caps_str);
11767 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
11768 MMMessageParamType msg_param;
11769 memset(&msg_param, 0, sizeof(MMMessageParamType));
11770 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
11771 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11772 LOGD("video file is not supported on this device");
11774 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
11775 LOGD("already video linked");
11778 LOGD("found new stream");
11785 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
11786 GstCaps* caps, GstElementFactory* factory, gpointer data)
11788 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
11789 We are defining our own and will be removed when it actually exposed */
11791 GST_AUTOPLUG_SELECT_TRY,
11792 GST_AUTOPLUG_SELECT_EXPOSE,
11793 GST_AUTOPLUG_SELECT_SKIP
11794 } GstAutoplugSelectResult;
11796 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
11797 mm_player_t* player = (mm_player_t*)data;
11799 gchar* factory_name = NULL;
11800 gchar* caps_str = NULL;
11801 const gchar* klass = NULL;
11804 factory_name = GST_OBJECT_NAME(factory);
11805 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
11806 caps_str = gst_caps_to_string(caps);
11808 LOGD("found new element [%s] to link", factory_name);
11810 /* store type string */
11811 if (player->type == NULL) {
11812 player->type = gst_caps_to_string(caps);
11813 __mmplayer_update_content_type_info(player);
11816 /* filtering exclude keyword */
11817 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
11818 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
11819 LOGW("skipping [%s] by exculde keyword [%s]\n",
11820 factory_name, player->ini.exclude_element_keyword[idx]);
11822 // NOTE : does we need to check n_value against the number of item selected?
11823 result = GST_AUTOPLUG_SELECT_SKIP;
11828 /* exclude webm format */
11829 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11830 * because webm format is not supportable.
11831 * If webm is disabled in "autoplug-continue", there is no state change
11832 * failure or error because the decodebin will expose the pad directly.
11833 * It make MSL invoke _prepare_async_callback.
11834 * So, we need to disable webm format in "autoplug-select" */
11835 if (caps_str && strstr(caps_str, "webm")) {
11836 LOGW("webm is not supported");
11837 result = GST_AUTOPLUG_SELECT_SKIP;
11841 /* check factory class for filtering */
11842 /* NOTE : msl don't need to use image plugins.
11843 * So, those plugins should be skipped for error handling.
11845 if (g_strrstr(klass, "Codec/Decoder/Image")) {
11846 LOGD("skipping [%s] by not required\n", factory_name);
11847 result = GST_AUTOPLUG_SELECT_SKIP;
11851 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11852 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11853 // TO CHECK : subtitle if needed, add subparse exception.
11854 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11855 result = GST_AUTOPLUG_SELECT_SKIP;
11859 if (g_strrstr(factory_name, "mpegpsdemux")) {
11860 LOGD("skipping PS container - not support\n");
11861 result = GST_AUTOPLUG_SELECT_SKIP;
11865 if (g_strrstr(factory_name, "mssdemux"))
11866 player->smooth_streaming = TRUE;
11868 /* check ALP Codec can be used or not */
11869 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
11870 GstStructure* str = NULL;
11873 str = gst_caps_get_structure(caps, 0);
11875 gst_structure_get_int(str, "channels", &channels);
11877 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
11878 if (player->max_audio_channels < channels)
11879 player->max_audio_channels = channels;
11881 /* set stream information */
11882 if (!player->audiodec_linked)
11883 __mmplayer_set_audio_attrs(player, caps);
11884 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
11885 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
11886 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
11887 /* prepare resource manager for video decoder */
11888 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
11890 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], &resource_state) == MM_ERROR_NONE) {
11891 /* prepare resource manager for video decoder */
11892 if ((resource_state >= RESOURCE_STATE_INITIALIZED) && (resource_state < RESOURCE_STATE_ACQUIRED)) {
11893 if (_mmplayer_resource_manager_prepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], RESOURCE_TYPE_VIDEO_DECODER)
11894 != MM_ERROR_NONE) {
11895 LOGW("could not prepare for video_decoder resource, skip it.");
11896 result = GST_AUTOPLUG_SELECT_SKIP;
11902 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], &resource_state)
11903 == MM_ERROR_NONE) {
11904 /* acquire resources for video playing */
11905 if (resource_state == RESOURCE_STATE_PREPARED) {
11906 if (_mmplayer_resource_manager_acquire(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER])
11907 != MM_ERROR_NONE) {
11908 LOGE("could not acquire resources for video decoding\n");
11909 _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER]);
11917 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11918 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11921 GstStructure *str = NULL;
11922 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11924 /* don't make video because of not required */
11925 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11926 (player->set_mode.media_packet_video_stream == FALSE)) {
11927 LOGD("no video because it's not required. -> return expose");
11928 result = GST_AUTOPLUG_SELECT_EXPOSE;
11932 /* get w/h for omx state-tune */
11933 str = gst_caps_get_structure(caps, 0);
11934 gst_structure_get_int(str, "width", &width);
11937 if (player->v_stream_caps) {
11938 gst_caps_unref(player->v_stream_caps);
11939 player->v_stream_caps = NULL;
11942 player->v_stream_caps = gst_caps_copy(caps);
11943 LOGD("take caps for video state tune");
11944 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11948 if (g_strrstr(klass, "Decoder")) {
11949 const char* mime = NULL;
11950 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11952 if (g_str_has_prefix(mime, "video")) {
11953 // __mmplayer_check_video_zero_cpoy(player, factory);
11955 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11956 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11958 player->videodec_linked = 1;
11959 } else if (g_str_has_prefix(mime, "audio")) {
11960 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11961 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11963 player->audiodec_linked = 1;
11968 MMPLAYER_FREEIF(caps_str);
11975 static GValueArray*
11976 __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad,
11977 GstCaps * caps, gpointer data)
11979 //mm_player_t* player = (mm_player_t*)data;
11981 LOGD("decodebin is requesting factories for caps [%s] from element[%s]",
11982 gst_caps_to_string(caps),
11983 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
11990 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11993 //mm_player_t* player = (mm_player_t*)data;
11994 GstCaps* caps = NULL;
11996 LOGD("[Decodebin2] pad-removed signal\n");
11998 caps = gst_pad_query_caps(new_pad, NULL);
12000 gchar* caps_str = NULL;
12001 caps_str = gst_caps_to_string(caps);
12003 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
12005 MMPLAYER_FREEIF(caps_str);
12010 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
12012 mm_player_t* player = (mm_player_t*)data;
12013 GstIterator *iter = NULL;
12014 GValue item = { 0, };
12015 GstPad *pad = NULL;
12016 gboolean done = FALSE;
12017 gboolean is_all_drained = TRUE;
12020 MMPLAYER_RETURN_IF_FAIL(player);
12022 LOGD("__mmplayer_gst_decode_drained");
12024 if (player->use_deinterleave == TRUE) {
12025 LOGD("group playing mode.");
12029 if (!MMPLAYER_CMD_TRYLOCK(player)) {
12030 LOGW("Fail to get cmd lock");
12034 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
12035 !__mmplayer_verify_next_play_path(player)) {
12036 LOGD("decoding is finished.");
12037 __mmplayer_reset_gapless_state(player);
12038 MMPLAYER_CMD_UNLOCK(player);
12042 player->gapless.reconfigure = TRUE;
12044 /* check decodebin src pads whether they received EOS or not */
12045 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12048 switch (gst_iterator_next(iter, &item)) {
12049 case GST_ITERATOR_OK:
12050 pad = g_value_get_object(&item);
12051 if (pad && !GST_PAD_IS_EOS(pad)) {
12052 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
12053 is_all_drained = FALSE;
12056 g_value_reset(&item);
12058 case GST_ITERATOR_RESYNC:
12059 gst_iterator_resync(iter);
12061 case GST_ITERATOR_ERROR:
12062 case GST_ITERATOR_DONE:
12067 g_value_unset(&item);
12068 gst_iterator_free(iter);
12070 if (!is_all_drained) {
12071 LOGD("Wait util the all pads get EOS.");
12072 MMPLAYER_CMD_UNLOCK(player);
12077 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
12078 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
12080 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
12081 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
12082 __mmplayer_deactivate_old_path(player);
12083 MMPLAYER_CMD_UNLOCK(player);
12089 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
12091 mm_player_t* player = (mm_player_t*)data;
12092 const gchar* klass = NULL;
12093 gchar* factory_name = NULL;
12095 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
12096 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
12098 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
12100 if (__mmplayer_add_dump_buffer_probe(player, element))
12101 LOGD("add buffer probe");
12104 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
12105 gchar* selected = NULL;
12106 selected = g_strdup(GST_ELEMENT_NAME(element));
12107 player->audio_decoders = g_list_append(player->audio_decoders, selected);
12111 if (g_strrstr(klass, "Parser")) {
12112 gchar* selected = NULL;
12114 selected = g_strdup(factory_name);
12115 player->parsers = g_list_append(player->parsers, selected);
12118 if (g_strrstr(klass, "Demuxer/Adaptive")) {
12119 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
12120 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
12122 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
12123 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
12125 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
12126 "max-bandwidth", player->adaptive_info.limit.bandwidth,
12127 "max-video-width", player->adaptive_info.limit.width,
12128 "max-video-height", player->adaptive_info.limit.height, NULL);
12130 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
12131 /* FIXIT : first value will be overwritten if there's more
12132 * than 1 demuxer/parser
12135 //LOGD("plugged element is demuxer. take it\n");
12136 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
12137 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
12139 /*Added for multi audio support */ // Q. del?
12140 if (g_strrstr(klass, "Demux")) {
12141 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
12142 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
12146 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
12147 int surface_type = 0;
12149 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
12152 // to support trust-zone only
12153 if (g_strrstr(factory_name, "asfdemux")) {
12154 LOGD("set file-location %s\n", player->profile.uri);
12155 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
12157 if (player->video_hub_download_mode == TRUE)
12158 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
12159 } else if (g_strrstr(factory_name, "legacyh264parse")) {
12160 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
12161 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
12162 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
12163 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
12164 (__mmplayer_is_only_mp3_type(player->type))) {
12165 LOGD("[mpegaudioparse] set streaming pull mode.");
12166 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
12168 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw))
12169 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
12172 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
12173 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
12174 LOGD("plugged element is multiqueue. take it\n");
12176 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
12177 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
12179 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
12180 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) {
12181 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
12182 __mm_player_streaming_set_multiqueue(player->streamer,
12185 player->ini.http_buffering_time,
12187 player->ini.http_buffering_limit);
12189 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12196 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
12199 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12201 if (MMPLAYER_IS_STREAMING(player))
12204 /* This callback can be set to music player only. */
12205 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
12206 LOGW("audio callback is not supported for video");
12210 if (player->audio_stream_cb) {
12211 GstPad *pad = NULL;
12213 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
12216 LOGE("failed to get sink pad from audiosink to probe data\n");
12219 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
12220 __mmplayer_audio_stream_probe, player, NULL);
12222 gst_object_unref(pad);
12226 LOGE("There is no audio callback to configure.\n");
12236 __mmplayer_init_factories(mm_player_t* player)
12238 MMPLAYER_RETURN_IF_FAIL(player);
12240 player->factories = gst_registry_feature_filter(gst_registry_get(),
12241 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
12242 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
12246 __mmplayer_release_factories(mm_player_t* player)
12249 MMPLAYER_RETURN_IF_FAIL(player);
12251 if (player->factories) {
12252 gst_plugin_feature_list_free(player->factories);
12253 player->factories = NULL;
12260 __mmplayer_release_misc(mm_player_t* player)
12263 gboolean cur_mode = player->set_mode.rich_audio;
12266 MMPLAYER_RETURN_IF_FAIL(player);
12268 player->video_stream_cb = NULL;
12269 player->video_stream_cb_user_param = NULL;
12270 player->video_stream_prerolled = FALSE;
12272 player->audio_stream_cb = NULL;
12273 player->audio_stream_render_cb_ex = NULL;
12274 player->audio_stream_cb_user_param = NULL;
12275 player->audio_stream_sink_sync = false;
12277 player->video_stream_changed_cb = NULL;
12278 player->video_stream_changed_cb_user_param = NULL;
12280 player->audio_stream_changed_cb = NULL;
12281 player->audio_stream_changed_cb_user_param = NULL;
12283 player->sent_bos = FALSE;
12284 player->playback_rate = DEFAULT_PLAYBACK_RATE;
12286 player->doing_seek = FALSE;
12288 player->updated_bitrate_count = 0;
12289 player->total_bitrate = 0;
12290 player->updated_maximum_bitrate_count = 0;
12291 player->total_maximum_bitrate = 0;
12293 player->not_found_demuxer = 0;
12295 player->last_position = 0;
12296 player->duration = 0;
12297 player->http_content_size = 0;
12298 player->not_supported_codec = MISSING_PLUGIN_NONE;
12299 player->can_support_codec = FOUND_PLUGIN_NONE;
12300 player->pending_seek.is_pending = FALSE;
12301 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12302 player->pending_seek.pos = 0;
12303 player->msg_posted = FALSE;
12304 player->has_many_types = FALSE;
12305 player->max_audio_channels = 0;
12306 player->video_share_api_delta = 0;
12307 player->video_share_clock_delta = 0;
12308 player->sound_focus.keep_last_pos = FALSE;
12309 player->sound_focus.acquired = FALSE;
12310 player->is_subtitle_force_drop = FALSE;
12311 player->play_subtitle = FALSE;
12312 player->adjust_subtitle_pos = 0;
12313 player->last_multiwin_status = FALSE;
12314 player->has_closed_caption = FALSE;
12315 player->set_mode.media_packet_video_stream = FALSE;
12316 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
12317 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12319 player->set_mode.rich_audio = cur_mode;
12321 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
12322 player->bitrate[i] = 0;
12323 player->maximum_bitrate[i] = 0;
12326 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
12328 /* remove media stream cb(appsrc cb) */
12329 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
12330 player->media_stream_buffer_status_cb[i] = NULL;
12331 player->media_stream_seek_data_cb[i] = NULL;
12332 player->buffer_cb_user_param[i] = NULL;
12333 player->seek_cb_user_param[i] = NULL;
12335 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
12337 /* free memory related to audio effect */
12338 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12340 if (player->state_tune_caps) {
12341 gst_caps_unref(player->state_tune_caps);
12342 player->state_tune_caps = NULL;
12345 if (player->adaptive_info.var_list) {
12346 g_list_free_full(player->adaptive_info.var_list, g_free);
12347 player->adaptive_info.var_list = NULL;
12350 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12351 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12352 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12358 __mmplayer_release_misc_post(mm_player_t* player)
12360 char *original_uri = NULL;
12363 /* player->pipeline is already released before. */
12365 MMPLAYER_RETURN_IF_FAIL(player);
12367 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12368 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12370 /* clean found parsers */
12371 if (player->parsers) {
12372 GList *parsers = player->parsers;
12373 for (; parsers; parsers = g_list_next(parsers)) {
12374 gchar *name = parsers->data;
12375 MMPLAYER_FREEIF(name);
12377 g_list_free(player->parsers);
12378 player->parsers = NULL;
12381 /* clean found audio decoders */
12382 if (player->audio_decoders) {
12383 GList *a_dec = player->audio_decoders;
12384 for (; a_dec; a_dec = g_list_next(a_dec)) {
12385 gchar *name = a_dec->data;
12386 MMPLAYER_FREEIF(name);
12388 g_list_free(player->audio_decoders);
12389 player->audio_decoders = NULL;
12392 /* clean the uri list except original uri */
12393 if (player->uri_info.uri_list) {
12394 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12396 if (player->attrs) {
12397 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12398 LOGD("restore original uri = %s\n", original_uri);
12400 if (mmf_attrs_commit(player->attrs))
12401 LOGE("failed to commit the original uri.\n");
12404 GList *uri_list = player->uri_info.uri_list;
12405 for (; uri_list; uri_list = g_list_next(uri_list)) {
12406 gchar *uri = uri_list->data;
12407 MMPLAYER_FREEIF(uri);
12409 g_list_free(player->uri_info.uri_list);
12410 player->uri_info.uri_list = NULL;
12413 /* clear the audio stream buffer list */
12414 __mmplayer_audio_stream_clear_buffer(player, FALSE);
12416 /* clear the video stream bo list */
12417 __mmplayer_video_stream_destroy_bo_list(player);
12418 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
12420 if (player->profile.mem) {
12421 free(player->profile.mem);
12422 player->profile.mem = NULL;
12423 player->mem_buf.buf = NULL;
12425 player->uri_info.uri_idx = 0;
12429 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12431 GstElement *element = NULL;
12434 LOGD("creating %s to plug\n", name);
12436 element = gst_element_factory_make(name, NULL);
12438 LOGE("failed to create queue\n");
12442 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
12443 LOGE("failed to set state READY to %s\n", name);
12444 gst_object_unref(element);
12448 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
12449 LOGE("failed to add %s\n", name);
12450 gst_object_unref(element);
12454 sinkpad = gst_element_get_static_pad(element, "sink");
12456 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
12457 LOGE("failed to link %s\n", name);
12458 gst_object_unref(sinkpad);
12459 gst_object_unref(element);
12463 LOGD("linked %s to pipeline successfully\n", name);
12465 gst_object_unref(sinkpad);
12471 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
12472 const char *padname, const GList *templlist)
12474 GstPad *pad = NULL;
12475 gboolean has_dynamic_pads = FALSE;
12476 gboolean has_many_types = FALSE;
12477 const char *klass = NULL;
12478 GstStaticPadTemplate *padtemplate = NULL;
12479 GstElementFactory *factory = NULL;
12480 GstElement* queue = NULL;
12481 GstElement* parser = NULL;
12482 GstPad *pssrcpad = NULL;
12483 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
12484 MMPlayerGstElement *mainbin = NULL;
12485 GstStructure* str = NULL;
12486 GstCaps* srccaps = NULL;
12487 GstState target_state = GST_STATE_READY;
12488 gboolean isvideo_decoder = FALSE;
12489 guint q_max_size_time = 0;
12493 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12494 player->pipeline &&
12495 player->pipeline->mainbin,
12498 mainbin = player->pipeline->mainbin;
12500 LOGD("plugging pad %s:%s to newly create %s:%s\n",
12501 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)),
12502 GST_PAD_NAME(srcpad),
12503 GST_ELEMENT_NAME(sinkelement),
12506 factory = gst_element_get_factory(sinkelement);
12507 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
12509 /* check if player can do start continually */
12510 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12512 /* need it to warm up omx before linking to pipeline */
12513 if (g_strrstr(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), "demux")) {
12514 LOGD("get demux caps.\n");
12515 if (player->state_tune_caps) {
12516 gst_caps_unref(player->state_tune_caps);
12517 player->state_tune_caps = NULL;
12519 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
12522 /* NOTE : OMX Codec can check if resource is available or not at this state. */
12523 if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx")) {
12524 if (player->state_tune_caps != NULL) {
12525 LOGD("set demux's caps to omx codec if resource is available");
12526 if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps)) {
12527 target_state = GST_STATE_PAUSED;
12528 isvideo_decoder = TRUE;
12529 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
12531 LOGW("failed to set caps for state tuning");
12533 gst_caps_unref(player->state_tune_caps);
12534 player->state_tune_caps = NULL;
12537 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state)) {
12538 LOGE("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME(sinkelement));
12539 if (isvideo_decoder) {
12540 gst_element_set_state(sinkelement, GST_STATE_NULL);
12541 gst_object_unref(G_OBJECT(sinkelement));
12542 player->keep_detecting_vcodec = TRUE;
12547 /* add to pipeline */
12548 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement)) {
12549 LOGE("failed to add %s to mainbin\n", GST_ELEMENT_NAME(sinkelement));
12553 LOGD("element klass : %s\n", klass);
12555 /* added to support multi track files */
12556 /* only decoder case and any of the video/audio still need to link*/
12557 if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, srcpad)) {
12558 gchar *name = g_strdup(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)));
12560 if (g_strrstr(name, "mpegtsdemux") || g_strrstr(name, "mssdemux")) {
12561 gchar *src_demux_caps_str = NULL;
12562 gchar *needed_parser = NULL;
12563 GstCaps *src_demux_caps = NULL;
12564 gboolean smooth_streaming = FALSE;
12566 src_demux_caps = gst_pad_query_caps(srcpad, NULL);
12567 src_demux_caps_str = gst_caps_to_string(src_demux_caps);
12569 gst_caps_unref(src_demux_caps);
12571 if (g_strrstr(src_demux_caps_str, "video/x-h264")) {
12572 if (g_strrstr(name, "mssdemux")) {
12573 needed_parser = g_strdup("legacyh264parse");
12574 smooth_streaming = TRUE;
12576 needed_parser = g_strdup("h264parse");
12577 } else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
12578 needed_parser = g_strdup("mpeg4videoparse");
12580 MMPLAYER_FREEIF(src_demux_caps_str);
12582 if (needed_parser) {
12583 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
12584 MMPLAYER_FREEIF(needed_parser);
12587 LOGE("failed to create parser\n");
12589 if (smooth_streaming)
12590 g_object_set(parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
12592 /* update srcpad if parser is created */
12593 pssrcpad = gst_element_get_static_pad(parser, "src");
12598 MMPLAYER_FREEIF(name);
12600 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
12602 LOGE("failed to create queue\n");
12606 /* update srcpad to link with decoder */
12607 qsrcpad = gst_element_get_static_pad(queue, "src");
12610 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
12612 /* assigning queue handle for futher manipulation purpose */
12613 /* FIXIT : make it some kind of list so that msl can support more then two stream(text, data, etc...) */
12614 if (mainbin[MMPLAYER_M_Q1].gst == NULL) {
12615 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
12616 mainbin[MMPLAYER_M_Q1].gst = queue;
12618 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12619 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
12620 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
12621 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
12623 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12624 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12626 } else if (mainbin[MMPLAYER_M_Q2].gst == NULL) {
12627 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
12628 mainbin[MMPLAYER_M_Q2].gst = queue;
12630 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12631 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
12632 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
12633 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
12635 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12636 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12639 LOGE("Not supporting more then two elementary stream\n");
12643 pad = gst_element_get_static_pad(sinkelement, padname);
12646 LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12647 padname, GST_ELEMENT_NAME(sinkelement));
12649 pad = gst_element_get_static_pad(sinkelement, "sink");
12651 LOGE("failed to get pad(sink) from %s. \n",
12652 GST_ELEMENT_NAME(sinkelement));
12657 /* to check the video/audio type set the proper flag*/
12658 const gchar *mime_type = NULL;
12659 srccaps = gst_pad_query_caps(srcpad, NULL);
12662 str = gst_caps_get_structure(srccaps, 0);
12665 mime_type = gst_structure_get_name(str);
12669 /* link queue and decoder. so, it will be queue - decoder. */
12670 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12671 gst_object_unref(GST_OBJECT(pad));
12672 LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12674 /* reconstitute supportable codec */
12675 if (strstr(mime_type, "video"))
12676 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
12677 else if (strstr(mime_type, "audio"))
12678 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
12682 if (strstr(mime_type, "video")) {
12683 player->videodec_linked = 1;
12684 LOGI("player->videodec_linked set to 1\n");
12686 } else if (strstr(mime_type, "audio")) {
12687 player->audiodec_linked = 1;
12688 LOGI("player->auddiodec_linked set to 1\n");
12691 gst_object_unref(GST_OBJECT(pad));
12692 gst_caps_unref(GST_CAPS(srccaps));
12696 if (!MMPLAYER_IS_HTTP_PD(player)) {
12697 if ((g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser"))) {
12698 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
12699 gint64 dur_bytes = 0L;
12700 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
12702 if (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
12703 LOGD("creating http streaming buffering queue\n");
12705 queue = gst_element_factory_make("queue2", "queue2");
12707 LOGE("failed to create buffering queue element\n");
12711 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
12712 LOGE("failed to set state READY to buffering queue\n");
12716 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
12717 LOGE("failed to add buffering queue\n");
12721 qsinkpad = gst_element_get_static_pad(queue, "sink");
12722 qsrcpad = gst_element_get_static_pad(queue, "src");
12724 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad)) {
12725 LOGE("failed to link buffering queue\n");
12731 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
12732 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
12734 if (!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
12735 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
12736 LOGE("fail to get duration.\n");
12738 if (dur_bytes > 0) {
12739 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
12740 type = MUXED_BUFFER_TYPE_FILE;
12742 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
12743 if (player->streamer)
12744 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
12751 /* NOTE : we cannot get any duration info from ts container in case of streaming */
12752 if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) {
12753 __mm_player_streaming_set_queue2(player->streamer,
12756 player->ini.http_max_size_bytes,
12757 player->ini.http_buffering_time,
12759 player->ini.http_buffering_limit,
12761 player->http_file_buffering_path,
12762 (guint64)dur_bytes);
12768 /* if it is not decoder or */
12769 /* in decoder case any of the video/audio still need to link*/
12770 if (!g_strrstr(klass, "Decoder")) {
12771 pad = gst_element_get_static_pad(sinkelement, padname);
12773 LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12774 padname, GST_ELEMENT_NAME(sinkelement));
12776 pad = gst_element_get_static_pad(sinkelement, "sink");
12779 LOGE("failed to get pad(sink) from %s. \n",
12780 GST_ELEMENT_NAME(sinkelement));
12785 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12786 gst_object_unref(GST_OBJECT(pad));
12787 LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12791 gst_object_unref(GST_OBJECT(pad));
12794 for (; templlist != NULL; templlist = templlist->next) {
12795 padtemplate = templlist->data;
12797 LOGD("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
12799 if (padtemplate->direction != GST_PAD_SRC ||
12800 padtemplate->presence == GST_PAD_REQUEST)
12803 switch (padtemplate->presence) {
12804 case GST_PAD_ALWAYS:
12806 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
12807 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
12809 /* Check whether caps has many types */
12810 if (!gst_caps_is_fixed(caps)) {
12811 LOGD("always pad but, caps has many types");
12812 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12813 has_many_types = TRUE;
12817 if (!__mmplayer_try_to_plug(player, srcpad, caps)) {
12818 gst_object_unref(GST_OBJECT(srcpad));
12819 gst_caps_unref(GST_CAPS(caps));
12821 LOGE("failed to plug something after %s\n", GST_ELEMENT_NAME(sinkelement));
12825 gst_caps_unref(GST_CAPS(caps));
12826 gst_object_unref(GST_OBJECT(srcpad));
12832 case GST_PAD_SOMETIMES:
12833 has_dynamic_pads = TRUE;
12841 /* check if player can do start continually */
12842 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12844 if (has_dynamic_pads) {
12845 player->have_dynamic_pad = TRUE;
12846 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
12847 G_CALLBACK(__mmplayer_add_new_pad), player);
12849 /* for streaming, more then one typefind will used for each elementary stream
12850 * so this doesn't mean the whole pipeline completion
12852 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
12853 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
12854 G_CALLBACK(__mmplayer_pipeline_complete), player);
12858 if (has_many_types) {
12859 GstPad *pad = NULL;
12861 player->has_many_types = has_many_types;
12863 pad = gst_element_get_static_pad(sinkelement, "src");
12864 MMPLAYER_SIGNAL_CONNECT(player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
12865 gst_object_unref(GST_OBJECT(pad));
12869 /* check if player can do start continually */
12870 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12872 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED)) {
12873 LOGE("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME(sinkelement));
12878 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
12879 LOGE("failed to set state PAUSED to queue\n");
12885 gst_object_unref(GST_OBJECT(qsrcpad));
12890 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(parser, GST_STATE_PAUSED)) {
12891 LOGE("failed to set state PAUSED to queue\n");
12897 gst_object_unref(GST_OBJECT(pssrcpad));
12908 gst_object_unref(GST_OBJECT(qsrcpad));
12910 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
12911 * You need to explicitly set elements to the NULL state before
12912 * dropping the final reference, to allow them to clean up.
12914 gst_element_set_state(queue, GST_STATE_NULL);
12915 /* And, it still has a parent "player".
12916 * You need to let the parent manage the object instead of unreffing the object directly.
12919 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
12920 //gst_object_unref(queue);
12924 gst_caps_unref(GST_CAPS(srccaps));
12929 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data)
12931 const gchar *klass;
12933 /* we only care about element factories */
12934 if (!GST_IS_ELEMENT_FACTORY(feature))
12937 /* only parsers, demuxers and decoders */
12938 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS);
12940 if (g_strrstr(klass, "Demux") == NULL &&
12941 g_strrstr(klass, "Codec/Decoder") == NULL &&
12942 g_strrstr(klass, "Depayloader") == NULL &&
12943 g_strrstr(klass, "Parse") == NULL)
12949 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
12951 mm_player_t* player = (mm_player_t*) data;
12952 GstCaps *caps = NULL;
12953 GstStructure *str = NULL;
12958 MMPLAYER_RETURN_IF_FAIL(pad)
12959 MMPLAYER_RETURN_IF_FAIL(unused)
12960 MMPLAYER_RETURN_IF_FAIL(data)
12962 caps = gst_pad_query_caps(pad, NULL);
12966 str = gst_caps_get_structure(caps, 0);
12970 name = gst_structure_get_name(str);
12973 LOGD("name=%s\n", name);
12975 if (!__mmplayer_try_to_plug(player, pad, caps)) {
12976 LOGE("failed to autoplug for type(%s)\n", name);
12977 gst_caps_unref(caps);
12981 gst_caps_unref(caps);
12983 __mmplayer_pipeline_complete(NULL, (gpointer)player);
12990 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
12994 const char *stream_type;
12995 gchar *version_field = NULL;
12999 MMPLAYER_RETURN_IF_FAIL(player);
13000 MMPLAYER_RETURN_IF_FAIL(caps);
13002 str = gst_caps_get_structure(caps, 0);
13006 stream_type = gst_structure_get_name(str);
13011 /* set unlinked mime type for downloadable codec */
13012 if (g_str_has_prefix(stream_type, "video/")) {
13013 if (g_str_has_prefix(stream_type, "video/mpeg")) {
13014 gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
13015 version_field = MM_PLAYER_MPEG_VNAME;
13016 } else if (g_str_has_prefix(stream_type, "video/x-wmv")) {
13017 gst_structure_get_int(str, MM_PLAYER_WMV_VNAME, &version);
13018 version_field = MM_PLAYER_WMV_VNAME;
13020 } else if (g_str_has_prefix(stream_type, "video/x-divx")) {
13021 gst_structure_get_int(str, MM_PLAYER_DIVX_VNAME, &version);
13022 version_field = MM_PLAYER_DIVX_VNAME;
13026 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
13028 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
13029 } else if (g_str_has_prefix(stream_type, "audio/")) {
13030 if (g_str_has_prefix(stream_type, "audio/mpeg")) {
13032 gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
13033 version_field = MM_PLAYER_MPEG_VNAME;
13034 } else if (g_str_has_prefix(stream_type, "audio/x-wma")) {
13035 gst_structure_get_int(str, MM_PLAYER_WMA_VNAME, &version);
13036 version_field = MM_PLAYER_WMA_VNAME;
13040 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
13042 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
13048 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
13050 mm_player_t* player = (mm_player_t*) data;
13051 GstCaps *caps = NULL;
13052 GstStructure *str = NULL;
13056 MMPLAYER_RETURN_IF_FAIL(player);
13057 MMPLAYER_RETURN_IF_FAIL(pad);
13059 GST_OBJECT_LOCK(pad);
13060 if ((caps = gst_pad_get_current_caps(pad)))
13061 gst_caps_ref(caps);
13062 GST_OBJECT_UNLOCK(pad);
13064 if (NULL == caps) {
13065 caps = gst_pad_query_caps(pad, NULL);
13069 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
13071 str = gst_caps_get_structure(caps, 0);
13075 name = gst_structure_get_name(str);
13079 player->num_dynamic_pad++;
13080 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
13082 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
13083 * If want to play it, remove this code.
13085 if (g_strrstr(name, "application")) {
13086 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag")) {
13087 /* If id3/ape tag comes, keep going */
13088 LOGD("application mime exception : id3/ape tag");
13090 /* Otherwise, we assume that this stream is subtile. */
13091 LOGD(" application mime type pad is closed.");
13094 } else if (g_strrstr(name, "audio")) {
13095 gint samplerate = 0, channels = 0;
13097 if (player->audiodec_linked) {
13098 gst_caps_unref(caps);
13099 LOGD("multi tracks. skip to plug");
13103 /* set stream information */
13104 /* if possible, set it here because the caps is not distrubed by resampler. */
13105 gst_structure_get_int(str, "rate", &samplerate);
13106 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
13108 gst_structure_get_int(str, "channels", &channels);
13109 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
13111 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
13112 } else if (g_strrstr(name, "video")) {
13114 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
13116 /* don't make video because of not required */
13117 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
13118 LOGD("no video because it's not required");
13122 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
13125 if (!__mmplayer_try_to_plug(player, pad, caps)) {
13126 LOGE("failed to autoplug for type(%s)", name);
13128 __mmplayer_set_unlinked_mime_type(player, caps);
13131 gst_caps_unref(caps);
13138 __mmplayer_check_subtitle(mm_player_t* player)
13140 MMHandleType attrs = 0;
13141 char *subtitle_uri = NULL;
13145 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13147 /* get subtitle attribute */
13148 attrs = MMPLAYER_GET_ATTRS(player);
13152 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
13153 if (!subtitle_uri || !strlen(subtitle_uri))
13156 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
13157 player->is_external_subtitle_present = TRUE;
13165 __mmplayer_can_extract_pcm(mm_player_t* player)
13167 MMHandleType attrs = 0;
13168 gboolean sound_extraction = FALSE;
13170 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13172 attrs = MMPLAYER_GET_ATTRS(player);
13174 LOGE("fail to get attributes.");
13178 /* get sound_extraction property */
13179 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
13181 if (!sound_extraction) {
13182 LOGD("checking pcm extraction mode : %d ", sound_extraction);
13190 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
13193 MMMessageParamType msg_param;
13194 gchar *msg_src_element = NULL;
13195 GstStructure *s = NULL;
13196 guint error_id = 0;
13197 gchar *error_string = NULL;
13201 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13202 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
13204 s = malloc(sizeof(GstStructure));
13206 LOGE("failed to alloc data.");
13210 memcpy(s, gst_message_get_structure(message), sizeof(GstStructure));
13212 if (!gst_structure_get_uint(s, "error_id", &error_id))
13213 error_id = MMPLAYER_STREAMING_ERROR_NONE;
13215 switch (error_id) {
13216 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
13217 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
13219 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
13220 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
13222 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
13223 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
13225 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
13226 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
13228 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
13229 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
13231 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
13232 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
13234 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
13235 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
13237 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
13238 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
13240 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
13241 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
13243 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
13244 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
13246 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
13247 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
13249 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
13250 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
13252 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
13253 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
13255 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
13256 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
13258 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
13259 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
13261 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
13262 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
13264 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
13265 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
13267 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
13268 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
13270 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
13271 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
13273 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
13274 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
13276 case MMPLAYER_STREAMING_ERROR_GONE:
13277 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
13279 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
13280 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
13282 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
13283 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
13285 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
13286 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
13288 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
13289 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
13291 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
13292 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
13294 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
13295 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
13297 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
13298 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
13300 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
13301 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
13303 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
13304 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
13306 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
13307 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
13309 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
13310 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
13312 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
13313 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
13315 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
13316 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
13318 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
13319 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
13321 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
13322 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
13324 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
13325 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
13327 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
13328 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
13330 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
13331 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
13333 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
13334 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
13336 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
13337 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
13339 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
13340 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
13342 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
13343 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
13345 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
13346 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
13348 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
13349 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
13353 MMPLAYER_FREEIF(s);
13354 return MM_ERROR_PLAYER_STREAMING_FAIL;
13358 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
13360 msg_param.data = (void *) error_string;
13362 if (message->src) {
13363 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
13365 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
13366 msg_src_element, msg_param.code, (char*)msg_param.data);
13369 /* post error to application */
13370 if (!player->msg_posted) {
13371 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13373 /* don't post more if one was sent already */
13374 player->msg_posted = TRUE;
13376 LOGD("skip error post because it's sent already.\n");
13378 MMPLAYER_FREEIF(s);
13380 g_free(error_string);
13387 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
13389 MMPLAYER_RETURN_IF_FAIL(player);
13392 /* post now if delay is zero */
13393 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
13394 LOGD("eos delay is zero. posting EOS now\n");
13395 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13397 if (player->set_mode.pcm_extraction)
13398 __mmplayer_cancel_eos_timer(player);
13403 /* cancel if existing */
13404 __mmplayer_cancel_eos_timer(player);
13406 /* init new timeout */
13407 /* NOTE : consider give high priority to this timer */
13408 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
13410 player->eos_timer = g_timeout_add(delay_in_ms,
13411 __mmplayer_eos_timer_cb, player);
13413 player->context.global_default = g_main_context_default();
13414 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
13416 /* check timer is valid. if not, send EOS now */
13417 if (player->eos_timer == 0) {
13418 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
13419 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13424 __mmplayer_cancel_eos_timer(mm_player_t* player)
13426 MMPLAYER_RETURN_IF_FAIL(player);
13428 if (player->eos_timer) {
13429 LOGD("cancel eos timer");
13430 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
13431 player->eos_timer = 0;
13438 __mmplayer_eos_timer_cb(gpointer u_data)
13440 mm_player_t* player = NULL;
13441 player = (mm_player_t*) u_data;
13443 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13445 if (player->play_count > 1) {
13446 gint ret_value = 0;
13447 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
13448 if (ret_value == MM_ERROR_NONE) {
13449 MMHandleType attrs = 0;
13450 attrs = MMPLAYER_GET_ATTRS(player);
13452 /* we successeded to rewind. update play count and then wait for next EOS */
13453 player->play_count--;
13455 mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
13456 mmf_attrs_commit(attrs);
13458 LOGE("seeking to 0 failed in repeat play");
13462 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13465 /* we are returning FALSE as we need only one posting */
13470 __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad)
13472 const gchar* name = NULL;
13473 GstStructure* str = NULL;
13474 GstCaps* srccaps = NULL;
13478 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13479 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13481 /* to check any of the decoder(video/audio) need to be linked to parser*/
13482 srccaps = gst_pad_query_caps(srcpad, NULL);
13486 str = gst_caps_get_structure(srccaps, 0);
13490 name = gst_structure_get_name(str);
13494 if (strstr(name, "video")) {
13495 if (player->videodec_linked) {
13496 LOGI("Video decoder already linked\n");
13500 if (strstr(name, "audio")) {
13501 if (player->audiodec_linked) {
13502 LOGI("Audio decoder already linked\n");
13507 gst_caps_unref(srccaps);
13515 gst_caps_unref(srccaps);
13521 __mmplayer_link_sink(mm_player_t* player , GstPad *srcpad)
13523 const gchar* name = NULL;
13524 GstStructure* str = NULL;
13525 GstCaps* srccaps = NULL;
13529 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13530 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13532 /* to check any of the decoder(video/audio) need to be linked to parser*/
13533 srccaps = gst_pad_query_caps(srcpad, NULL);
13537 str = gst_caps_get_structure(srccaps, 0);
13541 name = gst_structure_get_name(str);
13545 if (strstr(name, "video")) {
13546 if (player->videosink_linked) {
13547 LOGI("Video Sink already linked\n");
13551 if (strstr(name, "audio")) {
13552 if (player->audiosink_linked) {
13553 LOGI("Audio Sink already linked\n");
13557 if (strstr(name, "text")) {
13558 if (player->textsink_linked) {
13559 LOGI("Text Sink already linked\n");
13564 gst_caps_unref(srccaps);
13568 //return (!player->videosink_linked || !player->audiosink_linked);
13573 gst_caps_unref(srccaps);
13579 /* sending event to one of sinkelements */
13581 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
13583 GstEvent * event2 = NULL;
13584 GList *sinks = NULL;
13585 gboolean res = FALSE;
13588 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13589 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
13591 /* While adding subtitles in live feeds seek is getting called.
13592 Adding defensive check in framework layer.*/
13593 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13594 if (MMPLAYER_IS_LIVE_STREAMING (player)) {
13595 LOGE ("Should not send seek event during live playback");
13600 if (player->play_subtitle)
13601 event2 = gst_event_copy((const GstEvent *)event);
13603 sinks = player->sink_elements;
13605 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
13607 if (GST_IS_ELEMENT(sink)) {
13608 /* keep ref to the event */
13609 gst_event_ref(event);
13611 if ((res = gst_element_send_event(sink, event))) {
13612 LOGD("sending event[%s] to sink element [%s] success!\n",
13613 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13615 /* rtsp case, asyn_done is not called after seek during pause state */
13616 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
13617 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13618 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
13619 LOGD("RTSP seek completed, after pause state..\n");
13620 player->doing_seek = FALSE;
13621 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
13627 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
13628 sinks = g_list_next(sinks);
13635 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
13636 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13639 sinks = g_list_next(sinks);
13644 request pad name = sink0;
13646 request pad name = sink1; // external
13649 /* Note : Textbin is not linked to the video or audio bin.
13650 * It needs to send the event to the text sink seperatelly.
13652 if (player->play_subtitle) {
13653 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
13655 if (GST_IS_ELEMENT(text_sink)) {
13656 /* keep ref to the event */
13657 gst_event_ref(event2);
13659 if ((res = gst_element_send_event(text_sink, event2)))
13660 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
13661 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13663 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
13664 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13666 gst_event_unref(event2);
13670 gst_event_unref(event);
13678 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
13682 MMPLAYER_RETURN_IF_FAIL(player);
13683 MMPLAYER_RETURN_IF_FAIL(sink);
13685 player->sink_elements =
13686 g_list_append(player->sink_elements, sink);
13692 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
13696 MMPLAYER_RETURN_IF_FAIL(player);
13697 MMPLAYER_RETURN_IF_FAIL(sink);
13699 player->sink_elements =
13700 g_list_remove(player->sink_elements, sink);
13706 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
13707 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
13708 gint64 cur, GstSeekType stop_type, gint64 stop)
13710 GstEvent* event = NULL;
13711 gboolean result = FALSE;
13715 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13717 if (player->pipeline && player->pipeline->textbin)
13718 __mmplayer_drop_subtitle(player, FALSE);
13720 event = gst_event_new_seek(rate, format, flags, cur_type,
13721 cur, stop_type, stop);
13723 result = __gst_send_event_to_sink(player, event);
13730 /* NOTE : be careful with calling this api. please refer to below glib comment
13731 * glib comment : Note that there is a bug in GObject that makes this function much
13732 * less useful than it might seem otherwise. Once gobject is disposed, the callback
13733 * will no longer be called, but, the signal handler is not currently disconnected.
13734 * If the instance is itself being freed at the same time than this doesn't matter,
13735 * since the signal will automatically be removed, but if instance persists,
13736 * then the signal handler will leak. You should not remove the signal yourself
13737 * because in a future versions of GObject, the handler will automatically be
13740 * It's possible to work around this problem in a way that will continue to work
13741 * with future versions of GObject by checking that the signal handler is still
13742 * connected before disconnected it:
13744 * if (g_signal_handler_is_connected(instance, id))
13745 * g_signal_handler_disconnect(instance, id);
13748 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
13750 GList* sig_list = NULL;
13751 MMPlayerSignalItem* item = NULL;
13755 MMPLAYER_RETURN_IF_FAIL(player);
13757 LOGD("release signals type : %d", type);
13759 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
13760 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
13761 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
13762 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
13763 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
13764 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
13768 sig_list = player->signals[type];
13770 for (; sig_list; sig_list = sig_list->next) {
13771 item = sig_list->data;
13773 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
13774 if (g_signal_handler_is_connected(item->obj, item->sig))
13775 g_signal_handler_disconnect(item->obj, item->sig);
13778 MMPLAYER_FREEIF(item);
13781 g_list_free(player->signals[type]);
13782 player->signals[type] = NULL;
13789 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
13791 mm_player_t* player = 0;
13792 int prev_display_surface_type = 0;
13793 void *prev_display_overlay = NULL;
13794 const gchar *klass = NULL;
13795 gchar *cur_videosink_name = NULL;
13798 int num_of_dec = 2; /* DEC1, DEC2 */
13802 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
13803 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13805 player = MM_PLAYER_CAST(handle);
13807 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
13808 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
13810 return MM_ERROR_INVALID_ARGUMENT;
13813 /* load previous attributes */
13814 if (player->attrs) {
13815 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
13816 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
13817 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
13818 if (prev_display_surface_type == surface_type) {
13819 LOGD("incoming display surface type is same as previous one, do nothing..");
13821 return MM_ERROR_NONE;
13824 LOGE("failed to load attributes");
13826 return MM_ERROR_PLAYER_INTERNAL;
13829 /* check videosink element is created */
13830 if (!player->pipeline || !player->pipeline->videobin ||
13831 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13832 LOGD("videosink element is not yet ready");
13834 /* videobin is not created yet, so we just set attributes related to display surface */
13835 LOGD("store display attribute for given surface type(%d)", surface_type);
13836 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13837 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13838 if (mmf_attrs_commit(player->attrs)) {
13839 LOGE("failed to commit attribute");
13841 return MM_ERROR_PLAYER_INTERNAL;
13844 return MM_ERROR_NONE;
13846 /* get player command status */
13847 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
13848 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
13850 return MM_ERROR_PLAYER_INVALID_STATE;
13853 /* surface change */
13854 for (i = 0 ; i < num_of_dec ; i++) {
13855 if (player->pipeline->mainbin &&
13856 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
13857 GstElementFactory *decfactory;
13858 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
13860 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
13861 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
13862 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
13863 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
13867 LOGW("success to changing display surface(%d)", surface_type);
13869 return MM_ERROR_NONE;
13871 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
13872 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
13876 LOGW("success to changing display surface(%d)", surface_type);
13878 return MM_ERROR_NONE;
13881 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
13882 ret = MM_ERROR_PLAYER_INTERNAL;
13891 /* rollback to previous attributes */
13892 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
13893 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
13894 if (mmf_attrs_commit(player->attrs)) {
13895 LOGE("failed to commit attributes to rollback");
13897 return MM_ERROR_PLAYER_INTERNAL;
13903 /* NOTE : It does not support some use cases, eg using colorspace converter */
13905 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
13907 GstPad *src_pad_dec = NULL;
13908 GstPad *sink_pad_videosink = NULL;
13909 GstPad *sink_pad_videobin = NULL;
13910 GstClock *clock = NULL;
13911 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
13912 int ret = MM_ERROR_NONE;
13913 gboolean is_audiobin_created = TRUE;
13917 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
13918 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
13919 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13921 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
13922 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
13924 /* get information whether if audiobin is created */
13925 if (!player->pipeline->audiobin ||
13926 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
13927 LOGW("audiobin is null, this video content may not have audio data");
13928 is_audiobin_created = FALSE;
13931 /* get current state of player */
13932 previous_state = MMPLAYER_CURRENT_STATE(player);
13933 LOGD("previous state(%d)", previous_state);
13936 /* get src pad of decoder and block it */
13937 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
13938 if (!src_pad_dec) {
13939 LOGE("failed to get src pad from decode in mainbin");
13940 return MM_ERROR_PLAYER_INTERNAL;
13943 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13944 LOGW("trying to block pad(video)");
13945 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
13946 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
13949 LOGE("failed to set block pad(video)");
13950 return MM_ERROR_PLAYER_INTERNAL;
13952 LOGW("pad is blocked(video)");
13954 /* no data flows, so no need to do pad_block */
13955 if (player->doing_seek)
13956 LOGW("not completed seek(%d), do nothing", player->doing_seek);
13958 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
13962 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
13963 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
13964 LOGE("failed to remove previous ghost_pad for videobin");
13965 return MM_ERROR_PLAYER_INTERNAL;
13968 /* change state of videobin to NULL */
13969 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
13970 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
13971 if (ret != GST_STATE_CHANGE_SUCCESS) {
13972 LOGE("failed to change state of videobin to NULL");
13973 return MM_ERROR_PLAYER_INTERNAL;
13976 /* unlink between decoder and videobin and remove previous videosink from videobin */
13977 GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
13978 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
13979 LOGE("failed to remove former videosink from videobin");
13980 return MM_ERROR_PLAYER_INTERNAL;
13983 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13985 /* create a new videosink and add it to videobin */
13986 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
13987 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13988 LOGE("failed to create videosink element\n");
13990 return MM_ERROR_PLAYER_INTERNAL;
13992 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
13993 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13994 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
13996 /* save attributes */
13997 if (player->attrs) {
13998 /* set a new display surface type */
13999 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
14000 /* set a new diplay overlay */
14001 switch (surface_type) {
14002 case MM_DISPLAY_SURFACE_OVERLAY:
14003 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
14004 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
14007 LOGE("invalid type(%d) for changing display surface", surface_type);
14009 return MM_ERROR_INVALID_ARGUMENT;
14011 if (mmf_attrs_commit(player->attrs)) {
14012 LOGE("failed to commit");
14014 return MM_ERROR_PLAYER_INTERNAL;
14017 LOGE("player->attrs is null, failed to save attributes");
14019 return MM_ERROR_PLAYER_INTERNAL;
14022 /* update video param */
14023 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
14024 LOGE("failed to update video param");
14025 return MM_ERROR_PLAYER_INTERNAL;
14028 /* change state of videobin to READY */
14029 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
14030 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
14031 if (ret != GST_STATE_CHANGE_SUCCESS) {
14032 LOGE("failed to change state of videobin to READY");
14033 return MM_ERROR_PLAYER_INTERNAL;
14036 /* change ghostpad */
14037 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
14038 if (!sink_pad_videosink) {
14039 LOGE("failed to get sink pad from videosink element");
14040 return MM_ERROR_PLAYER_INTERNAL;
14042 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
14043 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
14044 LOGE("failed to set active to ghost_pad");
14045 return MM_ERROR_PLAYER_INTERNAL;
14047 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
14048 LOGE("failed to change ghostpad for videobin");
14049 return MM_ERROR_PLAYER_INTERNAL;
14051 gst_object_unref(sink_pad_videosink);
14053 /* link decoder with videobin */
14054 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
14055 if (!sink_pad_videobin) {
14056 LOGE("failed to get sink pad from videobin");
14057 return MM_ERROR_PLAYER_INTERNAL;
14059 if (GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin)) {
14060 LOGE("failed to link");
14061 return MM_ERROR_PLAYER_INTERNAL;
14063 gst_object_unref(sink_pad_videobin);
14065 /* clock setting for a new videosink plugin */
14066 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
14067 so we set it from audiosink plugin or pipeline(system clock) */
14068 if (!is_audiobin_created) {
14069 LOGW("audiobin is not created, get clock from pipeline..");
14070 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14072 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14076 GstClockTime base_time;
14077 LOGD("set the clock to videosink");
14078 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
14079 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14081 LOGD("got clock of videosink");
14082 now = gst_clock_get_time(clock);
14083 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
14084 LOGD("at time %" GST_TIME_FORMAT ", base %"
14085 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
14087 LOGE("failed to get clock of videosink after setting clock");
14088 return MM_ERROR_PLAYER_INTERNAL;
14091 LOGW("failed to get clock, maybe it is the time before first playing");
14093 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
14094 /* change state of videobin to PAUSED */
14095 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
14096 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
14097 if (ret != GST_STATE_CHANGE_FAILURE) {
14098 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
14100 LOGE("failed to change state of videobin to PLAYING");
14101 return MM_ERROR_PLAYER_INTERNAL;
14104 /* release blocked and unref src pad of video decoder */
14106 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
14107 LOGE("failed to set pad blocked FALSE(video)");
14108 return MM_ERROR_PLAYER_INTERNAL;
14111 LOGW("pad is unblocked(video)");
14113 if (player->doing_seek)
14114 LOGW("not completed seek(%d)", player->doing_seek);
14115 /* change state of videobin to PAUSED */
14116 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
14117 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
14118 if (ret != GST_STATE_CHANGE_FAILURE) {
14119 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
14121 LOGE("failed to change state of videobin to PLAYING");
14122 return MM_ERROR_PLAYER_INTERNAL;
14125 /* already skipped pad block */
14126 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
14129 /* do get/set position for new videosink plugin */
14131 unsigned long position = 0;
14132 gint64 pos_msec = 0;
14134 LOGD("do get/set position for new videosink plugin");
14135 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
14136 LOGE("failed to get position");
14137 return MM_ERROR_PLAYER_INTERNAL;
14139 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
14140 /* accurate seek */
14141 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
14142 LOGE("failed to set position");
14143 return MM_ERROR_PLAYER_INTERNAL;
14146 /* key unit seek */
14147 pos_msec = position * G_GINT64_CONSTANT(1000000);
14148 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
14149 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
14150 GST_SEEK_TYPE_SET, pos_msec,
14151 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
14153 LOGE("failed to set position");
14154 return MM_ERROR_PLAYER_INTERNAL;
14160 gst_object_unref(src_pad_dec);
14161 LOGD("success to change sink");
14165 return MM_ERROR_NONE;
14169 /* Note : if silent is true, then subtitle would not be displayed. :*/
14170 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
14172 mm_player_t* player = (mm_player_t*) hplayer;
14176 /* check player handle */
14177 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14179 player->set_mode.subtitle_off = silent;
14181 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
14185 return MM_ERROR_NONE;
14188 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
14190 MMPlayerGstElement* mainbin = NULL;
14191 MMPlayerGstElement* textbin = NULL;
14192 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14193 GstState current_state = GST_STATE_VOID_PENDING;
14194 GstState element_state = GST_STATE_VOID_PENDING;
14195 GstState element_pending_state = GST_STATE_VOID_PENDING;
14197 GstEvent *event = NULL;
14198 int result = MM_ERROR_NONE;
14200 GstClock *curr_clock = NULL;
14201 GstClockTime base_time, start_time, curr_time;
14206 /* check player handle */
14207 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
14208 player->pipeline &&
14209 player->pipeline->mainbin &&
14210 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14212 mainbin = player->pipeline->mainbin;
14213 textbin = player->pipeline->textbin;
14215 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14217 // sync clock with current pipeline
14218 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14219 curr_time = gst_clock_get_time(curr_clock);
14221 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14222 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14224 LOGD("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
14225 GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
14227 if (current_state > GST_STATE_READY) {
14228 // sync state with current pipeline
14229 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
14230 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
14231 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
14233 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
14234 if (GST_STATE_CHANGE_FAILURE == ret) {
14235 LOGE("fail to state change.\n");
14236 result = MM_ERROR_PLAYER_INTERNAL;
14241 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
14242 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
14245 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
14246 gst_object_unref(curr_clock);
14249 // seek to current position
14250 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14251 result = MM_ERROR_PLAYER_INVALID_STATE;
14252 LOGE("gst_element_query_position failed, invalid state\n");
14256 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
14257 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);
14259 __gst_send_event_to_sink(player, event);
14261 result = MM_ERROR_PLAYER_INTERNAL;
14262 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
14266 /* sync state with current pipeline */
14267 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
14268 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
14269 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
14271 return MM_ERROR_NONE;
14274 /* release text pipeline resource */
14275 player->textsink_linked = 0;
14277 /* release signal */
14278 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
14280 /* release textbin with it's childs */
14281 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
14282 MMPLAYER_FREEIF(player->pipeline->textbin);
14283 player->pipeline->textbin = NULL;
14285 /* release subtitle elem */
14286 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
14287 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
14293 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
14295 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14296 GstState current_state = GST_STATE_VOID_PENDING;
14298 MMHandleType attrs = 0;
14299 MMPlayerGstElement* mainbin = NULL;
14300 MMPlayerGstElement* textbin = NULL;
14302 gchar* subtitle_uri = NULL;
14303 int result = MM_ERROR_NONE;
14304 const gchar *charset = NULL;
14308 /* check player handle */
14309 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
14310 player->pipeline &&
14311 player->pipeline->mainbin &&
14312 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14313 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
14315 mainbin = player->pipeline->mainbin;
14316 textbin = player->pipeline->textbin;
14318 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14319 if (current_state < GST_STATE_READY) {
14320 result = MM_ERROR_PLAYER_INVALID_STATE;
14321 LOGE("Pipeline is not in proper state\n");
14325 attrs = MMPLAYER_GET_ATTRS(player);
14327 LOGE("cannot get content attribute\n");
14328 result = MM_ERROR_PLAYER_INTERNAL;
14332 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
14333 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
14334 LOGE("subtitle uri is not proper filepath\n");
14335 result = MM_ERROR_PLAYER_INVALID_URI;
14339 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
14340 LOGE("failed to get storage info of subtitle path");
14341 result = MM_ERROR_PLAYER_INVALID_URI;
14345 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
14346 LOGD("new subtitle file path is [%s]\n", filepath);
14348 if (!strcmp(filepath, subtitle_uri)) {
14349 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
14352 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14353 if (mmf_attrs_commit(player->attrs)) {
14354 LOGE("failed to commit.\n");
14359 //gst_pad_set_blocked_async(src-srcpad, TRUE)
14361 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
14362 if (ret != GST_STATE_CHANGE_SUCCESS) {
14363 LOGE("failed to change state of textbin to READY");
14364 result = MM_ERROR_PLAYER_INTERNAL;
14368 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
14369 if (ret != GST_STATE_CHANGE_SUCCESS) {
14370 LOGE("failed to change state of subparse to READY");
14371 result = MM_ERROR_PLAYER_INTERNAL;
14375 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
14376 if (ret != GST_STATE_CHANGE_SUCCESS) {
14377 LOGE("failed to change state of filesrc to READY");
14378 result = MM_ERROR_PLAYER_INTERNAL;
14382 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
14384 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
14386 charset = util_get_charset(filepath);
14388 LOGD("detected charset is %s\n", charset);
14389 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
14392 result = _mmplayer_sync_subtitle_pipeline(player);
14399 /* API to switch between external subtitles */
14400 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
14402 int result = MM_ERROR_NONE;
14403 mm_player_t* player = (mm_player_t*)hplayer;
14408 /* check player handle */
14409 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14411 /* filepath can be null in idle state */
14413 /* check file path */
14414 if ((path = strstr(filepath, "file://"))) {
14415 result = util_exist_file_path(path + 7);
14417 result = util_exist_file_path(filepath);
14420 if (result != MM_ERROR_NONE) {
14421 LOGE("invalid subtitle path 0x%X", result);
14422 return result; /* file not found or permission denied */
14426 if (!player->pipeline) {
14428 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14429 if (mmf_attrs_commit(player->attrs)) {
14430 LOGE("failed to commit"); /* subtitle path will not be created */
14431 return MM_ERROR_PLAYER_INTERNAL;
14434 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
14435 /* check filepath */
14436 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
14438 if (!__mmplayer_check_subtitle(player)) {
14439 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14440 if (mmf_attrs_commit(player->attrs)) {
14441 LOGE("failed to commit");
14442 return MM_ERROR_PLAYER_INTERNAL;
14445 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
14446 LOGE("fail to create text pipeline");
14447 return MM_ERROR_PLAYER_INTERNAL;
14450 result = _mmplayer_sync_subtitle_pipeline(player);
14452 result = __mmplayer_change_external_subtitle_language(player, filepath);
14455 player->is_external_subtitle_added_now = TRUE;
14463 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
14465 int result = MM_ERROR_NONE;
14466 gchar* change_pad_name = NULL;
14467 GstPad* sinkpad = NULL;
14468 MMPlayerGstElement* mainbin = NULL;
14469 enum MainElementID elemId = MMPLAYER_M_NUM;
14470 GstCaps* caps = NULL;
14471 gint total_track_num = 0;
14475 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
14476 MM_ERROR_PLAYER_NOT_INITIALIZED);
14478 LOGD("Change Track(%d) to %d\n", type, index);
14480 mainbin = player->pipeline->mainbin;
14482 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
14483 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
14484 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
14485 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
14487 /* Changing Video Track is not supported. */
14488 LOGE("Track Type Error\n");
14492 if (mainbin[elemId].gst == NULL) {
14493 result = MM_ERROR_PLAYER_NO_OP;
14494 LOGD("Req track doesn't exist\n");
14498 total_track_num = player->selector[type].total_track_num;
14499 if (total_track_num <= 0) {
14500 result = MM_ERROR_PLAYER_NO_OP;
14501 LOGD("Language list is not available \n");
14505 if ((index < 0) || (index >= total_track_num)) {
14506 result = MM_ERROR_INVALID_ARGUMENT;
14507 LOGD("Not a proper index : %d \n", index);
14511 /*To get the new pad from the selector*/
14512 change_pad_name = g_strdup_printf("sink_%u", index);
14513 if (change_pad_name == NULL) {
14514 result = MM_ERROR_PLAYER_INTERNAL;
14515 LOGD("Pad does not exists\n");
14519 LOGD("new active pad name: %s\n", change_pad_name);
14521 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
14522 if (sinkpad == NULL) {
14523 LOGD("sinkpad is NULL");
14524 result = MM_ERROR_PLAYER_INTERNAL;
14528 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
14529 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
14531 caps = gst_pad_get_current_caps(sinkpad);
14532 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
14535 gst_object_unref(sinkpad);
14537 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
14538 __mmplayer_set_audio_attrs(player, caps);
14542 MMPLAYER_FREEIF(change_pad_name);
14546 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
14548 int result = MM_ERROR_NONE;
14549 mm_player_t* player = NULL;
14550 MMPlayerGstElement* mainbin = NULL;
14552 gint current_active_index = 0;
14554 GstState current_state = GST_STATE_VOID_PENDING;
14555 GstEvent* event = NULL;
14560 player = (mm_player_t*)hplayer;
14561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14563 if (!player->pipeline) {
14564 LOGE("Track %d pre setting -> %d\n", type, index);
14566 player->selector[type].active_pad_index = index;
14570 mainbin = player->pipeline->mainbin;
14572 current_active_index = player->selector[type].active_pad_index;
14574 /*If index is same as running index no need to change the pad*/
14575 if (current_active_index == index)
14578 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14579 result = MM_ERROR_PLAYER_INVALID_STATE;
14583 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14584 if (current_state < GST_STATE_PAUSED) {
14585 result = MM_ERROR_PLAYER_INVALID_STATE;
14586 LOGW("Pipeline not in porper state\n");
14590 result = __mmplayer_change_selector_pad(player, type, index);
14591 if (result != MM_ERROR_NONE) {
14592 LOGE("change selector pad error\n");
14596 player->selector[type].active_pad_index = index;
14598 if (current_state == GST_STATE_PLAYING) {
14599 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);
14601 __gst_send_event_to_sink(player, event);
14603 result = MM_ERROR_PLAYER_INTERNAL;
14612 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
14614 mm_player_t* player = (mm_player_t*) hplayer;
14618 /* check player handle */
14619 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14621 *silent = player->set_mode.subtitle_off;
14623 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
14627 return MM_ERROR_NONE;
14631 __is_ms_buff_src(mm_player_t* player)
14633 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14635 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
14639 __has_suffix(mm_player_t* player, const gchar* suffix)
14641 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14642 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
14644 gboolean ret = FALSE;
14645 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
14646 gchar* t_suffix = g_ascii_strdown(suffix, -1);
14648 if (g_str_has_suffix(player->profile.uri, suffix))
14651 MMPLAYER_FREEIF(t_url);
14652 MMPLAYER_FREEIF(t_suffix);
14658 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
14660 mm_player_t* player = (mm_player_t*) hplayer;
14662 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14664 MMPLAYER_VIDEO_SINK_CHECK(player);
14666 LOGD("setting display zoom level = %f, offset = %d, %d", level, x, y);
14668 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
14670 return MM_ERROR_NONE;
14673 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
14676 mm_player_t* player = (mm_player_t*) hplayer;
14677 float _level = 0.0;
14681 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14683 MMPLAYER_VIDEO_SINK_CHECK(player);
14685 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
14687 LOGD("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
14693 return MM_ERROR_NONE;
14697 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
14699 mm_player_t* player = (mm_player_t*) hplayer;
14701 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14703 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
14704 MMPLAYER_PRINT_STATE(player);
14705 LOGE("wrong-state : can't set the download mode to parse");
14706 return MM_ERROR_PLAYER_INVALID_STATE;
14709 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
14710 player->video_hub_download_mode = mode;
14712 return MM_ERROR_NONE;
14716 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
14718 mm_player_t* player = (mm_player_t*) hplayer;
14720 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14722 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
14723 player->sync_handler = enable;
14725 return MM_ERROR_NONE;
14729 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
14731 long long clock_delta,
14732 long long video_time,
14733 long long media_clock,
14734 long long audio_time)
14736 mm_player_t* player = (mm_player_t*) hplayer;
14737 MMPlayerGstElement* mainbin = NULL;
14738 GstClockTime start_time_audio = 0, start_time_video = 0;
14739 GstClockTimeDiff base_time = 0, new_base_time = 0;
14740 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14741 gint64 api_delta = 0;
14742 gint64 position = 0, position_delta = 0;
14743 gint64 adj_base_time = 0;
14744 GstClock *curr_clock = NULL;
14745 GstClockTime curr_time = 0;
14746 gboolean query_ret = TRUE;
14747 int result = MM_ERROR_NONE;
14751 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14752 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14753 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14755 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
14757 if ((video_time < 0) || (player->doing_seek)) {
14758 LOGD("skip setting master clock. %lld", video_time);
14762 mainbin = player->pipeline->mainbin;
14764 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14765 curr_time = gst_clock_get_time(curr_clock);
14767 current_state = MMPLAYER_CURRENT_STATE(player);
14769 if (current_state == MM_PLAYER_STATE_PLAYING)
14770 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14772 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
14774 position = player->last_position;
14775 LOGD("query fail. %lld", position);
14778 clock *= GST_USECOND;
14779 clock_delta *= GST_USECOND;
14781 api_delta = clock - curr_time;
14782 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
14783 player->video_share_api_delta = api_delta;
14785 clock_delta += (api_delta - player->video_share_api_delta);
14787 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
14788 player->video_share_clock_delta = (gint64)clock_delta;
14790 position_delta = (position/GST_USECOND) - video_time;
14791 position_delta *= GST_USECOND;
14793 adj_base_time = position_delta;
14794 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
14797 gint64 new_play_time = 0;
14798 gint64 network_delay = 0;
14800 video_time *= GST_USECOND;
14802 network_delay = clock_delta - player->video_share_clock_delta;
14803 new_play_time = video_time + network_delay;
14805 adj_base_time = position - new_play_time;
14807 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
14808 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
14811 /* Adjust Current Stream Time with base_time of sink
14812 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
14813 * 2. Set new base time
14814 * if adj_base_time is positive value, the stream time will be decreased.
14815 * 3. If seek event is occurred, the start time will be reset. */
14816 if ((player->pipeline->audiobin) &&
14817 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
14818 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14820 if (start_time_audio != GST_CLOCK_TIME_NONE) {
14821 LOGD("audio sink : gst_element_set_start_time -> NONE");
14822 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
14825 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14828 if ((player->pipeline->videobin) &&
14829 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
14830 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14832 if (start_time_video != GST_CLOCK_TIME_NONE) {
14833 LOGD("video sink : gst_element_set_start_time -> NONE");
14834 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
14837 // if videobin exist, get base_time from videobin.
14838 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14841 new_base_time = base_time + adj_base_time;
14843 if ((player->pipeline->audiobin) &&
14844 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
14845 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
14847 if ((player->pipeline->videobin) &&
14848 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
14849 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
14858 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
14859 long long *video_time,
14860 long long *media_clock,
14861 long long *audio_time)
14863 mm_player_t* player = (mm_player_t*) hplayer;
14864 MMPlayerGstElement* mainbin = NULL;
14865 GstClock *curr_clock = NULL;
14866 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14867 gint64 position = 0;
14868 gboolean query_ret = TRUE;
14872 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14873 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14874 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14876 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14877 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
14878 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14880 mainbin = player->pipeline->mainbin;
14882 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14884 current_state = MMPLAYER_CURRENT_STATE(player);
14886 if (current_state != MM_PLAYER_STATE_PAUSED)
14887 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14889 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
14891 position = player->last_position;
14893 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
14895 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
14898 gst_object_unref(curr_clock);
14902 return MM_ERROR_NONE;
14906 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
14908 mm_player_t* player = (mm_player_t*) hplayer;
14913 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14914 MMPLAYER_RETURN_VAL_IF_FAIL(angle, MM_ERROR_COMMON_INVALID_ARGUMENT);
14916 if (player->v_stream_caps) {
14917 GstStructure *str = NULL;
14919 str = gst_caps_get_structure(player->v_stream_caps, 0);
14920 if (!gst_structure_get_int(str, "orientation", &org_angle))
14921 LOGD("missing 'orientation' field in video caps");
14924 LOGD("orientation: %d", org_angle);
14925 *angle = org_angle;
14928 return MM_ERROR_NONE;
14932 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
14934 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14935 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
14937 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
14938 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
14942 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
14943 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
14944 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
14945 mm_player_dump_t *dump_s;
14946 dump_s = g_malloc(sizeof(mm_player_dump_t));
14948 if (dump_s == NULL) {
14949 LOGE("malloc fail");
14953 dump_s->dump_element_file = NULL;
14954 dump_s->dump_pad = NULL;
14955 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
14957 if (dump_s->dump_pad) {
14958 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
14959 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]);
14960 dump_s->dump_element_file = fopen(dump_file_name, "w+");
14961 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);
14962 /* add list for removed buffer probe and close FILE */
14963 player->dump_list = g_list_append(player->dump_list, dump_s);
14964 LOGD("%s sink pad added buffer probe for dump", factory_name);
14969 LOGE("failed to get %s sink pad added", factory_name);
14978 static GstPadProbeReturn
14979 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
14981 FILE *dump_data = (FILE *) u_data;
14982 // int written = 0;
14983 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
14984 GstMapInfo probe_info = GST_MAP_INFO_INIT;
14986 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
14988 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
14990 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
14992 fwrite(probe_info.data, 1, probe_info.size , dump_data);
14994 return GST_PAD_PROBE_OK;
14998 __mmplayer_release_dump_list(GList *dump_list)
15001 GList *d_list = dump_list;
15002 for (; d_list; d_list = g_list_next(d_list)) {
15003 mm_player_dump_t *dump_s = d_list->data;
15004 if (dump_s->dump_pad) {
15005 if (dump_s->probe_handle_id)
15006 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
15008 if (dump_s->dump_element_file) {
15009 fclose(dump_s->dump_element_file);
15010 dump_s->dump_element_file = NULL;
15012 MMPLAYER_FREEIF(dump_s);
15014 g_list_free(dump_list);
15020 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
15022 mm_player_t* player = (mm_player_t*) hplayer;
15026 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15027 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
15029 *exist = player->has_closed_caption;
15033 return MM_ERROR_NONE;
15036 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
15040 /* increase ref count of gst buffer */
15042 ret = gst_buffer_ref((GstBuffer *)buffer);
15048 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
15052 gst_buffer_unref((GstBuffer *)buffer);
15059 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
15061 mm_player_t *player = (mm_player_t*)user_data;
15062 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15063 guint64 current_level_bytes = 0;
15065 MMPLAYER_RETURN_IF_FAIL(player);
15067 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15069 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
15070 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15072 if (player->media_stream_buffer_status_cb[type])
15073 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
15074 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15079 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
15081 mm_player_t *player = (mm_player_t*)user_data;
15082 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15083 guint64 current_level_bytes = 0;
15085 MMPLAYER_RETURN_IF_FAIL(player);
15087 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15089 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
15091 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15092 if (player->media_stream_buffer_status_cb[type])
15093 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
15094 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15098 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
15100 mm_player_t *player = (mm_player_t*)user_data;
15101 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15102 guint64 current_level_bytes = 0;
15104 MMPLAYER_RETURN_IF_FAIL(player);
15106 LOGI("app-src: feed subtitle\n");
15108 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15110 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15111 if (player->media_stream_buffer_status_cb[type])
15112 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
15114 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15118 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
15120 mm_player_t *player = (mm_player_t*)user_data;
15121 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15122 guint64 current_level_bytes = 0;
15124 MMPLAYER_RETURN_IF_FAIL(player);
15126 LOGI("app-src: audio buffer is full.\n");
15128 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15130 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15132 if (player->media_stream_buffer_status_cb[type])
15133 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
15135 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15139 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
15141 mm_player_t *player = (mm_player_t*)user_data;
15142 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15143 guint64 current_level_bytes = 0;
15145 MMPLAYER_RETURN_IF_FAIL(player);
15147 LOGI("app-src: video buffer is full.\n");
15149 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15151 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15152 if (player->media_stream_buffer_status_cb[type])
15153 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
15155 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15159 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
15161 mm_player_t *player = (mm_player_t*)user_data;
15162 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15164 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15166 LOGD("app-src: seek audio data %llu\n", position);
15167 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15169 if (player->media_stream_seek_data_cb[type])
15170 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
15171 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15177 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
15179 mm_player_t *player = (mm_player_t*)user_data;
15180 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15182 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15184 LOGD("app-src: seek video data %llu\n", position);
15185 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15186 if (player->media_stream_seek_data_cb[type])
15187 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
15188 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15194 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
15196 mm_player_t *player = (mm_player_t*)user_data;
15197 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15199 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15201 LOGD("app-src: seek subtitle data\n");
15202 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15204 if (player->media_stream_seek_data_cb[type])
15205 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
15206 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15212 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
15214 mm_player_t* player = (mm_player_t*) hplayer;
15218 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15220 player->pcm_samplerate = samplerate;
15221 player->pcm_channel = channel;
15224 return MM_ERROR_NONE;
15227 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
15229 mm_player_t* player = (mm_player_t*) hplayer;
15233 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15234 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
15236 if (MMPLAYER_IS_STREAMING(player))
15237 *timeout = player->ini.live_state_change_timeout;
15239 *timeout = player->ini.localplayback_state_change_timeout;
15241 LOGD("timeout = %d\n", *timeout);
15244 return MM_ERROR_NONE;
15247 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
15249 mm_player_t* player = (mm_player_t*) hplayer;
15253 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15254 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
15256 *num = player->video_num_buffers;
15257 *extra_num = player->video_extra_num_buffers;
15259 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
15262 return MM_ERROR_NONE;
15266 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
15270 MMPLAYER_RETURN_IF_FAIL(player);
15272 for (i=0; i<MMPLAYER_PATH_MAX; i++) {
15274 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
15275 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
15276 player->storage_info[i].state = STORAGE_STATE_MOUNTED;
15277 player->storage_info[i].id = -1;
15279 if (path_type != MMPLAYER_PATH_MAX)
15287 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int state)
15289 int ret = MM_ERROR_NONE;
15290 mm_player_t* player = (mm_player_t*) hplayer;
15291 MMMessageParamType msg_param = {0, };
15294 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15296 LOGD("storage state : %d", state);
15298 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
15299 return MM_ERROR_NONE;
15301 if ((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) ||
15302 (player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)) {
15303 LOGW("external storage is removed.");
15305 if (player->msg_posted == FALSE) {
15306 memset(&msg_param, 0, sizeof(MMMessageParamType));
15307 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
15308 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
15309 player->msg_posted = TRUE;
15312 /* unrealize the player */
15313 ret = _mmplayer_unrealize(hplayer);
15314 if (ret != MM_ERROR_NONE)
15315 LOGE("failed to unrealize");
15322 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
15324 int ret = MM_ERROR_NONE;
15325 mm_player_t* player = (mm_player_t*) hplayer;
15326 int idx = 0, total = 0;
15327 gchar *result = NULL, *tmp = NULL;
15330 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15331 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
15333 total = *num = g_list_length(player->adaptive_info.var_list);
15335 LOGW("There is no stream variant info.");
15339 result = g_strdup ("");
15340 for (idx = 0 ; idx < total ; idx++) {
15341 VariantData *v_data = NULL;
15342 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
15345 gchar data[64]={0};
15346 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
15348 tmp = g_strconcat (result, data, NULL);
15352 LOGW("There is no variant data in %d", idx);
15357 *var_info = (char *)result;
15359 LOGD("variant info %d:%s", *num, *var_info);
15364 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
15366 int ret = MM_ERROR_NONE;
15367 mm_player_t* player = (mm_player_t*) hplayer;
15370 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15372 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
15374 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE)?(bandwidth):(ADAPTIVE_VARIANT_DEFAULT_VALUE);
15375 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE)?(width):(ADAPTIVE_VARIANT_DEFAULT_VALUE);
15376 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE)?(height):(ADAPTIVE_VARIANT_DEFAULT_VALUE);
15378 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
15379 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
15380 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
15381 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
15383 /* FIXME: seek to current position for applying new variant limitation */
15391 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
15393 int ret = MM_ERROR_NONE;
15394 mm_player_t* player = (mm_player_t*) hplayer;
15397 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15398 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
15400 *bandwidth = player->adaptive_info.limit.bandwidth;
15401 *width = player->adaptive_info.limit.width;
15402 *height = player->adaptive_info.limit.height;
15404 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);